Beispiel #1
0
        /// <summary>
        /// Removes the client from  the client list and all of the server rooms
        /// </summary>
        /// <param name="client">Our client</param>
        public static void RemoveClientFromAll(ClientInfo client)
        {
            Console.WriteLine($"Client {client.GetUsername()} disconnected");

            // Remove client from global list
            Console.WriteLine(Globals.ClientList.Remove(client)
                ? $"Removed client {client.GetUsername()} from client list"
                : $"Error removing client {client.GetUsername()} from client list");

            // remove from rooms too
            int removedFrom = 0;

            foreach (var room in Globals.ServerRooms)
            {
                if (room.RemoveClient(client))
                {
                    removedFrom++;
                    // Notify all clients of new member list
                    List <string> toSendList = new List <string> {
                        room.RoomName()
                    };
                    toSendList.AddRange(room.GetAllClientsNames());
                    MessageAllClients(FormatMessage(Headers.RoomMembersResult, toSendList.ToArray()));
                }
            }

            MessageAllClients(FormatMessage(Headers.ClientDisconnected, client.GetUsername()));// Notify all clients that this client left
            Console.WriteLine($"Removed client {client.GetUsername()} from {removedFrom} rooms");
            client.StopClient();
        }
Beispiel #2
0
 /// <summary>
 /// Sends a private message to another member
 /// </summary>
 /// <param name="memberName">Member to message</param>
 /// <param name="message">Unformatted message to send</param>
 /// <param name="client">Client sending the message</param>
 /// <returns>True if member was found and false otherwise</returns>
 public static bool MessageMember(string memberName, string message, ClientInfo client)
 {
     foreach (var curClient in Globals.ClientList)
     {
         if (curClient.GetUsername() == memberName)
         {
             curClient.MessageClient(FormatMessage(Headers.PrivMsgData, client.GetUsername(), curClient.GetUsername(), message));
             client.MessageClient(FormatMessage(Headers.PrivMsgData, client.GetUsername(), curClient.GetUsername(), message));
             return(true);
         }
     }
     return(false);
 }
