private void ReadCallback(IAsyncResult ar) { Client client = ar.AsyncState as Client; try { if (client != null) { NetworkStream networkStream = client.NetworkStream; int bytesRead = networkStream.EndRead(ar); // Keep track of the total number of bytes read in the client client.BytesRead += bytesRead; if (bytesRead == 0) { Console.WriteLine("Got 0 bytes from {0}, marking as OFFLINE.", client.User.Username); RemoveClient(client); } // Allocate a new byte array the size of the data that needs to be read from client.Buffer byte[] data = new byte[bytesRead]; Buffer.BlockCopy( client.Buffer, 0, data, 0, bytesRead); if (client.DataBuffer == null) client.DataBuffer = new MemoryStream(); // Do we need to get the packet length header? if (client.PacketLength == null) { if (client.DataBuffer.Length > 0) { byte[] packetLengthBytes = new byte[4]; Buffer.BlockCopy( client.DataBuffer.ToArray(), 0, packetLengthBytes, 0, packetLengthBytes.Length); client.PacketLength = BitConverter.ToInt32(packetLengthBytes, 0); Console.WriteLine("Found {0} bytes leftover from previous packet to parse, expecting {1} bytes.", client.DataBuffer.Length, client.PacketLength); } else { // Read the first Int32 to get the packet length and then use the byte[4] to get the packetLength byte[] packetLengthBytes = new byte[4]; Buffer.BlockCopy( data, 0, packetLengthBytes, 0, packetLengthBytes.Length); client.PacketLength = BitConverter.ToInt32(packetLengthBytes, 0); } Console.WriteLine("Reading in new packet, size of {0} bytes.", client.PacketLength); } client.DataBuffer.Write(data, 4, (int) client.PacketLength); int actual = (data.Length - 4); Console.WriteLine("> Expecting {0} bytes. Actually recieved {1} bytes.", client.PacketLength, actual); if (actual < client.PacketLength) // is it less than or greater? { // Copy the remaining data do the client.dataBuffer Console.WriteLine(" [!!!] Received less data than the we wanted. Appending rest to the dataBuffer and waiting for more"); byte[] toAppend = new byte[actual]; Buffer.BlockCopy( data, 4, toAppend, 0, actual); client.DataBuffer.Write(toAppend, (int)client.DataBuffer.Length, actual); // Continue listening for more networkStream.BeginRead(client.Buffer, 0, client.Buffer.Length, ReadCallback, client); } else { Console.WriteLine(" > Parsing packet size of {0} bytes and removing that length from the buffer.", client.PacketLength); // Allocate memory for the packet we want to parse based on the packet length we acquired byte[] packetToParse = new byte[(int) client.PacketLength]; // Copy the data Buffer.BlockCopy( client.DataBuffer.ToArray(), 0, packetToParse, 0, (int) client.PacketLength ); // Clear the old data out and leave the remaining int newArray = (int) (client.DataBuffer.Length - client.PacketLength); if (newArray > 0) // Is it greater? { Console.WriteLine(" [!!!] Received more data than we wanted."); byte[] toPutBackInBuffer = new byte[newArray]; Buffer.BlockCopy( client.DataBuffer.ToArray(), (int) client.PacketLength, toPutBackInBuffer, 0, newArray); // Clear client.DataBuffer.Position = 0; client.DataBuffer.SetLength(0); Console.WriteLine(" [!!] Checking extra data sent, size of {0} bytes.", toPutBackInBuffer.Length); client.DataBuffer.Write(toPutBackInBuffer, 0, toPutBackInBuffer.Length); } else { // Tell client to get the length again from a new packet header client.PacketLength = null; // Parse the databuffer CollabPacket.Packet packet = CollabPacket.ClassSerializer.DeserializeByteArray(packetToParse); // Clear the data buffer client.DataBuffer.Position = 0; client.DataBuffer.SetLength(0); if (packet.Message != null) { string[] parts = packet.Message.Split('|'); switch (parts[0]) { case "LOGIN": if (parts.Length > 2) { string username = parts[1]; string password = parts[2]; CollabPacket.Packet loginReply = new CollabPacket.Packet(); if (Program.DbConnection.AuthenticateUser(username, password)) { loginReply.Message = "LOGIN_SUCCESS"; loginReply.User = Program.DbConnection.GetUserByUsername(username); client.User = loginReply.User; AddClient(client); } else { loginReply.Message = "LOGIN_FAILED"; } Write(client.TcpClient, CollabPacket.ClassSerializer.SerializeClass(loginReply)); } break; case "REQUEST_FRIENDS": if (packet.User != null) { // Query out every friend in the databse for the p.User.UserID into a List<User> // Foreach User u in List<User> create a packet with the message LIST_FRIEND and the User object of that individual from List<CollabPacket.User> friends = Program.DbConnection.ReturnFriends(packet.User.UserID); foreach (CollabPacket.User u in friends) { CollabPacket.Packet listFriend = new CollabPacket.Packet {User = u}; // Send the friend as ONLINE if they exist in the connectedClients list, otherwise send them as OFFLINE listFriend.Message = IsFriendOnline(u.UserID) ? "LIST_FRIEND|ONLINE" : "LIST_FRIEND|OFFLINE"; Console.WriteLine("Sending FriendID: {0} to UserID: {1} ({2}).", u.UserID, packet.User.UserID, listFriend.Message.Split('|')[1]); Write(client.TcpClient, CollabPacket.ClassSerializer.SerializeClass(listFriend)); } } break; case "SHARE_REQUEST": if (parts.Length > 3) { int targetUserID = Convert.ToInt32(parts[1]); string windowTitle = parts[2]; IntPtr hWnd = (IntPtr) Convert.ToInt32(parts[3]); CollabPacket.User targetUser = Program.DbConnection.GetUserByUserID(targetUserID); Console.WriteLine( "Got request from {0} to share screen with {1}. Sending request to {1}.", packet.User.Username, targetUser.Username ); CollabPacket.Packet shareRequest = new CollabPacket.Packet { User = packet.User, WindowTitle = windowTitle, ShareID = packet.User.UserID, Message = "SHARE_PROMPT" }; SendToUserID(targetUserID, CollabPacket.ClassSerializer.SerializeClass(shareRequest)); } break; case "MOUSE_MOVE": //Console.WriteLine("Got mouse data from user: {0}x{1}", packet.MousePacket.X, packet.MousePacket.Y); SendToAllExceptSender(packet, client); break; case "I": SendToAllExceptSender(packet, client); break; } // Continue listening for more networkStream.BeginRead(client.Buffer, 0, client.Buffer.Length, ReadCallback, client); } } } } } catch (Exception ex) { Console.WriteLine(ex.Message); // Remove the client from the list. // TODO: Fix // RemoveClient(client); } }
private void RemoveClient(Client c) { // Push out online notification if (_connectedClients.Contains(c)) { if (c.User != null) { Console.WriteLine("User logged OFF: {0}.", c.User.Username); } CollabPacket.Packet onlineNotification = new CollabPacket.Packet { Message = "FRIEND_OFFLINE", User = c.User }; SendToAllExceptSender(onlineNotification, c); lock (_connectedClients) { _connectedClients.Remove(c); } } }
private void ParsePacket(byte[] dataToParse, Client client, NetworkStream networkStream) { CollabPacket.Packet packet = CollabPacket.ClassSerializer.DeserializeByteArray(dataToParse); if (packet.Message != null) { string[] parts = packet.Message.Split('|'); switch (parts[0]) { case "LOGIN": if (parts.Length > 2) { string username = parts[1]; string password = parts[2]; CollabPacket.Packet loginReply = new CollabPacket.Packet(); if (Program.DbConnection.AuthenticateUser(username, password)) { loginReply.Message = "LOGIN_SUCCESS"; loginReply.User = Program.DbConnection.GetUserByUsername(username); client.User = loginReply.User; AddClient(client); } else { loginReply.Message = "LOGIN_FAILED"; } Write(client.TcpClient, CollabPacket.ClassSerializer.SerializeClass(loginReply)); } break; case "REQUEST_FRIENDS": if (packet.User != null) { // Query out every friend in the databse for the p.User.UserID into a List<User> // Foreach User u in List<User> create a packet with the message LIST_FRIEND and the User object of that individual from List<CollabPacket.User> friends = Program.DbConnection.ReturnFriends(packet.User.UserID); foreach (CollabPacket.User u in friends) { CollabPacket.Packet listFriend = new CollabPacket.Packet { User = u }; // Send the friend as ONLINE if they exist in the connectedClients list, otherwise send them as OFFLINE listFriend.Message = IsFriendOnline(u.UserID) ? "LIST_FRIEND|ONLINE" : "LIST_FRIEND|OFFLINE"; Console.WriteLine("Sending FriendID: {0} to UserID: {1} ({2}).", u.UserID, packet.User.UserID, listFriend.Message.Split('|')[1]); Write(client.TcpClient, CollabPacket.ClassSerializer.SerializeClass(listFriend)); } } break; case "SHARE_REQUEST": if (parts.Length > 3) { int targetUserID = Convert.ToInt32(parts[1]); string windowTitle = parts[2]; IntPtr hWnd = (IntPtr)Convert.ToInt32(parts[3]); CollabPacket.User targetUser = Program.DbConnection.GetUserByUserID(targetUserID); Console.WriteLine( "Got request from {0} to share screen with {1}. Sending request to {1}.", packet.User.Username, targetUser.Username ); CollabPacket.Packet shareRequest = new CollabPacket.Packet { User = packet.User, WindowTitle = windowTitle, ShareID = packet.User.UserID, Message = "SHARE_PROMPT" }; SendToUserID(targetUserID, CollabPacket.ClassSerializer.SerializeClass(shareRequest)); } break; case "JOIN_SHARE": Console.WriteLine("{0} joined share id {1}", packet.User.Username, packet.ShareID); CollabPacket.Packet pShareJoin = new CollabPacket.Packet { Message = "JOIN_SHARE", ShareID = packet.ShareID, User = packet.User }; SendToAllExceptSender(pShareJoin, client); break; case "MOUSE_MOVE": //Console.WriteLine("Got mouse data from user: {0}x{1}", packet.MousePacket.X, packet.MousePacket.Y); SendToAllExceptSender(packet, client); break; case "MOUSE_CLICK": //Console.WriteLine("Got mouse data from user: {0}x{1}", packet.MousePacket.X, packet.MousePacket.Y); SendToAllExceptSender(packet, client); break; case "KB": //Console.WriteLine("Got mouse data from user: {0}x{1}", packet.MousePacket.X, packet.MousePacket.Y); SendToAllExceptSender(packet, client); break; case "I": SendToAllExceptSender(packet, client); break; } } }