Exemple #1
0
        public void Send(Stream stream, Message message)
        {
            if (!stream.CanWrite)
            {
                return;
            }

            if (message.ID == null)
            {
                throw new InvalidOperationException("Can not serialize a message without an ID!");
            }

            message.SentFromReceivingThread = NetworkThreadContext.IsSentFromReceivingThread();

            var writer = new BinaryWriter(stream);

            using (var memory = new MemoryStream())
            {
                Serializer.Serialize(memory, message);
                var length = (int)memory.Position;
                memory.Seek(0, SeekOrigin.Begin);
                var reader   = new BinaryReader(memory);
                var bytes    = reader.ReadBytes(length);
                var checksum = this.CalculateChecksum(length, bytes);


                writer.Write(length);
                writer.Write(checksum);
                writer.Write(bytes);
            }
        }
Exemple #2
0
        /// <summary>
        /// Send a message to the remote host that this client handler is connected to.
        /// </summary>
        /// <param name="message">
        /// The message.
        /// </param>
        public void Send(Message message)
        {
            try
            {
                NetworkThreadContext.AssertSendIsValid((IPEndPoint)this.m_Client.Client.RemoteEndPoint);

                lock (this.m_Client)
                {
                    this.m_MessageIo.Send(this.m_Client.GetStream(), message);
                }
            }
            catch (ObjectDisposedException)
            {
                // The client is no longer available.
                // TODO: Remove the client from the lookup list.
            }
        }
Exemple #3
0
        /// <summary>
        /// Continuously receive messages from a TCP client, calling "callback" until
        /// the client is no longer connected.
        /// </summary>
        /// <param name="client">
        /// The TCP client.
        /// </param>
        /// <param name="callback">
        /// The callback.
        /// </param>
        public void Run(TcpClient client, Action <Message> callback)
        {
            var remoteEndpoint = (IPEndPoint)client.Client.RemoteEndPoint;

            try
            {
                while (client.Connected)
                {
                    Message message = null;
                    try
                    {
                        message = this.m_MessageIo.Receive(client.GetStream());
                    }
                    catch (EndOfStreamException)
                    {
                        // This occurs when we are attempting to retrieve the next message
                        // but the stream is terminated (and so we reach the end of the network
                        // stream).  We can't read any more messages from the stream regardless
                        // of whether we are connected, so we need to return.
                        try
                        {
                            client.Close();
                        }
                        catch (SocketException)
                        {
                        }
                        catch (ObjectDisposedException)
                        {
                        }

                        return;
                    }
                    catch (InvalidOperationException)
                    {
                        if (!client.Connected)
                        {
                            // The client disconnected between checking in the while loop
                            // and actually attempt to retrieve the stream (or read from it).
                            // Break out of the while loop since we are no longer connected
                            // anyway.
                            return;
                        }
                    }
                    catch (IOException ex)
                    {
                        // If we don't have an inner exception, then we rethrow (we are only
                        // interested in networking related exceptions here, and they may be
                        // wrapped in IO exception due to reading from a stream).
                        var innerException = ex.InnerException;
                        if (innerException == null)
                        {
                            throw;
                        }

                        // Try and convert the inner exception to a socket exception; if it
                        // is, check if it's an exception that we might be expecting (for
                        // example if the connection was closed from another thread, as is
                        // the case when Stop() is called).
                        var socketException = innerException as SocketException;
                        if (socketException != null)
                        {
                            switch (socketException.ErrorCode)
                            {
                            case 10004:
                                // A blocking operation was interrupted by a call to WSACancelBlockingCall.
                                // This occurs when Stop() is called and the connection is forcibly closed.
                                return;

                            default:
                                // We don't know what kind of socket exception this was, so we rethrow it.
                                throw;
                            }
                        }

                        // Try and convert the inner exception to an object disposed exception;
                        // if it is, then the client has been disposed and we should return.
                        var objectDisposedException = innerException as ObjectDisposedException;
                        if (objectDisposedException != null)
                        {
                            return;
                        }

                        // Try and convert the inner exception to a thread abort exception;
                        // if it is, then the client is being terminated and we should return.
                        var threadAbortException = innerException as ThreadAbortException;
                        if (threadAbortException != null)
                        {
                            return;
                        }

                        throw;
                    }

                    if (message == null)
                    {
                        continue;
                    }

                    var endpoint = (IPEndPoint)client.Client.RemoteEndPoint;
                    message.Sender = new Contact {
                        IPAddress = endpoint.Address, Port = endpoint.Port
                    };

                    // Attempt to call the callback, which may execute user code based on the message.
                    // Since this is executing user code, there's the potential that an exception might
                    // occur, and that exception finds it's way back up to this code.  We need to ensure
                    // that any exceptions occurring in user code do not impact our ability to accept
                    // future messages, so we pass the exception off to the IUnhandledExceptionLog
                    // interface.
                    try
                    {
                        NetworkThreadContext.EnterNetworkContext(
                            message.SentFromReceivingThread,
                            (IPEndPoint)client.Client.RemoteEndPoint);
                        callback(message);
                    }
                    catch (Exception ex)
                    {
                        this.m_UnhandledExceptionLog.Log("user code", ex);
                        throw;
                    }
                    finally
                    {
                        NetworkThreadContext.ExitNetworkContext();
                    }
                }
            }
            catch (ThreadAbortException)
            {
                // This occurs when the thread is being forcibly aborted.  This seems to be much more
                // common under the Mono runtime than .NET.  We can't do anything here but return.
            }
            catch (Exception ex)
            {
                // Under Mono, we can not allow any exceptions to escape from a thread.  Mono does not
                // generally handle exceptions escaping from threads correctly, and it usually causes
                // a native crash from which there is no recovery (because at that point, C# is not
                // executing any more).
                //
                // Under all platforms, the best option is to log it via the unhandled exception log,
                // close the client (if possible), and return.
                this.m_UnhandledExceptionLog.Log(
                    "receive handler",
                    ex);

                try
                {
                    client.Close();
                }
                catch (SocketException)
                {
                }
                catch (ObjectDisposedException)
                {
                }
                catch (ThreadAbortException)
                {
                }
                catch (Exception exx)
                {
                    this.m_UnhandledExceptionLog.Log(
                        "while closing client",
                        exx);
                }
            }

            // Try and remove ourselves from the client handler list.  This is not
            // always possible to do.
            try
            {
                this.m_ClientLookup.Remove(remoteEndpoint);
            }
            catch (Exception ex)
            {
                this.m_UnhandledExceptionLog.Log(
                    "while removing client from lookup",
                    ex);
            }

            Console.WriteLine(Thread.CurrentThread.Name + " has ended");
        }