private void HandleSplitMessage(PlayerNetworkSession playerSession, ConnectedPackage package, SplitPartPackage splitMessage) { int spId = package._splitPacketId; int spIdx = package._splitPacketIndex; int spCount = package._splitPacketCount; if (!playerSession.Splits.ContainsKey(spId)) { playerSession.Splits.TryAdd(spId, new SplitPartPackage[spCount]); } SplitPartPackage[] spPackets = playerSession.Splits[spId]; spPackets[spIdx] = splitMessage; bool haveEmpty = false; for (int i = 0; i < spPackets.Length; i++) { haveEmpty = haveEmpty || spPackets[i] == null; } if (!haveEmpty) { Log.DebugFormat("Got all {0} split packages for split ID: {1}", spCount, spId); SplitPartPackage[] waste; playerSession.Splits.TryRemove(spId, out waste); MemoryStream stream = new MemoryStream(); for (int i = 0; i < spPackets.Length; i++) { SplitPartPackage splitPartPackage = spPackets[i]; byte[] buf = splitPartPackage.Message; stream.Write(buf, 0, buf.Length); splitPartPackage.PutPool(); } byte[] buffer = stream.ToArray(); byte id = buffer[0]; if (id == 0x8e) { id = buffer[1]; } Package fullMessage = PackageFactory.CreatePackage(id, buffer) ?? new UnknownPackage(id, buffer); fullMessage.DatagramSequenceNumber = package._datagramSequenceNumber; fullMessage.OrderingChannel = package._orderingChannel; fullMessage.OrderingIndex = package._orderingIndex; if (!(fullMessage is McpeBatch)) { Log.Debug($"Split: {fullMessage.GetType().Name} 0x{fullMessage.Id:x2} \n{Package.HexDump(buffer)}"); } HandlePackage(fullMessage); fullMessage.PutPool(); } }
private void SendDatagram(PlayerNetworkSession session, Datagram datagram) { if (datagram.MessageParts.Count != 0) { datagram.Header.datagramSequenceNumber = Interlocked.Increment(ref Session.DatagramSequenceNumber); byte[] data = datagram.Encode(); datagram.Timer.Restart(); SendData(data, _serverEndpoint); } }
public bool StartServer() { if (Listener != null) { return(false); // Already started } try { Log.Info("Initializing..."); Listener = new UdpClient(_clientEndpoint); if (IsRunningOnMono()) { Listener.Client.ReceiveBufferSize = 1024 * 1024 * 3; Listener.Client.SendBufferSize = 4096; } else { Listener.Client.ReceiveBufferSize = int.MaxValue; Listener.Client.SendBufferSize = int.MaxValue; Listener.DontFragment = false; // SIO_UDP_CONNRESET (opcode setting: I, T==3) // Windows: Controls whether UDP PORT_UNREACHABLE messages are reported. // - Set to TRUE to enable reporting. // - Set to FALSE to disable reporting. uint IOC_IN = 0x80000000; uint IOC_VENDOR = 0x18000000; uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; Listener.Client.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null); //// ////WARNING: We need to catch errors here to remove the code above. //// } Session = new PlayerNetworkSession(null, _clientEndpoint); Listener.BeginReceive(ReceiveCallback, Listener); Log.InfoFormat("Server open for business for {0}", Username); return(true); } catch (Exception e) { Log.Error(e); StopServer(); } return(false); }
public void StartClient() { if (UdpClient != null) { return; } try { Log.Info("Initializing..."); UdpClient = new UdpClient(_clientEndpoint) { Client = { ReceiveBufferSize = int.MaxValue, SendBufferSize = int.MaxValue }, DontFragment = false }; // SIO_UDP_CONNRESET (opcode setting: I, T==3) // Windows: Controls whether UDP PORT_UNREACHABLE messages are reported. // - Set to TRUE to enable reporting. // - Set to FALSE to disable reporting. //uint IOC_IN = 0x80000000; //uint IOC_VENDOR = 0x18000000; //uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; //UdpClient.Client.IOControl((int) SIO_UDP_CONNRESET, new byte[] {Convert.ToByte(false)}, null); //// ////WARNING: We need to catch errors here to remove the code above. //// Session = new PlayerNetworkSession(null, _clientEndpoint); UdpClient.BeginReceive(ReceiveCallback, UdpClient); _clientEndpoint = (IPEndPoint)UdpClient.Client.LocalEndPoint; Log.InfoFormat("Server open for business for {0}", Username); return; } catch (Exception e) { Log.Error("Main loop", e); StopClient(); } }
private void HandleSplitMessage(PlayerNetworkSession playerSession, ConnectedPackage package, SplitPartPackage splitMessage) { int spId = package._splitPacketId; int spIdx = package._splitPacketIndex; int spCount = package._splitPacketCount; if (!playerSession.Splits.ContainsKey(spId)) { playerSession.Splits.Add(spId, new SplitPartPackage[spCount]); } SplitPartPackage[] spPackets = playerSession.Splits[spId]; spPackets[spIdx] = splitMessage; bool haveEmpty = false; for (int i = 0; i < spPackets.Length; i++) { haveEmpty = haveEmpty || spPackets[i] == null; } if (!haveEmpty) { Log.DebugFormat("Got all {0} split packages for split ID: {1}", spCount, spId); MemoryStream stream = new MemoryStream(); for (int i = 0; i < spPackets.Length; i++) { SplitPartPackage splitPartPackage = spPackets[i]; byte[] buf = splitPartPackage.Message; stream.Write(buf, 0, buf.Length); splitPartPackage.PutPool(); } playerSession.Splits.Remove(spId); byte[] buffer = stream.ToArray(); Package fullMessage = PackageFactory.CreatePackage(buffer[0], buffer) ?? new UnknownPackage(buffer[0], buffer); fullMessage.DatagramSequenceNumber = package._datagramSequenceNumber; fullMessage.OrderingChannel = package._orderingChannel; fullMessage.OrderingIndex = package._orderingIndex; HandlePackage(fullMessage); fullMessage.PutPool(); } }
public static IEnumerable <Datagram> CreateDatagrams(Package message, int mtuSize, PlayerNetworkSession session) { if (message is InternalPing) { yield break; } Datagram datagram = CreateObject(); //datagram.Reset(); var messageParts = GetMessageParts(message, mtuSize, Reliability.Reliable, ref session.ReliableMessageNumber); foreach (var messagePart in messageParts) { if (!datagram.TryAddMessagePart(messagePart, mtuSize)) { yield return(datagram); datagram = CreateObject(); //datagram.Reset(); if (!datagram.TryAddMessagePart(messagePart, mtuSize)) { Log.Warn(string.Format("Message part too big for a single datagram. Size: {0}, MTU: {1}", messagePart.Encode().Length, mtuSize)); throw new Exception(string.Format("Message part too big for a single datagram. Size: {0}, MTU: {1}", messagePart.Encode().Length, mtuSize)); } } } yield return(datagram); }
private static List <MessagePart> GetMessageParts(Packet message, int mtuSize, Reliability reliability, PlayerNetworkSession session) { var messageParts = new List <MessagePart>(); Memory <byte> encodedMessage = message.Encode(); //if (Log.IsDebugEnabled && message is McpeBatch) // Log.Debug($"0x{encodedMessage[0]:x2}\n{Package.HexDump(encodedMessage)}"); int orderingIndex = 0; if (!(message is ConnectedPong) && !(message is DetectLostConnections)) { reliability = Reliability.ReliableOrdered; } CryptoContext cryptoContext = session.CryptoContext; if (cryptoContext != null && !(message is ConnectedPong) && !(message is DetectLostConnections)) { lock (session.EncodeSync) { reliability = Reliability.ReliableOrdered; var isBatch = message is McpeWrapper; if (!message.ForceClear && session.CryptoContext.UseEncryption) { if (isBatch) { encodedMessage = encodedMessage.Slice(1); } else { encodedMessage = Compression.Compress(encodedMessage, true, encodedMessage.Length > 1000 ? CompressionLevel.Fastest : CompressionLevel.NoCompression); } McpeWrapper wrapper = McpeWrapper.CreateObject(); wrapper.payload = CryptoUtils.Encrypt(encodedMessage, cryptoContext); encodedMessage = wrapper.Encode(); wrapper.PutPool(); } else if (!isBatch) { McpeWrapper wrapper = McpeWrapper.CreateObject(); wrapper.payload = Compression.Compress(encodedMessage, true, encodedMessage.Length > 1000 ? CompressionLevel.Fastest : CompressionLevel.NoCompression); encodedMessage = wrapper.Encode(); wrapper.PutPool(); } //if (Log.IsDebugEnabled) // Log.Debug($"0x{encodedMessage[0]:x2}\n{Package.HexDump(encodedMessage)}"); } } //if (Log.IsDebugEnabled) // Log.Debug($"0x{encodedMessage[0]:x2}\n{Package.HexDump(encodedMessage)}"); if (reliability == Reliability.ReliableOrdered) { orderingIndex = Interlocked.Increment(ref session.OrderingIndex); } if (encodedMessage.IsEmpty) { return(messageParts); } int datagramHeaderSize = 100; int count = (int)Math.Ceiling(encodedMessage.Length / ((double)mtuSize - datagramHeaderSize)); int index = 0; if (session.SplitPartId > short.MaxValue - 100) { Interlocked.CompareExchange(ref session.SplitPartId, 0, short.MaxValue); } short splitId = (short)Interlocked.Increment(ref session.SplitPartId); if (count <= 1) { MessagePart messagePart = MessagePart.CreateObject(); messagePart.Header.Reliability = reliability; messagePart.Header.ReliableMessageNumber = Interlocked.Increment(ref session.ReliableMessageNumber); messagePart.Header.HasSplit = count > 1; messagePart.Header.PartCount = count; messagePart.Header.PartId = splitId; messagePart.Header.PartIndex = index++; messagePart.Header.OrderingChannel = 0; messagePart.Header.OrderingIndex = orderingIndex; messagePart.ContainedMessageId = message.Id; messagePart.Buffer = encodedMessage.ToArray(); messageParts.Add(messagePart); } else { foreach ((int from, int to)span in ArraySplit(encodedMessage.Length, mtuSize - datagramHeaderSize)) { MessagePart messagePart = MessagePart.CreateObject(); messagePart.Header.Reliability = reliability; messagePart.Header.ReliableMessageNumber = Interlocked.Increment(ref session.ReliableMessageNumber); messagePart.Header.HasSplit = count > 1; messagePart.Header.PartCount = count; messagePart.Header.PartId = splitId; messagePart.Header.PartIndex = index++; messagePart.Header.OrderingChannel = 0; messagePart.Header.OrderingIndex = orderingIndex; messagePart.ContainedMessageId = message.Id; messagePart.Buffer = encodedMessage.Slice(span.from, span.to); messageParts.Add(messagePart); } } return(messageParts); }
public static IEnumerable <Datagram> CreateDatagrams(Packet message, int mtuSize, PlayerNetworkSession session) { if (message is InternalPing) { yield break; } Datagram datagram = CreateObject(); List <MessagePart> messageParts = GetMessageParts(message, mtuSize, Reliability.Reliable, session); foreach (var messagePart in messageParts) { if (!datagram.TryAddMessagePart(messagePart, mtuSize)) { yield return(datagram); datagram = CreateObject(); if (datagram.MessageParts.Count != 0) { throw new Exception("Excepted no message parts in new message"); } if (!datagram.TryAddMessagePart(messagePart, mtuSize)) { string error = $"Message part too big for a single datagram. Size: {messagePart.Encode().Length}, MTU: {mtuSize}"; Log.Error(error); throw new Exception(error); } } } yield return(datagram); }
public static void CreateDatagrams(List <Package> messages, int mtuSize, ref int reliableMessageNumber, PlayerNetworkSession session, Action <PlayerNetworkSession, Datagram> sendDatagram) { Datagram datagram = null; foreach (var message in messages) { if (message is InternalPing) { continue; } var messageParts = GetMessageParts(message, mtuSize, Reliability.Reliable, ref reliableMessageNumber); foreach (var messagePart in messageParts) { if (datagram == null) { datagram = CreateObject(); } if (!datagram.TryAddMessagePart(messagePart, mtuSize)) { Datagram datagram1 = datagram; sendDatagram(session, datagram1); datagram = CreateObject(); if (!datagram.TryAddMessagePart(messagePart, mtuSize)) { throw new Exception(string.Format("Message part too big for a single datagram. Size: {0}, MTU: {1}", messagePart.Encode().Length, mtuSize)); } } } } if (datagram != null) { sendDatagram(session, datagram); } }
private void HandleSplitMessage(PlayerNetworkSession playerSession, ConnectedPackage package, SplitPartPackage splitMessage) { int spId = package._splitPacketId; int spIdx = package._splitPacketIndex; int spCount = package._splitPacketCount; if (!playerSession.Splits.ContainsKey(spId)) { playerSession.Splits.TryAdd(spId, new SplitPartPackage[spCount]); } SplitPartPackage[] spPackets = playerSession.Splits[spId]; spPackets[spIdx] = splitMessage; bool haveEmpty = false; for (int i = 0; i < spPackets.Length; i++) { haveEmpty = haveEmpty || spPackets[i] == null; } if (!haveEmpty) { Log.DebugFormat("Got all {0} split packages for split ID: {1}", spCount, spId); SplitPartPackage[] waste; playerSession.Splits.TryRemove(spId, out waste); MemoryStream stream = new MemoryStream(); for (int i = 0; i < spPackets.Length; i++) { SplitPartPackage splitPartPackage = spPackets[i]; byte[] buf = splitPartPackage.Message; stream.Write(buf, 0, buf.Length); splitPartPackage.PutPool(); } byte[] buffer = stream.ToArray(); Package fullMessage = PackageFactory.CreatePackage(buffer[0], buffer) ?? new UnknownPackage(buffer[0], buffer); fullMessage.DatagramSequenceNumber = package._datagramSequenceNumber; fullMessage.OrderingChannel = package._orderingChannel; fullMessage.OrderingIndex = package._orderingIndex; HandlePackage(fullMessage); fullMessage.PutPool(); } }
public void StartClient() { if (UdpClient != null) return; try { Log.Info("Initializing..."); UdpClient = new UdpClient(_clientEndpoint) { Client = { ReceiveBufferSize = int.MaxValue, SendBufferSize = int.MaxValue }, DontFragment = false }; // SIO_UDP_CONNRESET (opcode setting: I, T==3) // Windows: Controls whether UDP PORT_UNREACHABLE messages are reported. // - Set to TRUE to enable reporting. // - Set to FALSE to disable reporting. //uint IOC_IN = 0x80000000; //uint IOC_VENDOR = 0x18000000; //uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; //UdpClient.Client.IOControl((int) SIO_UDP_CONNRESET, new byte[] {Convert.ToByte(false)}, null); //// ////WARNING: We need to catch errors here to remove the code above. //// Session = new PlayerNetworkSession(null, _clientEndpoint); UdpClient.BeginReceive(ReceiveCallback, UdpClient); _clientEndpoint = (IPEndPoint) UdpClient.Client.LocalEndPoint; Log.InfoFormat("Server open for business for {0}", Username); return; } catch (Exception e) { Log.Error("Main loop", e); StopClient(); } }
private static List <MessagePart> GetMessageParts(Package message, int mtuSize, Reliability reliability, PlayerNetworkSession session) { var messageParts = new List <MessagePart>(); byte[] encodedMessage = message.Encode(); int orderingIndex = 0; CryptoContext cryptoContext = session.CryptoContext; if (cryptoContext != null && !(message is ConnectedPong) && !(message is DetectLostConnections)) { lock (session.EncodeSync) { McpeWrapper wrapper = McpeWrapper.CreateObject(); reliability = Reliability.ReliableOrdered; orderingIndex = Interlocked.Increment(ref session.OrderingIndex); if (!message.ForceClear && session.CryptoContext.UseEncryption) { wrapper.payload = CryptoUtils.Encrypt(encodedMessage, cryptoContext); } else { wrapper.payload = encodedMessage; } encodedMessage = wrapper.Encode(); //if (Log.IsDebugEnabled) // Log.Debug($"0x{encodedMessage[0]:x2}\n{Package.HexDump(encodedMessage)}"); wrapper.PutPool(); } } //if (Log.IsDebugEnabled) // Log.Debug($"0x{encodedMessage[0]:x2}\n{Package.HexDump(encodedMessage)}"); if (encodedMessage == null) { return(messageParts); } int datagramHeaderSize = 100; int count = (int)Math.Ceiling(encodedMessage.Length / ((double)mtuSize - datagramHeaderSize)); int index = 0; if (session.SplitPartId > short.MaxValue - 100) { Interlocked.CompareExchange(ref session.SplitPartId, 0, short.MaxValue); } short splitId = (short)Interlocked.Increment(ref session.SplitPartId); if (count <= 1) { MessagePart messagePart = MessagePart.CreateObject(); messagePart.Header.Reliability = reliability; messagePart.Header.ReliableMessageNumber = Interlocked.Increment(ref session.ReliableMessageNumber); messagePart.Header.HasSplit = count > 1; messagePart.Header.PartCount = count; messagePart.Header.PartId = splitId; messagePart.Header.PartIndex = index++; messagePart.Header.OrderingChannel = 0; messagePart.Header.OrderingIndex = orderingIndex; messagePart.ContainedMessageId = message.Id; messagePart.Buffer = encodedMessage; messageParts.Add(messagePart); } else { foreach (var bytes in ArraySplit(encodedMessage, mtuSize - datagramHeaderSize)) { MessagePart messagePart = MessagePart.CreateObject(); messagePart.Header.Reliability = reliability; messagePart.Header.ReliableMessageNumber = Interlocked.Increment(ref session.ReliableMessageNumber); messagePart.Header.HasSplit = count > 1; messagePart.Header.PartCount = count; messagePart.Header.PartId = splitId; messagePart.Header.PartIndex = index++; messagePart.Header.OrderingChannel = 0; messagePart.Header.OrderingIndex = orderingIndex; messagePart.ContainedMessageId = message.Id; messagePart.Buffer = bytes; messageParts.Add(messagePart); } } return(messageParts); }
public bool StartServer() { if (Listener != null) return false; // Already started try { Log.Info("Initializing..."); Listener = new UdpClient(_clientEndpoint); if (IsRunningOnMono()) { Listener.Client.ReceiveBufferSize = 1024*1024*3; Listener.Client.SendBufferSize = 4096; } else { Listener.Client.ReceiveBufferSize = int.MaxValue; Listener.Client.SendBufferSize = int.MaxValue; Listener.DontFragment = false; // SIO_UDP_CONNRESET (opcode setting: I, T==3) // Windows: Controls whether UDP PORT_UNREACHABLE messages are reported. // - Set to TRUE to enable reporting. // - Set to FALSE to disable reporting. uint IOC_IN = 0x80000000; uint IOC_VENDOR = 0x18000000; uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; Listener.Client.IOControl((int) SIO_UDP_CONNRESET, new byte[] {Convert.ToByte(false)}, null); //// ////WARNING: We need to catch errors here to remove the code above. //// } Session = new PlayerNetworkSession(null, _clientEndpoint); Listener.BeginReceive(ReceiveCallback, Listener); Log.InfoFormat("Server open for business for {0}", Username); return true; } catch (Exception e) { Log.Error(e); StopServer(); } return false; }
private void SendDatagram(PlayerNetworkSession session, Datagram datagram) { SendDatagram(session.EndPoint, datagram, false); }
public void SendPackage(IPEndPoint senderEndpoint, List<Package> messages, short mtuSize, ref int datagramSequenceNumber, ref int reliableMessageNumber, Reliability reliability = Reliability.Reliable) { if (messages.Count == 0) return; foreach (var message in messages) { TraceSend(message); } PlayerNetworkSession session = new PlayerNetworkSession(null, senderEndpoint); Datagram.CreateDatagrams(messages, mtuSize, ref reliableMessageNumber, session, SendDatagram); }