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); } }
private void DoReceiveFrom(IAsyncResult iar) { //Get the received message. Socket recvSock = (Socket)iar.AsyncState; EndPoint clientEP = new IPEndPoint(IPAddress.Any, 0); int msgLen = recvSock.EndReceiveFrom(iar, ref clientEP); byte[] localMsg = new byte[msgLen]; Array.Copy(buffer, localMsg, msgLen); //Start listening for a new message. EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0); udpSock.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP, DoReceiveFrom, udpSock); // Found our client if (origin == null || (origin.Port != ((IPEndPoint)clientEP).Port) && ((IPEndPoint)clientEP).Address.Equals(origin.Address)) { if (origin != null) { Console.WriteLine("[Info] Found new client, did the old one get disconnected?"); } else { Console.WriteLine("[Info] Found new client"); } origin = (IPEndPoint)clientEP; } // Message is C -> S if (((IPEndPoint)clientEP).Address.Equals(origin.Address)) { udpSock.SendTo(localMsg, destination); } // Message is S -> C else { switch (localMsg[1]) { case 2: // SOE_SESSION_REPLY byte[] crcSeed = new byte[4]; Array.Copy(localMsg, 6, crcSeed, 0, 4); Program.session = new Session(crcSeed); break; case 9: // SOE_CHL_DATA_A SOEPacket packet = new SOEPacket(localMsg); Console.WriteLine("[Debug] Packet " + (localMsg.SequenceEqual(packet.ToArray()) ? "succesfully" : "unsuccessfully") + " rebuilt"); localMsg = packet.ToArray(); break; default: Console.WriteLine("[Debug] Unknown SOE opcode: {0}", localMsg[1]); break; } udpSock.SendTo(localMsg, origin); } }
public void SendPacket(SOEPacket packet) { // Send the packet Server.SendPacket(this, packet); // This client is still alive Interact(); }
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 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 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); } }
public void HandlePacket(SOEClient sender, SOEPacket packet) { // Operation ushort opCode = packet.GetOpCode(); // Security Measure if (!sender.HasSession()) { if (opCode != (ushort)SOEOPCodes.SESSION_REQUEST) { // We really don't care about this client. // They can try send stuff as much as possible. // TODO: Handle this (cuz attacks) return; } } // Handle! switch ((SOEOPCodes)opCode) { case SOEOPCodes.SESSION_REQUEST: HandleSessionRequest(sender, packet); break; case SOEOPCodes.MULTI: Console.WriteLine("MULTI!"); // TODO break; case SOEOPCodes.DISCONNECT: HandleDisconnect(sender, packet); break; case SOEOPCodes.PING: HandlePing(sender); break; case SOEOPCodes.RELIABLE_DATA: case SOEOPCodes.FRAGMENTED_RELIABLE_DATA: case SOEOPCodes.ACK_RELIABLE_DATA: sender.DataChannel.Receive(packet); break; default: Log("Received Unknown SOEPacket 0x{0:X2}!", packet.GetOpCode()); break; } }
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); }
public void HandleDisconnect(SOEClient sender, SOEPacket packet) { // Setup a reader SOEReader reader = new SOEReader(packet); // Get the data from the packet uint sessionID = reader.ReadUInt32(); ushort reason = reader.ReadUInt16(); // Handle if (sessionID == sender.GetSessionID()) { Console.WriteLine("Disconnecting"); Server.ConnectionManager.DisconnectClient(sender, reason, true); } }
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 }
public void Receive(SOEPacket packet) { ushort opCode = packet.GetOpCode(); if (opCode == (ushort)SOEOPCodes.FRAGMENTED_RELIABLE_DATA) { ReceiveFragment(packet); } else if (opCode == (ushort)SOEOPCodes.RELIABLE_DATA) { ReceiveMessage(packet); } else if (opCode == (ushort)SOEOPCodes.ACK_RELIABLE_DATA) { // TODO: Handle repeat-until-acknowledged and all that comes with it. Log("Data Ack"); } else { // Shrug ¯\_(ツ)_/¯ Log("Received a packet that was not data or acknowledge. Discarding.."); } }
private void ReceiveMessage(SOEPacket packet) { SOEReader reader = new SOEReader(packet); // Have we received in order? ushort sequenceNumber = reader.ReadUInt16(); if ((sequenceNumber != LastReceivedSequenceNumber + 1) && (sequenceNumber != 0)) { ReceivedSequenceOutOfOrder(sequenceNumber); return; } // Acknowledge Acknowledge(sequenceNumber); LastReceivedSequenceNumber = sequenceNumber; // Get the SOEMessage byte[] data = reader.ReadToEnd(); // Handle! Client.ReceiveMessage(data); }
public void SendPacket(SOEClient client, SOEPacket packet) { // Send the message UdpClient.Send(packet.GetRaw(), packet.GetLength(), client.Client); }
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; } }