Beispiel #1
0
        /// <summary>
        /// Call to disconnect from the server.
        /// </summary>
        /// <remarks>Always call disconnect before exiting the program. Failure to do so could cause a zombie thread.
        /// Also note that this sets the <see cref="Client.ClientNetwork.Username">Username</see> to blank and makes <see cref="Client.ClientNetwork.Connected">Connected</see> false.</remarks>
        /// <example>Always call this function on exit.
        /// <code>protected override void Dispose( bool disposing )
        ///	{
        ///		// Always call this before exiting the program
        ///		ClientNetwork.Disconnect();
        ///	}</code></example>
        public static void Disconnect(bool forced)
        {
            try
            {
                // Try to close the stream
                connectionStream.Close();
            }
            catch
            {}
            username = "";
            connected = false;

            if (forced)
            {
                Network.Header logoffHeader = new SDCSCommon.Network.Header();
                logoffHeader.DataType = Network.DataTypes.Logout;
                logoffHeader.Encrypted = false;
                logoffHeader.Length = 0;

                DataReceivedEventArgs e = new DataReceivedEventArgs();
                e.Header = logoffHeader;
                e.Data = System.Text.UnicodeEncoding.Unicode.GetBytes("Lost connection to server");

                DataReceived(null, e);
            }

            try
            {
                // Try to kill the thread
                listeningThread.Abort();
            }
            catch
            {}
        }
