public void DisconnectClient(SOEClient client, ushort reason, bool clientBased = false) { // Disconnect Log("Disconnecting client on {0} (ID: {1}) for reason: {2}", client.GetClientAddress(), client.GetClientID(), (SOEDisconnectReasons)reason); // Are they a connected client? if (Clients.Contains(client)) { // We don't care about them anymore // Open their ID as a space Host2ClientID.Remove(client.Client); SessionID2ClientID.Remove(client.GetSessionID()); Clients[client.GetClientID()] = null; } // Was this a disconnect request from the client itself? if (!clientBased) { // Tell them we're disconnecting them SOEWriter packetWriter = new SOEWriter((ushort)SOEOPCodes.DISCONNECT); // Arguments packetWriter.AddUInt32(client.GetSessionID()); packetWriter.AddUInt16(reason); // Send! SOEPacket packet = packetWriter.GetFinalSOEPacket(client, true, false); client.SendPacket(packet); } }
public byte[] Encrypt(SOEClient client, byte[] data) { SOEReader reader = new SOEReader(data); SOEWriter newPacket = new SOEWriter(); int blockCount = data.Length / 4; int byteCount = data.Length % 4; uint key = client.GetCRCSeed(); // Encrypt the blocks of 4 bytes for (int i = 0; i < blockCount; i++) { uint value = key = reader.ReadUInt32() ^ key; newPacket.AddUInt32(value); } // Encrypt the rest of the singular bytes byte newKey = (byte)((key >> 24) & 0xFF); for (int i = 0; i < byteCount; i++) { byte value = (byte)(reader.ReadByte() ^ newKey); newPacket.AddByte(value); } // Return the encrypted packet return(newPacket.GetRaw()); }
public void HandlePing(SOEClient sender) { // Setup a writer SOEWriter writer = new SOEWriter((ushort)SOEOPCodes.PING); SOEPacket pong = writer.GetFinalSOEPacket(sender, false, false); // Send a pong! sender.SendPacket(pong); }
private void SendFragmentedMessage(SOEMessage message) { // Are we already busy? if (BusySendingFragmentedPacket) { // The already-busy thread will pick up our message.. FragmentedQueue.Enqueue(message); return; } // Set that we're busy IMMEDIATELY! (thread-safe) BusySendingFragmentedPacket = true; // Setup the for loop SOEWriter writer; SOEPacket packet; ushort sequenceNumber; bool sentInitial = false; // The rest aren't any different for (int i = 0; i < message.GetFragmentCount(); i++) { // Setup a new writer writer = new SOEWriter((ushort)SOEOPCodes.FRAGMENTED_RELIABLE_DATA); // Are we the first packet? if (!sentInitial) { // Add the total message length writer.AddUInt32((uint)message.GetLength()); sentInitial = true; } // Sequence number sequenceNumber = GetNextSequenceNumber(); writer.AddUInt16(sequenceNumber); // Add the message fragment writer.AddBytes(message.GetFragment(i)); // Get the final packet and send it! packet = writer.GetFinalSOEPacket(Client, true, true); Client.SendPacket(packet); } // Did any other thread add a fragmented packet? if (FragmentedQueue.Count > 0) { BusySendingFragmentedPacket = false; SendFragmentedMessage(FragmentedQueue.Dequeue()); } }
private void ReceivedSequenceOutOfOrder(ushort sequenceNumber) { // Setup a writer SOEWriter writer = new SOEWriter((ushort)SOEOPCodes.OUT_OF_ORDER_RELIABLE_DATA); // Where abouts did the sending mess up? writer.AddUInt16(sequenceNumber); // Send the packet SOEPacket packet = writer.GetFinalSOEPacket(Client, true, true); Client.SendPacket(packet); }
public static void SendLoginResponse(SOEClient client, bool success) { // Login Reply SOEWriter writer = new SOEWriter((ushort)LoginMessages.LoginResponse, true); // Success? writer.AddBoolean(success); // Send the reply! SOEMessage reply = writer.GetFinalSOEMessage(client); client.SendMessage(reply); }
public void HandleSessionRequest(SOEClient sender, SOEPacket packet) { // Setup a reader SOEReader reader = new SOEReader(packet); // Get the data from the packet uint crcLength = reader.ReadUInt32(); uint sessionID = reader.ReadUInt32(); uint udpBufferSize = reader.ReadUInt32(); string protocol = reader.ReadNullTerminatedString(); // Is the client using the correct protocol? if (ProtocolString == protocol) { // Can we encrypt/compress? bool encryptable = false; bool compressable = true; // Start the session and manage the client sender.StartSession(crcLength, sessionID, udpBufferSize); sender.SetCompressable(compressable); sender.SetEncryptable(encryptable); Server.ConnectionManager.AddNewClient(sender); // Setup a writer SOEWriter writer = new SOEWriter((ushort)SOEOPCodes.SESSION_RESPONSE); // Write a response writer.AddUInt32(sessionID); writer.AddUInt32(sender.GetCRCSeed()); writer.AddByte((byte)crcLength); writer.AddBoolean(compressable); writer.AddBoolean(encryptable); writer.AddUInt32(udpBufferSize); writer.AddUInt32(3); // Get the response SOEPacket response = writer.GetFinalSOEPacket(sender, false, false); // Send the response! sender.SendPacket(response); } else { // They aren't using the right protocol... Log("Got connection request from client with incorrect protocol. Client: {0}, Server: {1}", protocol, ProtocolString); } }
private void Acknowledge(ushort sequenceNumber) { // Setup a writer SOEWriter writer = new SOEWriter((ushort)SOEOPCodes.ACK_RELIABLE_DATA); // Compressed? (Always false) writer.AddBoolean(false); // Add the sequence number writer.AddUInt16(sequenceNumber); // Send the packet SOEPacket packet = writer.GetFinalSOEPacket(Client, true, true); Client.SendPacket(packet); }
private byte[] DecryptPacket(SOEClient sender, byte[] packet) { // Compressable? if (!sender.IsEncrypted()) { return(packet); } // Setup our streams SOEReader reader = new SOEReader(packet); SOEWriter newPacket = new SOEWriter(reader.ReadUInt16()); // Skip the compression flag reader.ReadByte(); // Get our data int blockCount = (packet.Length - 3) / 4; int byteCount = (packet.Length - 3) % 4; uint key = sender.GetCRCSeed(); // Decrypt the blocks of 4 bytes for (int i = 0; i < blockCount; i++) { uint temp = reader.ReadUInt32(); uint value = temp ^ key; key = temp; newPacket.AddUInt32(value); } // Decrypt the rest of the singular bytes byte newKey = (byte)((key >> 24) & 0xFF); for (int i = 0; i < byteCount; i++) { byte value = (byte)(reader.ReadByte() ^ newKey); newPacket.AddByte(value); } // Return the decrypted packet return(newPacket.GetRaw()); }
private void SendMessage(SOEMessage message) { // Setup a writer SOEWriter writer = new SOEWriter((ushort)SOEOPCodes.RELIABLE_DATA); // Sequence number ushort sequenceNumber = GetNextSequenceNumber(); writer.AddUInt16(sequenceNumber); // Add the message writer.AddMessage(message); // Get the final packet and send it! SOEPacket packet = writer.GetFinalSOEPacket(Client, true, true); Client.SendPacket(packet); // TODO repeat-till-acknowledged }
private void ReceiveFragment(SOEPacket packet) { // Setup a reader SOEReader reader = new SOEReader(packet); reader.ReadUInt16(); // Have we already started a fragmented packet? if (StartedFragmentedPacket) { // One less fragment till we need to acknowledge! FragmentsTillAck--; // Get our sequence number uint previousFragmentSequenceNumber = FragmentSequenceNumber; FragmentSequenceNumber = reader.ReadUInt16(); // Did we get a correct sequence number? if (FragmentSequenceNumber != previousFragmentSequenceNumber + 1) { // Out of order! ReceivedSequenceOutOfOrder(FragmentSequenceNumber); return; } // Append the rest of the packet to the fragmented data for (int i = 4; i < FragmentedData.Length; i++) { FragmentedData[ReceivedFragmentsSize] = reader.ReadByte(); ReceivedFragmentsSize++; } } else { // We're expecting the starting packet FragmentSequenceNumber = reader.ReadUInt16(); uint totalSize = reader.ReadUInt32(); // Is this a valid sequence number? if ((FragmentSequenceNumber != LastReceivedSequenceNumber + 1) && (FragmentSequenceNumber != 0)) { // Out of order! ReceivedSequenceOutOfOrder(FragmentSequenceNumber); return; } // Get the total size FragmentedData = new byte[totalSize]; // How many fragments till we need to acknowledge FragmentsTillAck = 4; // Append the rest of the packet to the fragmented data for (int i = 8; i < FragmentedData.Length; i++) { FragmentedData[ReceivedFragmentsSize] = reader.ReadByte(); ReceivedFragmentsSize++; } // Started a fragmented packet StartedFragmentedPacket = true; } // Are we finished with the fragmented data? if (ReceivedFragmentsSize >= FragmentedData.Length) { // Finish fragmented packet StartedFragmentedPacket = false; FragmentsTillAck = 0; // Handle the fragmented packet as a RELIABLE_DATA packet SOEWriter writer = new SOEWriter((ushort)SOEOPCodes.RELIABLE_DATA); writer.AddBytes(FragmentedData); SOEPacket wholePacket = writer.GetFinalSOEPacket(Client, false, false); // Receive this packet! Receive(wholePacket); return; } // Do we need to acknowledge? if (FragmentsTillAck == 0) { Acknowledge(FragmentSequenceNumber); FragmentsTillAck = 5; } }
public static void HandleLoginRequest(LoginRequest request) { // Get variables string loginServer = Server.ApplicationConfiguration["LoginServer"]; string apiRequest = loginServer + "consumeToken/"; JObject response = null; using (var client = new WebClient { Proxy = null }) { var values = new NameValueCollection(); values["token"] = request.Token; var responseRaw = client.UploadValues(apiRequest, values); var responseString = Encoding.ASCII.GetString(responseRaw); try { response = JObject.Parse(responseString); } catch (Exception) { Log.Fatal("Received bad response from login server!"); Environment.Exit(0); } } if (response != null) { bool success = response["success"].ToObject <bool>(); if (success) { // Get the account! Account userAccount = response["account"].ToObject <Account>(); // Is the user banned? if (userAccount.Banned) { // Report the attempt and disconnect them Log.ErrorFormat("Received successful login for client {0} but this user is banned!", request.Client.GetClientID()); SendLoginResponse(request.Client, false); request.Client.Disconnect((ushort)SOEDisconnectReasons.Application); } else { // Check if they're allowed to be on this server if (userAccount.AccessLevel < (int)Server.ApplicationConfiguration["MinimumAccessLevel"]) { // Log the attempt Log.ErrorFormat("Received successful login for client {0} but this user doesn't meet the required minimum access level!", request.Client.GetClientID()); SendLoginResponse(request.Client, false); // Disconnect them request.Client.Disconnect((ushort)SOEDisconnectReasons.Application); return; } // Send the succesful login response! Log.Info("Successful login!"); SendLoginResponse(request.Client, true); // Manage the account on the gateway AccountManager.AddAccount(request.Client, userAccount); // Send the connection to the world server // Server.InternalManager.GetConnection("World").RouteConnection(request.Client, response.ToString()); // Gateway.InternalWorldConnection.RouteConnection(request.Client, response.ToString()); // The world server will then do a: 'Which internal connection is managing this connection?', // assign the client a world-clientID, map clients to internal servers, and then send packets // to us with a tagged "reciever". "reciever" will be the clientId on our side.. // Gateway1 -> { Client, 0x01 } -> World { Client, Gateway1, 0x01, 0x04 } // Client (0x01) <- Gateway1 <- { 0x01, data } <- World { 0x04 -> 0x01 (Gateway1) } // TODO: ^ // The world server would then send the client the Environment, World, Character, etc.. // For now, send that stuff from the gateway: // Environment SOEWriter commandWriter = new SOEWriter(0xA6, true); commandWriter.AddASCIIString("live"); byte[] environmentCommand = commandWriter.GetRaw(); SOEWriter writer = new SOEWriter((ushort)GatewayMessages.EnqueueCommand, true); writer.AddBoolean(true); writer.AddHostUInt32((uint)environmentCommand.Length); writer.AddBytes(environmentCommand); SOEMessage environmentMessage = writer.GetFinalSOEMessage(request.Client); // ZoneInfo commandWriter = new SOEWriter(0x2B, true); commandWriter.AddASCIIString("FabledRealms"); commandWriter.AddHostUInt32(2); commandWriter.AddHostUInt32(0); commandWriter.AddHostUInt32(0); commandWriter.AddUInt32(5); commandWriter.AddHostUInt32(0); commandWriter.AddBoolean(false); byte[] worldCommand = commandWriter.GetRaw(); writer = new SOEWriter((ushort)GatewayMessages.EnqueueCommand, true); writer.AddBoolean(true); writer.AddHostUInt32((uint)worldCommand.Length); writer.AddBytes(worldCommand); SOEMessage worldMessage = writer.GetFinalSOEMessage(request.Client); // Send! request.Client.SendMessage(environmentMessage); request.Client.SendMessage(worldMessage); } } else { // Send an unsucessful login response Log.ErrorFormat("Received invalid token from client {0}!", request.Client.GetClientID()); SendLoginResponse(request.Client, false); // Disconnect the requesting Client request.Client.Disconnect((ushort)SOEDisconnectReasons.Application); } } }