Ejemplo n.º 1
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.GetType().ToString());
                        m_Socket = new Socket(AddressFamily.InterNetwork, 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();
                        object o = bf.Deserialize(m_NetworkStream);
                        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();
                            bf.Serialize(ms, handshake);
                            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.Message);
                        }
                    }
                    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());
        }
Ejemplo n.º 2
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));
                    bf.Serialize(ms, handshake);
                    ns.Write(ms.GetBuffer(), 0, (int)ms.Length);
                    Trace.WriteLine("Handshake sent.", this.GetType().ToString());

                    //Receive a handshake
                    object o = bf.Deserialize(ns);

                    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());
                }
            }
        }
Ejemplo n.º 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());
        }
Ejemplo n.º 4
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());
                }
            }
        }