// TODO: It would be AWESOME if we could just store this class directly, but
        // unfortunately, Bond's type aliases allow only primitive types to be aliased.
        // We should check to see if we can add support for custom types in Bond's source,
        // but for now, we're forced to do a double serialization here.
        public static ArraySegment <byte> ToByteArray(IGenericSerializable Serializable)
        {
            if (Serializable == null)
            {
                return(default(ArraySegment <byte>));
            }

            var Type   = Serializable.GetType();
            var Result = new SerializationGenericReference(0)
            {
                Type = BondSerializationUtil.GetTypeIdentifierString(Type),
                Data = BondSerializer.Serialize(Serializable)
            };

            return(BondSerializer.Serialize(Result));
        }
Beispiel #2
0
        /// <summary>
        /// Receive and enqueue messages from the server endpoint.
        /// </summary>
        private void ReceiveThread()
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();

#if GENERIC_SERIALIZATION
            IGenericSerializable msg = null;
#else
            object msg = null;
#endif

            while (!m_Disposed)
            {
                if ((m_Socket != null) && (m_Socket.Connected) && (m_Connected))
                {
                    try {
#if GENERIC_SERIALIZATION
                        msg = PacketTypes.DecodeMessage(null, new SerializedPacket(m_NetworkStream));
#else
                        msg = binaryFormatter.Deserialize(m_NetworkStream);  //blocks
#endif
                    }
                    catch (Exception e) {
                        if (e.InnerException is SocketException)
                        {
                            if (((SocketException)e.InnerException).ErrorCode == 10053)
                            {
                                Trace.WriteLine("SocketException 10053: Read aborted by local host.");
                            }
                            else if (((SocketException)e.InnerException).ErrorCode == 10054)
                            {
                                Trace.WriteLine("SocketException 10054: Read aborted.  Remote connection lost.");
                            }
                            else
                            {
                                Trace.WriteLine("ReceiveThread SocketException while reading.  ErrorCode=" + ((SocketException)e.InnerException).ErrorCode.ToString());
                            }
                        }
                        else
                        {
                            Trace.WriteLine("ReceiveThread failed to read: " + e.ToString());
                        }

                        continue;
                    }

                    lock (m_ReceiveQueue) {
                        this.m_LastMsgReceived = DateTime.Now;
                        if (!(msg is TCPHeartbeatMessage))
                        {
                            m_ReceiveQueue.Enqueue(new ReceiveMessageAndParticipant(msg, m_ServerParticipant));
                            Chunk c = (msg as Chunk);
                            if (c != null)
                            {
                                m_LastMsgSequence   = c.MessageSequence;
                                m_LastChunkSequence = c.ChunkSequenceInMessage;
                            }
                        }
                        else
                        {
                            Trace.WriteLine("TCPClient received heartbeat message at " + DateTime.Now.ToString(), this.GetType().ToString());
                        }
                    }
                }
                else
                {
                    Thread.Sleep(100);
                }
            }
            Trace.WriteLine("Receive Thread is ending.", this.GetType().ToString());
        }