Beispiel #3
0
        /// <summary>
        /// Changes the clients username
        /// </summary>
        /// <param name="wantedUsername">The new username</param>
        /// <param name="client">Our client</param>
        /// <returns>True if username was changed and false otherwise</returns>
        public static bool ChangeClientUsername(string wantedUsername, ClientInfo client)
        {
            if (wantedUsername == "")
            {
                return(false);
            }

            if (!UsernameTaken(wantedUsername) && client != null)
            {
                Console.Write($"Client changed usernames. Previous username: {client.GetUsername()}\tNew username: "******"ERROR: Client wasn't in client list");
            return(false);
        }
Beispiel #4
0
        /// <summary>
        /// Sends a message to all members in a room
        /// </summary>
        /// <param name="roomName">Name of room to message</param>
        /// <param name="message">Unformatted message to send</param>
        /// <param name="client">Client sending the message</param>
        /// <returns>True if room exists and false if it doesn't</returns>
        public static bool MessageRoomMembers(string roomName, string message, ClientInfo client)
        {
            foreach (var room in Globals.ServerRooms)
            {
                // if room name is invalid or client isn't a member we continue looping
                if (room.RoomName() != roomName || !room.Contains(client))
                {
                    continue;
                }

                room.MessageClients(FormatMessage(Headers.RoomMsgData, roomName, client.GetUsername(), message));
                return(true);
            }
            return(false);
        }
Beispiel #5
0
        /// <summary>
        /// Runs when data is sent to the client
        /// </summary>
        /// <param name="asyncResult">Result containing the client info</param>
        public void DataSentCallback(IAsyncResult asyncResult)
        {
            ClientInfo client = (ClientInfo)asyncResult.AsyncState;

            try
            {
                if (_usingSsl)
                {
                    client._clientSslStream.EndWrite(asyncResult);
                    Console.WriteLine($"DataSentCallbackSsl(): Successfully sent message to {client.GetUsername()}");
                    _semaphorePool.Release();
                }
                else
                {
                    int result = client.ClientSocket().EndSend(asyncResult, out var errorCode);
                    Console.WriteLine(errorCode == SocketError.Success ?
                                      $"Successfully sent message with size of {result} bytes to {client.GetUsername()}" :
                                      $"Error sending. code: {errorCode}");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Unhandled DataSentCallback() Exception! " + e);
            }
        }
Beispiel #6
0
        /// <summary>
        /// Handles the commands sent from the client to the server
        /// </summary>
        /// <param name="command">The command received from the client</param>
        /// <param name="client">Client that sent the command</param>
        public static void CommandHandler(string command, ClientInfo client)
        {
            // Our format is
            // COMMAND<EOL>COMMAND DATA<EOF>

            string[] commandStrings = command.Split(new[] { "<EOL>" }, StringSplitOptions.None);
            switch (commandStrings[0])
            {
            // Set username
            // USERNAME<EOL>username<EOF>
            // Will return
            // USERNAMERESULT<EOL>TRUE?FALSE?USERNAME<EOL>NOTE<EOF>
            // USERNAMECHANGE<EOL>OLDUSERNAME<EOL>NEWUSERNAME<EOF>
            case Headers.Username:
                string oldUsername = client.GetUsername();
                // trim to remove white space from begging and end
                if (ChangeClientUsername(commandStrings[1].Trim(), client))
                {
                    client.MessageClient(FormatMessage(Headers.UsernameResult, "TRUE", client.GetUsername(), "Change successful"));
                    MessageAllClients(FormatMessage(Headers.UsernameChange, oldUsername, client.GetUsername()));    // Message all clients of username change
                }
                else
                {
                    client.MessageClient(FormatMessage(Headers.UsernameResult, "FALSE", client.GetUsername(), "Change unsuccessful; username taken"));
                }
                break;


            // Make room
            // MAKEROOM<EOL>ROOMNANE<EOF>
            // Will return
            // MAKEROOMRESULT<EOL>TRUE?FALSE<EOL>NOTE<EOL>ROOMCREATEDNAME<EOF>
            case Headers.MakeRoom:
                if (CreateRoom(commandStrings[1].Trim(), client))
                {
                    client.MessageClient(FormatMessage(Headers.MakeRoomResult, "TRUE", "Created room successfully", commandStrings[1].Trim()));
                    MessageAllClients(FormatMessage(Headers.GetRoomsResult, GetRoomNameList().ToArray()));    // Send all clients all of the rooms
                }
                else
                {
                    client.MessageClient(FormatMessage(Headers.MakeRoomResult, "FALSE", "Error creating room. Room name could be taken"));
                }
                break;


            // Delete room(can only be done by server or client who made it)
            // REMOVEROOM<EOL>ROOMNAME<EOF>
            // Will return
            // REMOVEROOMRESULT<EOL>TRUE?FALSE<EOL>NOTE<EOF>
            // ROOMREMOVED<EOL>ROOMNAME<EOF>
            case Headers.RemoveRoom:
                if (RemoveRoom(commandStrings[1].Trim(), client))
                {
                    client.MessageClient(FormatMessage(Headers.RemoveRoomResult, "TRUE", "Removed room successfully"));
                    MessageAllClients(FormatMessage(Headers.RoomRemoved, commandStrings[1].Trim()));    // Notify clients that the room was removed
                }
                else
                {
                    client.MessageClient(FormatMessage(Headers.RemoveRoomResult, "FALSE", "Error removing room. Not owner or invalid room name"));
                }
                break;


            // Get all rooms
            // GETROOMS<EOF>
            // Will return rooms in format
            // GETROOMSRESULT<EOL>RM1<EOL>RM2<EOF>
            case Headers.GetRooms:
                client.MessageClient(FormatMessage(Headers.GetRoomsResult, GetRoomNameList().ToArray()));
                break;


            // Join room
            // JOINROOM<EOL>ROOMNAME<EOF>
            // Will return
            // JOINROOMRESULT<EOL>TRUE?FALSE<EOF>
            case Headers.JoinRoom:
                client.MessageClient(AddClientToRoom(commandStrings[1].Trim(), client)
                        ? FormatMessage(Headers.JoinRoomResult, "TRUE")
                        : FormatMessage(Headers.JoinRoomResult, "FALSE"));
                break;


            // Leave room
            // LEAVEROOM<EOL>ROOMNAME<EOF>
            // Will return
            // LEAVEROOMRESULT<EOL>TRUE?FALSE<EOF>
            case Headers.LeaveRoom:
                client.MessageClient(RemoveClientFromRoom(commandStrings[1].Trim(), client)
                        ? FormatMessage(Headers.LeaveRoomResult, "TRUE")
                        : FormatMessage(Headers.LeaveRoomResult, "FALSE"));
                break;


            // Get room members
            // ROOMMEMBERS<EOL>ROOMNAME<EOF>
            // Will return
            // ROOMMEMBERSRESULT<EOL>ROOMNAME<EOL>MEM1<EOL>MEM2<EOF>
            case Headers.RoomMembers:
                List <string> roomMembers = new List <string> {
                    commandStrings[1].Trim()
                };
                if (GetRoomMembers(commandStrings[1].Trim(), ref roomMembers))
                {
                    client.MessageClient(FormatMessage(Headers.RoomMembersResult, roomMembers.ToArray()));
                }
                break;


            // Message to room
            // ROOMMSG<EOL>ROOMNAME<EOL>MSG<EOF>
            // Will return to client
            // ROOMMSGRETURN<EOL>TRUE?FALSE<EOF>
            // Will send to all room members
            // ROOMMSGDATA<EOL>ROOMNAME<EOL>SENDERNAME<EOL>MSG<EOF>
            // msg will be formatted in <username> CLIENTMSG
            case Headers.RoomMsg:
                client.MessageClient(MessageRoomMembers(commandStrings[1].Trim(), commandStrings[2].Trim(), client)
                        ? FormatMessage(Headers.RoomMsgReturn, "TRUE")
                        : FormatMessage(Headers.RoomMsgReturn, "FALSE"));
                break;


            // Message from client to client
            // PRIVMSG<EOL>DESTUSERNAME<EOL>MSG<EOF>
            // Will return to client
            // PRIVMSGRETURN<EOL>TRUE?FALSE<EOF>
            // Will send to dest client
            // PRIVMSGDATA<EOL>FROMUSERNAME<EOL>TOUSERNAME<EOL>MSG<EOF>
            case Headers.PrivMsg:
                client.MessageClient(MessageMember(commandStrings[1].Trim(), commandStrings[2].Trim(), client)
                        ? FormatMessage(Headers.PrivMsgReturn, "TRUE")
                        : FormatMessage(Headers.PrivMsgReturn, "FALSE"));
                break;


            // CLIENTDISCONNECTING<EOF>
            // Will return to all
            // CLIENTDISCONNECTED<EOL>USERNAME<EOF>
            case Headers.ClientDisconnecting:
                RemoveClientFromAll(client);
                break;


            // Ping pong
            // PING<EOF>
            // Will return
            // PONG<EOF>
            case Headers.Ping:
                client.MessageClient(FormatMessage(Headers.Pong));
                break;


            default:
                // We don't know the command
                break;
            }
        }
Beispiel #7
0
        /// <summary>
        /// Removes an existing room
        /// </summary>
        /// <param name="roomName">Room name to remove</param>
        /// <param name="client">Client trying to remove the room</param>
        /// <returns>True if room was removed and false otherwise</returns>
        public static bool RemoveRoom(string roomName, ClientInfo client)
        {
            foreach (var room in Globals.ServerRooms)
            {
                if (room.RoomName() == roomName && room.IsOwner(client))
                {
                    // Send a message to the room that it's getting removed
                    room.MessageClients(FormatMessage(Headers.RoomMsgData, roomName, "SERVER", $"Room owner {client.GetUsername()} has deleted the room."));
                    room.RemoveAllClients();

                    // Remove the room from the room list
                    Console.WriteLine(Globals.ServerRooms.Remove(room)
                        ? $"Successfully deleted room {roomName}"
                        : $"Error removing room {roomName} from room list");

                    return(true);
                }
            }
            return(false);
        }
Beispiel #8
0
        /// <summary>
        /// Runs on a new client connection, and sets a client id and adds to list of clients.
        /// </summary>
        /// <param name="asyncResult">Result from connection containing socket to client</param>
        public static void ClientConnectCallback(IAsyncResult asyncResult)
        {
            try
            {
                Socket clientSocket = Globals.Listener.EndAccept(asyncResult);

                NetworkStream networkStream = new NetworkStream(clientSocket);
                SslStream     sslStream     = new SslStream(networkStream, false);


                // Authenticate the server but don't require the client to authenticate.
                try
                {
                    sslStream.AuthenticateAsServer(Globals.ServerCertificate, false,
                                                   true);

                    // Display the properties and settings for the authenticated stream.
                    HelperMethods.DisplaySecurityLevel(sslStream);
                    HelperMethods.DisplaySecurityServices(sslStream);
                    HelperMethods.DisplayCertificateInformation(sslStream);
                    HelperMethods.DisplayStreamProperties(sslStream);

                    // Set timeouts to 5 seconds.
                    sslStream.ReadTimeout  = 5000;
                    sslStream.WriteTimeout = 5000;
                }
                catch (AuthenticationException e)
                {
                    Console.WriteLine($"Exception: {e.Message}");
                    if (e.InnerException != null)
                    {
                        Console.WriteLine($"Inner exception: {e.InnerException.Message}");
                    }

                    Console.WriteLine("Authentication failed - closing the connection.");
                    sslStream.Close();
                    clientSocket.Close();
                    Globals.Listener.BeginAccept(ClientConnectCallback, null);// keep listening
                    return;
                }
                catch (Exception e)
                {
                    Console.WriteLine($"Exception: {e.Message}");
                    sslStream.Close();
                    clientSocket.Close();
                    Globals.Listener.BeginAccept(ClientConnectCallback, null);// keep listening
                    return;
                }


                byte[] clientId = new byte[10];
                Globals.Random.NextBytes(clientId);
                string idString = clientId.Aggregate("", (current, idByte) => current + idByte);

                // Keep trying until we get a username that isn't taken
                while (HelperMethods.UsernameTaken(idString))
                {
                    Globals.Random.NextBytes(clientId);
                    idString = clientId.Aggregate("", (current, idByte) => current + idByte);
                }

                ClientInfo newClient = new ClientInfo(clientSocket, sslStream, networkStream);
                newClient.SetUsername(idString);// Set the default username to the randomly generated byte id

                Globals.ClientList.Add(newClient);
                Console.WriteLine($"Client {newClient.GetUsername()} connected");
                newClient.BeginReceiveData();

                Globals.Listener.BeginAccept(ClientConnectCallback, null);
            }
            catch (ObjectDisposedException)
            {
                Console.WriteLine("ClientConnectCallback(): Object already disposed");
            }
            catch (SocketException se)
            {
                Console.WriteLine(se.Message);
            }
        }