Beispiel #2
0
        /// <summary>
        /// Sends the keepAlive signal to check if the network connection is still active
        /// </summary>
        private static void sendKeepAlive()
        {
            Network.Header pingHead = new SDCSCommon.Network.Header();
            pingHead.DataType = Network.DataTypes.Ping;
            pingHead.Encrypted = false;
            pingHead.FromID = 0;
            pingHead.Length = 0;
            pingHead.ToID = -1;

            SendData(Network.headerToBytes(pingHead));
        }
        /// <summary>
        /// Function for the connection watching thread to live in. Basically is a message pump for the network
        /// </summary>
        private void connectionWatcherFunc()
        {
            // Records the last time a byte was received so we can check for a read timeout
            System.DateTime lastRead;

            // First send the random code for the client
            Network.Header sendHead = new SDCSCommon.Network.Header();
            sendHead.DataType = Network.DataTypes.RandomPassCode;
            sendHead.FromID = -1;
            sendHead.ToID = 0;
            sendHead.Length = 32;

            // Create a random 32 byte unicode string
            randomCode = new byte[32];
            Random rand = new Random();
            rand.NextBytes(randomCode);

            // And send it to the client
            sendData(Network.headerToBytes(sendHead), randomCode);

            // Now loop forever
            while (true)
            {
                // Each while loop continually checks if the server is shutting down.
                // This is to make sure that we don't end up with zombie threads.
                while (conn.stream.DataAvailable == false)
                {
                    if (ServerNetwork.ShuttingDown)
                        return;
                    if (BuddyListData.Count != 0)
                        sendBuddyListData();
                    if (System.DateTime.Now - lastActivity > TimeSpan.FromMilliseconds(KEEP_ALIVE_TIME))
                        sendKeepAlive();
                    Thread.Sleep(100);
                }

                byte[] headerBuffer = new byte[Network.HEADER_SIZE];
                lastRead = System.DateTime.Now;
                for (int i = 0; i < headerBuffer.Length; i++)
                {
                    while (conn.stream.DataAvailable == false)
                    {
                        if (frmServer.ShuttingDown || (System.DateTime.Now - lastRead) > System.TimeSpan.FromMilliseconds(MAX_READ_WAIT_TIME))
                            return;
                        Thread.Sleep(100);
                    }
                    headerBuffer[i] = (byte)conn.stream.ReadByte();
                    lastRead = System.DateTime.Now;
                }

                Network.Header head = Network.bytesToHeader(headerBuffer);

                // This is to prevent a user from spoofing themselves as another user
                head.FromID = conn.userID;

                // Read in exactly the amount of data sent
                byte[] data = new byte[head.Length];
                lastRead = System.DateTime.Now;
                for (int i = 0; i < head.Length; i++)
                {
                    while (conn.stream.DataAvailable == false)
                    {if (frmServer.ShuttingDown || (System.DateTime.Now - lastRead) > System.TimeSpan.FromMilliseconds(MAX_READ_WAIT_TIME))
                         return;
                        Thread.Sleep(100);}
                    data[i] = (byte)conn.stream.ReadByte();
                    lastRead = System.DateTime.Now;
                }

                // We don't want to allow someone to do anything but log in until they are logged in
                if ((loggedIn && head.DataType != Network.DataTypes.LoginInformation) || head.DataType == Network.DataTypes.LoginInformation || head.DataType == Network.DataTypes.Ping)
                {
                    switch (head.DataType)
                    {
                        case Network.DataTypes.InstantMessage: // Instant message data
                            for (int i = 0; i < ServerNetwork.netStreams.Count; i++)
                            {
                                if (((ServerNetwork.connection)ServerNetwork.netStreams[i]).userID == head.ToID)
                                {
                                    ((ServerNetwork.connection)ServerNetwork.netStreams[i]).watchingClass.sendData(Network.headerToBytes(head), data);
                                }
                            }
                            break;
                        case Network.DataTypes.WhiteBoard: // Whiteboard drawing information
                            break;
                        case Network.DataTypes.LoginInformation: // Initial login
                            // We receive a double hased password from the client. We store the single hash in the user database.
                            // First we convert the received username and double hash in to unicode strings.
                            int usernameLength = BitConverter.ToInt32(data,0);
                            string username = System.Text.UnicodeEncoding.Unicode.GetString(data, 4, usernameLength);
                            string password = System.Text.UnicodeEncoding.Unicode.GetString(data, 4 + usernameLength, data.Length - (4 + usernameLength));

                            Network.Header confirmHead = new SDCSCommon.Network.Header();
                            confirmHead.DataType = Network.DataTypes.LoginStatus;
                            confirmHead.FromID = -1;
                            confirmHead.Length = 4;

                            // This statement performs the second hash on the stored password and compares it with the password received from
                            // the client.
                            if (CryptoFunctions.getMD5Hash(String.Concat(ServerDatabase.getUserPass(username), System.Text.UnicodeEncoding.Unicode.GetString(randomCode))) == password)
                            { // Login successful

                                conn.userID = ServerDatabase.getUserID(username);
                                conn.username = username;

                                // Make sure we are only logged in from one place at a time
                                lock (ServerNetwork.netStreams.SyncRoot)
                                {
                                    for (int i = ServerNetwork.netStreams.Count - 1; i >= 0; i--)
                                        if (((ServerNetwork.connection)ServerNetwork.netStreams[i]).userID == conn.userID && ((ServerNetwork.connection)ServerNetwork.netStreams[i]).watchingClass.loggedIn)
                                            ((ServerNetwork.connection)ServerNetwork.netStreams[i]).watchingClass.Shutdown();
                                }

                                confirmHead.ToID = conn.userID;

                                // Send the Login OK message to let the client know they're authenticated
                                sendData(Network.headerToBytes(confirmHead), BitConverter.GetBytes(Network.LoginOK));
                                loggedIn = true;

                                // Let everyone know that the user is now online
                                conn.userState = SDCSCommon.Network.UserState.Online;
                                ServerNetwork.notifyBuddyStatus(conn.userID, conn.username, Network.UserState.Online);
                                ServerNetwork.refreshBuddyList(conn);
                            }
                            else
                            { // Login failed
                                confirmHead.ToID = 0;
                                sendData(Network.headerToBytes(confirmHead), BitConverter.GetBytes(Network.LoginBad));
                                Shutdown();
                            }
                            break;
                        case Network.DataTypes.Logout:
                            Shutdown();
                            break;
                        default:
                            break;
                    }
                }
                else
                    Shutdown();

                lastActivity = System.DateTime.Now;
            }
        }