Beispiel #3
0
        /// <summary>
        /// Maintain the connection to the server endpoint.
        /// </summary>
        private void ConnectThread()
        {
            while (!m_Disposed)
            {
                if ((m_Socket == null) || (!m_Socket.Connected) || (!m_Connected))
                {
                    Socket s = (Socket)Interlocked.Exchange(ref m_Socket, null);
                    if (s != null)
                    {
                        s.Close();
                    }

                    try {
                        if (m_Disposed)
                        {
                            break;
                        }
                        using (Synchronizer.Lock(this.SyncRoot)) {
                            this.SetPublishedProperty("Connected", ref this.m_Connected, false);
                            NetworkStatus newStatus = m_NetworkStatus.Clone();
                            newStatus.ConnectionStatus = ConnectionStatus.TryingToConnect;
                            this.SetPublishedProperty("NetworkStatus", ref m_NetworkStatus, newStatus);
                        }
                        Trace.WriteLine("Attempting connection to server: " + this.m_RemoteEP.ToString(), this.GetType().ToString());
                        m_Socket = new Socket(this.m_RemoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                        m_Socket.ReceiveTimeout = 20000; //Temporarily set to 20 seconds for the handshaking phase.
                        //In case the server endpoint changed:
                        UpdateRemoteEndpoint();
                        m_Socket.Connect(this.m_RemoteEP);
                        m_NetworkStream = new NetworkStream(m_Socket); //NetworkStream does not own the socket.

                        //Receive handshake
                        BinaryFormatter bf = new BinaryFormatter();
#if GENERIC_SERIALIZATION
                        IGenericSerializable o = PacketTypes.DecodeMessage(null, new SerializedPacket(m_NetworkStream));
#else
                        object o = bf.Deserialize(m_NetworkStream);
#endif
                        if (o is TCPHandshakeMessage)
                        {
                            Trace.WriteLine("Handshake received from " + ((TCPHandshakeMessage)o).ParticipantId.ToString() + " ep=" + ((TCPHandshakeMessage)o).EndPoint.ToString());
                            //send a handshake
                            TCPHandshakeMessage handshake = new TCPHandshakeMessage(m_Participant, (IPEndPoint)m_Socket.LocalEndPoint);
                            lock (this.m_ReceiveQueue) {
                                //If this is a reconnect, these values tell the server where we left off
                                handshake.LastMessageSequence = m_LastMsgSequence;
                                handshake.LastChunkSequence   = m_LastChunkSequence;
                            }
                            MemoryStream ms = new MemoryStream();
#if GENERIC_SERIALIZATION
                            handshake.Serialize().WriteToStream(ms);
#else
                            bf.Serialize(ms, handshake);
#endif
                            m_NetworkStream.Write(ms.GetBuffer(), 0, (int)ms.Length);
                            Trace.WriteLine("Handshake sent.", this.GetType().ToString());
                            //The first time we connect to a server we create a new ParticipantModel to represent the server.
                            if (m_ServerParticipant == null)
                            {
                                TCPHandshakeMessage h = (TCPHandshakeMessage)o;
                                m_ServerId          = h.ParticipantId;
                                m_ServerParticipant = new ParticipantModel(m_ServerId, h.HumanName);
                            }
                            else
                            {
                                //In reconnect scenarios we keep the same server ParticipantModel, but the Guid could
                                //change if the server was restarted.  In this case we just want to update the Guid.
                                //Notice that we can't create a new ParticipantModel here without breaking some things.
                                if (!m_ServerId.Equals(((TCPHandshakeMessage)o).ParticipantId))
                                {
                                    m_ServerId = ((TCPHandshakeMessage)o).ParticipantId;
                                    m_ServerParticipant.Guid = m_ServerId;
                                }
                            }
                        }
                        else
                        {
                            throw new ApplicationException("Invalid handshake received: " + o.GetType().ToString());
                        }

                        m_Socket.ReceiveTimeout = 0; //Reset socket to infinite timeout.
                        m_ClientTimeout         = SetClientTimeout();

                        using (Synchronizer.Lock(this.SyncRoot)) {
                            //Setting this property allows the ReceiveThread to begin:
                            this.SetPublishedProperty("Connected", ref this.m_Connected, true);
                            NetworkStatus newStatus = m_NetworkStatus.Clone();
                            newStatus.ConnectionStatus = ConnectionStatus.Connected;
                            this.SetPublishedProperty("NetworkStatus", ref m_NetworkStatus, newStatus);
                        }

                        lock (this.m_ReceiveQueue) {
                            //This enables the client timeout:
                            this.m_LastMsgReceived = DateTime.Now;
                        }

                        Trace.WriteLine("Connected.", this.GetType().ToString());
                    }
                    catch (SocketException se) {
                        if (se.ErrorCode == 10060)
                        {
                            Trace.WriteLine("ConnectThread SocketException 10060: remote host failed to respond.");
                        }
                        else if (se.ErrorCode == 10038)
                        {
                            Trace.WriteLine("ConnectThread SocketException 10038: operation attempted on non-socket.");
                        }
                        else
                        {
                            Trace.WriteLine("ConnectThread SocketException " + se.ErrorCode.ToString() + ": " + se.ToString());
                        }
                    }
                    catch (IOException ioe) {
                        Trace.WriteLine("ConnectThread IOException: " + ioe.Message);
                        if ((ioe.InnerException != null) && (ioe.InnerException is SocketException))
                        {
                            Trace.WriteLine("  InnerException: SocketException " + ((SocketException)ioe.InnerException).ErrorCode.ToString());
                        }
                    }
                    catch (Exception e) {
                        Trace.WriteLine("ConnectThread exception: " + e.ToString());
                    }
                }

                for (int i = 0; ((i < 10) && (!m_Disposed)); i++)
                {
                    Thread.Sleep(100);
                }
            }
            Trace.WriteLine("ConnectThread is ending.", this.GetType().ToString());
        }
Beispiel #4
0
 public static ArraySegment <byte> Convert(IGenericSerializable value, ArraySegment <byte> unused, Type ExpectedType)
 {
     return(SerializationGenericReference.ToByteArray(value));
 }
Beispiel #5
0
 public static IGenericSerializable Convert(ArraySegment <byte> value, IGenericSerializable unused, Type ExpectedType)
 {
     return(SerializationGenericReference.FromByteArray(value));
 }
Beispiel #6
0
        /// <summary>
        /// When the ListenThread has a prospective new client on the line, here we attempt to establish the connection.
        /// </summary>
        /// <param name="ar"></param>
        private void AcceptSocketCallback(IAsyncResult ar)
        {
            Socket      s           = null;
            TcpListener tcpListener = (TcpListener)ar.AsyncState;

            try {
                s = tcpListener.EndAcceptSocket(ar);
            }
            catch (ObjectDisposedException ode) {
                Trace.WriteLine("AcceptSocketCallback ObjectDisposedException" + ode.Message, this.GetType().ToString());
                return;
            }
            catch (SocketException se) {
                Trace.WriteLine("AcceptSocketCallback: " + se.ToString(), this.GetType().ToString());
                return;
            }
            catch (Exception e) {
                Trace.WriteLine(e.ToString(), this.GetType().ToString());
                return;
            }
            finally {
                m_ClientConnected.Set();  //Let the ListenThread continue
            }

            if (s != null)
            {
                try {
                    //Send a handshake
                    NetworkStream       ns        = new NetworkStream(s); //Here the network stream does not "own" the socket, so we have to close it explicitly.
                    BinaryFormatter     bf        = new BinaryFormatter();
                    MemoryStream        ms        = new MemoryStream();
                    TCPHandshakeMessage handshake = new TCPHandshakeMessage(this.m_Participant, new IPEndPoint(0, 0));
#if GENERIC_SERIALIZATION
                    handshake.Serialize().WriteToStream(ms);
#else
                    bf.Serialize(ms, handshake);
#endif
                    ns.Write(ms.GetBuffer(), 0, (int)ms.Length);
                    Trace.WriteLine("Handshake sent.", this.GetType().ToString());

                    //Receive a handshake
#if GENERIC_SERIALIZATION
                    IGenericSerializable o = PacketTypes.DecodeMessage(null, new SerializedPacket(ns));
#else
                    object o = bf.Deserialize(ns);
#endif

                    if (o is TCPHandshakeMessage)
                    {
                        TCPHandshakeMessage h = (TCPHandshakeMessage)o;
                        Trace.WriteLine("Handshake received from " + h.ParticipantId.ToString() + " ep=" + h.EndPoint.ToString(), this.GetType().ToString());
                        ParticipantModel p;

                        //In case this client still has a socket open, force it to close
                        ClosePreviousSocket(h.ParticipantId);

                        //Notice that as soon as we add the entry to m_AllClients, it is eligible for sending of outbound messages:
                        bool newClient = false;
                        lock (m_AllClients) {
                            if (m_AllClients.ContainsKey(h.ParticipantId))
                            {
                                ((ClientData)m_AllClients[h.ParticipantId]).ConnectionState = ConnectionState.Connected;
                                ((ClientData)m_AllClients[h.ParticipantId]).Socket          = s;
                                p = ((ClientData)m_AllClients[h.ParticipantId]).Participant;
                                //Add the participant to the classroom model
                                using (Synchronizer.Lock(m_Classroom.SyncRoot)) {
                                    m_Classroom.Participants.Add(p);
                                }
                                ((ClientData)m_AllClients[h.ParticipantId]).Timeout = DateTime.MaxValue;
                                this.m_ServerSender.Reconnect(((ClientData)m_AllClients[h.ParticipantId]), h.LastMessageSequence, h.LastChunkSequence);
                            }
                            else
                            {
                                p = new ParticipantModel(h.ParticipantId, h.HumanName);
                                //Add the participant to the classroom model
                                using (Synchronizer.Lock(m_Classroom.SyncRoot)) {
                                    m_Classroom.Participants.Add(p);
                                }
                                ClientData client = new ClientData(s, h.ParticipantId, p);
                                this.m_ServerSender.AddClient(client);
                                m_AllClients.Add(h.ParticipantId, client);
                                newClient = true;
                            }
                        }

                        //Update connected client count for network status
                        using (Synchronizer.Lock(this.SyncRoot)) {
                            this.SetPublishedProperty("ClientCount", ref this.m_ClientCount, this.m_ClientCount + 1);
                            NetworkStatus newStatus = m_NetworkStatus.Clone();
                            newStatus.ClientCount = this.m_ClientCount;
                            this.SetPublishedProperty("NetworkStatus", ref m_NetworkStatus, newStatus);
                        }

                        //Start a receive thread for this socket.
                        Thread receiveThread = new Thread(ReceiveThread);
                        receiveThread.Start(new ReceiveThreadArgs(p, ns, s.RemoteEndPoint));

                        //Send the current presentation state if this is a new client
                        if (newClient)
                        {
                            m_Sender.ForceUpdate(new SingletonGroup(p));
                        }
                    }
                    else
                    {
                        Trace.WriteLine("AcceptSocketCallback invalid handshake from " + s.RemoteEndPoint.ToString(), this.GetType().ToString());
                    }
                }
                catch (Exception e) {
                    Trace.WriteLine("AcceptSocketCallback exception while handshaking with " + s.RemoteEndPoint.ToString() + ": " + e.ToString(), this.GetType().ToString());
                }
            }
        }
Beispiel #7
0
        /// <summary>
        /// We use one receive thread per socket
        /// </summary>
        /// <param name="o"></param>
        private void ReceiveThread(Object o)
        {
            ReceiveThreadArgs args        = (ReceiveThreadArgs)o;
            NetworkStream     ns          = args.NetStream;
            ParticipantModel  participant = args.Participant;
            Guid     participantId        = participant.Guid;
            EndPoint remoteEP             = args.RemoteEndPoint;

            IFormatter binaryFormatter = new BinaryFormatter();

#if GENERIC_SERIALIZATION
            IGenericSerializable msg = null;
#else
            object msg = null;
#endif

            while (!this.m_Disposed)
            {
                try {
#if GENERIC_SERIALIZATION
                    msg = PacketTypes.DecodeMessage(null, new SerializedPacket(ns));
#else
                    msg = binaryFormatter.Deserialize(ns);  //blocks
#endif
                }
                catch (SerializationException se) {
                    Trace.WriteLine(se.ToString(), this.GetType().ToString());
                    break;
                }
                catch (Exception e) {
                    if (e.InnerException is SocketException)
                    {
                        SocketException se = (SocketException)e.InnerException;
                        if (se.ErrorCode == 10054)
                        {
                            Trace.WriteLine("ReceiveThread detected a disconnected client during NetworkStream.Read: " + remoteEP.ToString(), this.GetType().ToString());
                            break;
                        }
                        else if (se.ErrorCode == 10053)
                        {
                            Trace.WriteLine("ReceiveThread: socket was closed by local host.", this.GetType().ToString());
                            break;
                        }
                        else if (se.ErrorCode == 10004)
                        {
                            Trace.WriteLine("ReceiveThread: a blocking operation was interrupted.", this.GetType().ToString());
                            break;
                        }
                        else
                        {
                            Trace.WriteLine("SocketException in ReceiveThread. remote Endpoint= " + remoteEP.ToString() + " " + se.ToString() + " error code: " + se.ErrorCode.ToString(), this.GetType().ToString());
                            break;
                        }
                    }
                    else
                    {
                        Trace.WriteLine("Exception while reading: " + e.ToString(), this.GetType().ToString());
                        break;
                    }
                }

                lock (m_ReceiveQueue) {
                    m_ReceiveQueue.Enqueue(new ReceiveMessageAndParticipant(msg, participant));
                }
            }

            //Remove the participant from the classroom here.  Notice that the socket for this participant may still be open.
            using (Synchronizer.Lock(m_Classroom.SyncRoot)) {
                m_Classroom.Participants.Remove(participant);
            }

            Trace.WriteLine("ReceiveThread is ending for remote endpoint=" + remoteEP.ToString(), this.GetType().ToString());
        }