// on user thread private NetSendResult SendFragmentedMessage(NetOutgoingMessage msg, IList<NetConnection> recipients, NetDeliveryMethod method, int sequenceChannel) { // Note: this group id is PER SENDING/NetPeer; ie. same id is sent to all recipients; // this should be ok however; as long as recipients differentiate between same id but different sender int group = Interlocked.Increment(ref m_lastUsedFragmentGroup); if (group >= NetConstants.MaxFragmentationGroups) { // @TODO: not thread safe; but in practice probably not an issue m_lastUsedFragmentGroup = 1; group = 1; } msg.m_fragmentGroup = group; // do not send msg; but set fragmentgroup in case user tries to recycle it immediately // create fragmentation specifics int totalBytes = msg.LengthBytes; // determine minimum mtu for all recipients int mtu = GetMTU(recipients); int bytesPerChunk = NetFragmentationHelper.GetBestChunkSize(group, totalBytes, mtu); int numChunks = totalBytes / bytesPerChunk; if (numChunks * bytesPerChunk < totalBytes) numChunks++; NetSendResult retval = NetSendResult.Sent; int bitsPerChunk = bytesPerChunk * 8; int bitsLeft = msg.LengthBits; for (int i = 0; i < numChunks; i++) { NetOutgoingMessage chunk = CreateMessage(0); chunk.m_bitLength = (bitsLeft > bitsPerChunk ? bitsPerChunk : bitsLeft); chunk.m_data = msg.m_data; chunk.m_fragmentGroup = group; chunk.m_fragmentGroupTotalBits = totalBytes * 8; chunk.m_fragmentChunkByteSize = bytesPerChunk; chunk.m_fragmentChunkNumber = i; NetException.Assert(chunk.m_bitLength != 0); NetException.Assert(chunk.GetEncodedSize() < mtu); Interlocked.Add(ref chunk.m_recyclingCount, recipients.Count); foreach (NetConnection recipient in recipients) { var res = recipient.EnqueueMessage(chunk, method, sequenceChannel); if (res == NetSendResult.Dropped) Interlocked.Decrement(ref chunk.m_recyclingCount); if ((int)res > (int)retval) retval = res; // return "worst" result } bitsLeft -= bitsPerChunk; } return retval; }
public void WriteToMessage(NetOutgoingMessage message) { message.Write(SessionID); message.Write(ID); message.Write(IsValid); message.Write(PlayerIndex); }
internal override NetSendResult Enqueue(NetOutgoingMessage message) { m_queuedSends.Enqueue(message); if (m_queuedSends.Count <= GetAllowedSends()) return NetSendResult.Sent; return NetSendResult.Queued; }
protected override void WriteData(NetOutgoingMessage Message) { texture.Write(Message); byte[] data = GetBytes(texture.Texture); Message.Write((Int32)data.Length); Message.Write(data); }
/// <summary> /// Send a message to a specific connection /// </summary> /// <param name="msg">The message to send</param> /// <param name="recipient">The recipient connection</param> /// <param name="method">How to deliver the message</param> /// <param name="sequenceChannel">Sequence channel within the delivery method</param> public NetSendResult SendMessage(NetOutgoingMessage msg, NetConnection recipient, NetDeliveryMethod method, int sequenceChannel) { if (msg == null) throw new ArgumentNullException("msg"); if (recipient == null) throw new ArgumentNullException("recipient"); if (sequenceChannel >= NetConstants.NetChannelsPerDeliveryMethod) throw new ArgumentOutOfRangeException("sequenceChannel"); NetException.Assert( ((method != NetDeliveryMethod.Unreliable && method != NetDeliveryMethod.ReliableUnordered) || ((method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered) && sequenceChannel == 0)), "Delivery method " + method + " cannot use sequence channels other than 0!" ); NetException.Assert(method != NetDeliveryMethod.Unknown, "Bad delivery method!"); if (msg.m_isSent) throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently"); msg.m_isSent = true; int len = NetConstants.UnfragmentedMessageHeaderSize + msg.LengthBytes; // headers + length, faster than calling msg.GetEncodedSize if (len <= recipient.m_currentMTU) { Interlocked.Increment(ref msg.m_recyclingCount); return recipient.EnqueueMessage(msg, method, sequenceChannel); } else { // message must be fragmented! SendFragmentedMessage(msg, new NetConnection[] { recipient }, method, sequenceChannel); return NetSendResult.Queued; // could be different for each connection; Queued is "most true" } }
public void Encode(NetOutgoingMessage om) { om.Write(this.MessageTime); om.Write(this.Id); om.Write(this.OldPosition); om.Write(this.NewPosition); }
private void SerializeStream(NetOutgoingMessage netOutgoingMessage) { //send our position to the server //this should only be happening on an object that is ours _serializer.vector3 = transform.position; _serializer.OnSerialize(netOutgoingMessage); }
public void SendBlockSet(BlockTypes type,Vector3 pos) { _outmsg = _client.CreateMessage(); _outmsg.Write((byte)PacketType.PlayerBlockSet); _outmsg.Write(pos); _outmsg.Write((byte)type); }
public NetOutgoingMessage Pack(NetOutgoingMessage msg) { msg.Write((byte)packetType); msg.Write(username); msg.Write(message); return msg; }
public void SendMessage(NetOutgoingMessage msg, IList<NetConnection> recipients, NetDeliveryMethod method, int sequenceChannel) { if (msg == null) throw new ArgumentNullException("msg"); if (recipients == null) throw new ArgumentNullException("recipients"); if (method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered) NetException.Assert(sequenceChannel == 0, "Delivery method " + method + " cannot use sequence channels other than 0!"); if (msg.m_isSent) throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently"); int len = msg.LengthBytes; if (len <= m_configuration.MaximumTransmissionUnit) { Interlocked.Add(ref msg.m_recyclingCount, recipients.Count); foreach (NetConnection conn in recipients) { if (conn == null) { Interlocked.Decrement(ref msg.m_recyclingCount); continue; } NetSendResult res = conn.EnqueueMessage(msg, method, sequenceChannel); if (res == NetSendResult.Dropped) Interlocked.Decrement(ref msg.m_recyclingCount); } } else { // message must be fragmented! SendFragmentedMessage(msg, recipients, method, sequenceChannel); } return; }
/// <summary> /// Send a message to a specific connection /// </summary> /// <param name="msg">The message to send</param> /// <param name="recipient">The recipient connection</param> /// <param name="method">How to deliver the message</param> /// <param name="sequenceChannel">Sequence channel within the delivery method</param> public NetSendResult SendMessage(NetOutgoingMessage msg, NetConnection recipient, NetDeliveryMethod method, int sequenceChannel) { if (msg == null) throw new ArgumentNullException("msg"); if (recipient == null) throw new ArgumentNullException("recipient"); NetException.Assert( ((method != NetDeliveryMethod.Unreliable && method != NetDeliveryMethod.ReliableUnordered) || ((method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered) && sequenceChannel == 0)), "Delivery method " + method + " cannot use sequence channels other than 0!" ); NetException.Assert(method != NetDeliveryMethod.Unknown, "Bad delivery method!"); if (msg.m_isSent) throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently"); int len = msg.LengthBytes; if (len <= m_configuration.MaximumTransmissionUnit) { Interlocked.Increment(ref msg.m_recyclingCount); return recipient.EnqueueMessage(msg, method, sequenceChannel); } else { // message must be fragmented! SendFragmentedMessage(msg, new NetConnection[] { recipient }, method, sequenceChannel); return NetSendResult.Queued; // could be different for each connection; Queued is "most true" } }
public void SendMovementUpdate() { _outmsg = _client.CreateMessage(); _outmsg.Write((byte)PacketType.PlayerMovementUpdate); _outmsg.Write(_pbag.Player.Position); _client.SendMessage(_outmsg, NetDeliveryMethod.ReliableOrdered); }
/// <summary> /// Converts the packet into an outgoing packet /// </summary> /// <returns>Returns the specified IPacket as a packet</returns> public virtual NetOutgoingMessage ToNetBuffer(ref NetOutgoingMessage netOutgoingMessage) { //TODO: Find a way to write the packet header given the HashCode of the class name... netOutgoingMessage.Write(GlobalPacketMap.PacketCache[GetType()]); return null; }
public void SendMessage(NetOutgoingMessage msg) { if (InnerClient.Status == NetPeerStatus.Running) { InnerClient.SendMessage(msg, NetDeliveryMethod.Unreliable); } }
public static void Write(NetOutgoingMessage msg, Quaternion data) { msg.Write(data.x); msg.Write(data.y); msg.Write(data.z); msg.Write(data.w); }
internal void Write(NetOutgoingMessage Message) { ChunkCoords.Write(Message); Vector3i BlockCoords = ChunkCoords * Size; for (int x = 0; x < Size.X; x++) { for (int y = 0; y < Size.Y; y++) { for (int z = 0; z < Size.Z; z++) { Vector3i BlockAt = BlockCoords + new Vector3i(x, y, z); if (!Game.World.MapGenerator.Exists(BlockAt / Sector.Size)) { Game.World.MapGenerator.GenerateSector(BlockAt / Sector.Size); } Block Value = Realm.GetBlock(BlockAt); if (Value != null) { Message.Write(true); Value.Write(Message); } else { Message.Write(false); } } } } }
public override void Write(NetOutgoingMessage msg) { msg.Write(Id); msg.Write(Cards.Count); foreach(string value in Cards) msg.Write(value); }
public override void WriteOutUpdateData(Lidgren.Network.NetOutgoingMessage om) { base.WriteOutUpdateData(om); om.Write(this.elapsedTime); }
public override void SendMessage(NetOutgoingMessage message) { for (int i = 0; i < connections.Count; ++i) { SendMessage(message, connections[i]); } }
public void Write(NetOutgoingMessage packet) { packet.Write(Slot); packet.Write((Byte)Team); packet.Write(Callsign); packet.Write(Tag); }
public void Encode(NetOutgoingMessage om) { om.Write(this.BlockID); om.Write(this.X); om.Write(this.Y); om.Write(this.Z); }
public void Encode(NetOutgoingMessage om) { om.Write((int) Value); om.Write(Text); om.Write(Row); om.Write(Col); }
/// <summary> /// write all the serializing objects to the stream /// </summary> /// <param name="msg"></param> /// <param name="towrite"></param> public static void WriteParams(ref NetOutgoingMessage msg, INetSerializable[] towrite) { foreach (var arg in towrite) { arg.OnSerialize(msg); } }
public static OutgoingMessage CreateOutgoingMessage(int opcode, byte[] data, NetOutgoingMessage packet) { OutgoingMessage com = CreateOutgoingMessage(opcode, data); com.EncodeTo(packet); return com; }
public void WriteType(NetOutgoingMessage Message, AttributeTypeID Type, object Data) { switch (Type) { case AttributeTypeID.Float: Message.Write((float)Data); break; case AttributeTypeID.Int: Message.Write((int)Data); break; case AttributeTypeID.List: Console.WriteLine("Engine unable to serialize list objects"); break; case AttributeTypeID.Long: Message.Write((long)Data); break; case AttributeTypeID.Rectangle: Message.WriteRectangle((Rectangle)Data); break; case AttributeTypeID.String: Message.Write((string)Data); break; case AttributeTypeID.Vector2: Message.WriteVector2((Vector2)Data); break; case AttributeTypeID.Bool: Message.Write((bool)Data); break; default: Console.WriteLine("AttributeSystem Unrecognised Type In AttributeSystem Type: {0}", Type.ToString()); break; } }
public void Encode(NetOutgoingMessage om) { om.Write(this.Id); om.Write(this.MessageTime); om.Write(this.Health); om.Write(this.MaxHealth); }
public void W(NetOutgoingMessage om) { om.Write(Uid); om.Write(X); om.Write(Y); om.Write(SpriteId); }
/// <summary> /// write to the message /// </summary> /// <param name="message">message to write to</param> public void OnSerialize(NetOutgoingMessage message) { message.Write(X); message.Write(Y); message.Write(Z); message.Write(W); }
public void SendPlayerInWorld() { _outmsg = _client.CreateMessage(); _outmsg.Write((byte)PacketType.PlayerInWorld); _outmsg.Write(true); _client.SendMessage(_outmsg, NetDeliveryMethod.ReliableOrdered); }
public void Encode(NetOutgoingMessage om) { om.Write(Shots); om.Write(Hits); om.Write(Misses); om.Write(ShipsKilled); }
public void Encode(NetOutgoingMessage om) { om.Write(this.MessageTime); om.Write(this.Id); om.Write(this.EquipmentPosition); om.Write(this.InventoryPosition); }
/// <summary> /// serialize to the message /// </summary> /// <param name="message"></param> public void OnSerialize(Lidgren.Network.NetOutgoingMessage message) { message.Write(dictionary.Count); foreach (var kvp in dictionary) { message.Write(kvp.Key); message.Write(kvp.Value); } }
/// <summary> /// Serialize the array to the message /// </summary> /// <param name="message"></param> public void OnSerialize(Lidgren.Network.NetOutgoingMessage message) { if (items == null || items.Length == 0) { return; } message.Write(items.Length); foreach (var item in items) { item.OnSerialize(message); } }
/// <summary> /// Approves this connection; sending a connection response to the remote host /// </summary> /// <param name="localHail">The local hail message that will be set as RemoteHailMessage on the remote host</param> public void Approve(NetOutgoingMessage localHail) { m_localHailMessage = localHail; m_handshakeAttempts = 0; SendConnectResponse((float)NetTime.Now, false); }
public void Reset() { NumSent = 0; LastSent = 0.0; Message = null; }
public NetReason(NetOutgoingMessage message) { Message = message ?? throw new ArgumentNullException(nameof(message)); Text = null; }
/// <summary> /// Send a message to this remote connection /// </summary> /// <param name="msg">The message to send</param> /// <param name="method">How to deliver the message</param> /// <param name="sequenceChannel">Sequence channel within the delivery method</param> public NetSendResult SendMessage(NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel) { return(m_peer.SendMessage(msg, this, method, sequenceChannel)); }
/// <summary> /// Create a connection to a remote endpoint /// </summary> public NetConnection Connect(string host, int port, NetOutgoingMessage hailMessage) { return(Connect(new IPEndPoint(NetUtility.Resolve(host), port), hailMessage)); }
/// <summary> /// Create a connection to a remote endpoint /// </summary> public virtual NetConnection Connect(NetEndPoint remoteEndPoint, NetOutgoingMessage hailMessage) { if (remoteEndPoint == null) { throw new ArgumentNullException("remoteEndPoint"); } lock (m_connections) { if (m_status == NetPeerStatus.NotRunning) { throw new NetException("Must call Start() first"); } if (m_connectionLookup.ContainsKey(remoteEndPoint)) { throw new NetException("Already connected to that endpoint!"); } NetConnection hs; if (m_handshakes.TryGetValue(remoteEndPoint, out hs)) { // already trying to connect to that endpoint; make another try switch (hs.m_status) { case NetConnectionStatus.InitiatedConnect: // send another connect hs.m_connectRequested = true; break; case NetConnectionStatus.RespondedConnect: // send another response hs.SendConnectResponse(NetTime.Now, false); break; case NetConnectionStatus.None: case NetConnectionStatus.ReceivedInitiation: case NetConnectionStatus.RespondedAwaitingApproval: case NetConnectionStatus.Connected: case NetConnectionStatus.Disconnecting: case NetConnectionStatus.Disconnected: default: // weird LogWarning("Weird situation; Connect() already in progress to remote endpoint; but hs status is " + hs.m_status); break; } return(hs); } NetConnection conn = new NetConnection(this, remoteEndPoint); conn.m_status = NetConnectionStatus.InitiatedConnect; conn.m_localHailMessage = hailMessage; // handle on network thread conn.m_connectRequested = true; conn.m_connectionInitiator = true; m_handshakes.Add(remoteEndPoint, conn); return(conn); } }
public static void SendMessage(Lidgren.Network.NetOutgoingMessage msg, List <GamePlayer> players, Lidgren.Network.NetDeliveryMethod deliveryMethod = Lidgren.Network.NetDeliveryMethod.ReliableOrdered) { GameServer.UsingPeer.SendMessage(msg, players.Select(p => p.User.GetNetConnection()).ToList(), deliveryMethod, 0); }
private void Heartbeat() { VerifyNetworkThread(); double dnow = NetTime.Now; float now = (float)dnow; double delta = dnow - m_lastHeartbeat; int maxCHBpS = 1250 - m_connections.Count; if (maxCHBpS < 250) { maxCHBpS = 250; } if (delta > (1.0 / (double)maxCHBpS) || delta < 0.0) // max connection heartbeats/second max { m_frameCounter++; m_lastHeartbeat = dnow; // do handshake heartbeats if ((m_frameCounter % 3) == 0) { foreach (var kvp in m_handshakes) { NetConnection conn = kvp.Value as NetConnection; #if DEBUG // sanity check if (kvp.Key != kvp.Key) { LogWarning("Sanity fail! Connection in handshake list under wrong key!"); } #endif conn.UnconnectedHeartbeat(now); if (conn.m_status == NetConnectionStatus.Connected || conn.m_status == NetConnectionStatus.Disconnected) { #if DEBUG // sanity check if (conn.m_status == NetConnectionStatus.Disconnected && m_handshakes.ContainsKey(conn.RemoteEndPoint)) { LogWarning("Sanity fail! Handshakes list contained disconnected connection!"); m_handshakes.Remove(conn.RemoteEndPoint); } #endif break; // collection has been modified } } } #if DEBUG SendDelayedPackets(); #endif // update m_executeFlushSendQueue if (m_configuration.m_autoFlushSendQueue) { m_executeFlushSendQueue = true; } // do connection heartbeats lock (m_connections) { foreach (NetConnection conn in m_connections) { conn.Heartbeat(now, m_frameCounter); if (conn.m_status == NetConnectionStatus.Disconnected) { // // remove connection // m_connections.Remove(conn); m_connectionLookup.Remove(conn.RemoteEndPoint); break; // can't continue iteration here } } } m_executeFlushSendQueue = false; // send unsent unconnected messages NetTuple <IPEndPoint, NetOutgoingMessage> unsent; while (m_unsentUnconnectedMessages.TryDequeue(out unsent)) { NetOutgoingMessage om = unsent.Item2; bool connReset; int len = om.Encode(m_sendBuffer, 0, 0); SendPacket(len, unsent.Item1, 1, out connReset); Interlocked.Decrement(ref om.m_recyclingCount); if (om.m_recyclingCount <= 0) { Recycle(om); } } } // // read from socket // if (m_socket == null) { return; } if (!m_socket.Poll(1000, SelectMode.SelectRead)) // wait up to 1 ms for data to arrive { return; } do { int bytesReceived = 0; try { bytesReceived = m_socket.ReceiveFrom(m_receiveBuffer, 0, m_receiveBuffer.Length, SocketFlags.None, ref m_senderRemote); } catch (SocketException sx) { if (sx.SocketErrorCode == SocketError.ConnectionReset) { // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable" // we should shut down the connection; but m_senderRemote seemingly cannot be trusted, so which connection should we shut down?! // So, what to do? LogWarning("ConnectionReset"); return; } LogWarning(sx.ToString()); return; } if (bytesReceived < NetConstants.HeaderByteSize) { return; } IPEndPoint ipsender = (IPEndPoint)m_senderRemote; if (ipsender.Port == 1900) { // UPnP response try { string resp = System.Text.Encoding.ASCII.GetString(m_receiveBuffer, 0, bytesReceived); if (resp.Contains("upnp:rootdevice")) { resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9); resp = resp.Substring(0, resp.IndexOf("\r")).Trim(); m_upnp.ExtractServiceUrl(resp); return; } } catch { } } NetConnection sender = null; m_connectionLookup.TryGetValue(ipsender, out sender); double receiveTime = NetTime.Now; // // parse packet into messages // int numMessages = 0; int ptr = 0; while ((bytesReceived - ptr) >= NetConstants.HeaderByteSize) { // decode header // 8 bits - NetMessageType // 1 bit - Fragment? // 15 bits - Sequence number // 16 bits - Payload length in bits numMessages++; NetMessageType tp = (NetMessageType)m_receiveBuffer[ptr++]; byte low = m_receiveBuffer[ptr++]; byte high = m_receiveBuffer[ptr++]; bool isFragment = ((low & 1) == 1); ushort sequenceNumber = (ushort)((low >> 1) | (((int)high) << 7)); ushort payloadBitLength = (ushort)(m_receiveBuffer[ptr++] | (m_receiveBuffer[ptr++] << 8)); int payloadByteLength = NetUtility.BytesToHoldBits(payloadBitLength); if (bytesReceived - ptr < payloadByteLength) { LogWarning("Malformed packet; stated payload length " + payloadByteLength + ", remaining bytes " + (bytesReceived - ptr)); return; } try { NetException.Assert(tp <NetMessageType.Unused1 || tp> NetMessageType.Unused29); if (tp >= NetMessageType.LibraryError) { if (sender != null) { sender.ReceivedLibraryMessage(tp, ptr, payloadByteLength); } else { ReceivedUnconnectedLibraryMessage(receiveTime, ipsender, tp, ptr, payloadByteLength); } } else { if (sender == null && !m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.UnconnectedData)) { return; // dropping unconnected message since it's not enabled } NetIncomingMessage msg = CreateIncomingMessage(NetIncomingMessageType.Data, payloadByteLength); msg.m_isFragment = isFragment; msg.m_receiveTime = receiveTime; msg.m_sequenceNumber = sequenceNumber; msg.m_receivedMessageType = tp; msg.m_senderConnection = sender; msg.m_senderEndPoint = ipsender; msg.m_bitLength = payloadBitLength; Buffer.BlockCopy(m_receiveBuffer, ptr, msg.m_data, 0, payloadByteLength); if (sender != null) { if (tp == NetMessageType.Unconnected) { // We're connected; but we can still send unconnected messages to this peer msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData; ReleaseMessage(msg); } else { // connected application (non-library) message sender.ReceivedMessage(msg); } } else { // at this point we know the message type is enabled // unconnected application (non-library) message msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData; ReleaseMessage(msg); } } } catch (Exception ex) { LogError("Packet parsing error: " + ex.Message + " from " + ipsender); } ptr += payloadByteLength; } m_statistics.PacketReceived(bytesReceived, numMessages); if (sender != null) { sender.m_statistics.PacketReceived(bytesReceived, numMessages); } } while (m_socket.Available > 0); }
/// <summary> /// Create a connection to a remote endpoint /// </summary> public NetConnection Connect(string host, int port, NetOutgoingMessage hailMessage) { return(Connect(GetNetEndPoint(host, port), hailMessage)); }
// remoteWindowStart is remote expected sequence number; everything below this has arrived properly // seqNr is the actual nr received internal override void ReceiveAcknowledge(double now, int seqNr) { // late (dupe), on time or early ack? int relate = NetUtility.RelativeSequenceNumber(seqNr, m_windowStart); if (relate < 0) { //m_connection.m_peer.LogDebug("Received late/dupe ack for #" + seqNr); return; // late/duplicate ack } if (relate == 0) { //m_connection.m_peer.LogDebug("Received right-on-time ack for #" + seqNr); // ack arrived right on time NetException.Assert(seqNr == m_windowStart); bool resetTimeout; m_receivedAcks[m_windowStart] = false; DestoreMessage(now, m_windowStart % m_windowSize, out resetTimeout); m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers; // advance window if we already have early acks while (m_receivedAcks.Get(m_windowStart)) { //m_connection.m_peer.LogDebug("Using early ack for #" + m_windowStart + "..."); m_receivedAcks[m_windowStart] = false; bool rt; DestoreMessage(now, m_windowStart % m_windowSize, out rt); resetTimeout |= rt; NetException.Assert(m_storedMessages[m_windowStart % m_windowSize].Message == null); // should already be destored m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers; //m_connection.m_peer.LogDebug("Advancing window to #" + m_windowStart); } if (resetTimeout) { m_connection.ResetTimeout(now); } return; } // // early ack... (if it has been sent!) // // If it has been sent either the m_windowStart message was lost // ... or the ack for that message was lost // //m_connection.m_peer.LogDebug("Received early ack for #" + seqNr); int sendRelate = NetUtility.RelativeSequenceNumber(seqNr, m_sendStart); if (sendRelate <= 0) { // yes, we've sent this message - it's an early (but valid) ack if (m_receivedAcks[seqNr]) { // we've already destored/been acked for this message } else { m_receivedAcks[seqNr] = true; } } else if (sendRelate > 0) { // uh... we haven't sent this message yet? Weird, dupe or error... NetException.Assert(false, "Got ack for message not yet sent?"); return; } // Ok, lets resend all missing acks int rnr = seqNr; do { rnr--; if (rnr < 0) { rnr = NetConstants.NumSequenceNumbers - 1; } if (m_receivedAcks[rnr]) { // m_connection.m_peer.LogDebug("Not resending #" + rnr + " (since we got ack)"); } else { int slot = rnr % m_windowSize; NetException.Assert(m_storedMessages[slot].Message != null); if (m_storedMessages[slot].NumSent == 1) { // just sent once; resend immediately since we found gap in ack sequence NetOutgoingMessage rmsg = m_storedMessages[slot].Message; //m_connection.m_peer.LogVerbose("Resending #" + rnr + " (" + rmsg + ")"); if (now - m_storedMessages[slot].LastSent < (m_resendDelay * 0.35)) { // already resent recently } else { m_storedMessages[slot].LastSent = now; m_storedMessages[slot].NumSent++; m_connection.m_statistics.MessageResent(MessageResendReason.HoleInSequence); Interlocked.Increment(ref rmsg.m_recyclingCount); // increment this since it's being decremented in QueueSendMessage m_connection.QueueSendMessage(rmsg, rnr); } } } } while (rnr != m_windowStart); }
private void ReceivedUnconnectedLibraryMessage(double now, IPEndPoint senderEndPoint, NetMessageType tp, int ptr, int payloadByteLength) { NetConnection shake; if (m_handshakes.TryGetValue(senderEndPoint, out shake)) { shake.ReceivedHandshake(now, tp, ptr, payloadByteLength); return; } // // Library message from a completely unknown sender; lets just accept Connect // switch (tp) { case NetMessageType.Discovery: HandleIncomingDiscoveryRequest(now, senderEndPoint, ptr, payloadByteLength); return; case NetMessageType.DiscoveryResponse: HandleIncomingDiscoveryResponse(now, senderEndPoint, ptr, payloadByteLength); return; case NetMessageType.NatIntroduction: HandleNatIntroduction(ptr); return; case NetMessageType.NatPunchMessage: HandleNatPunch(ptr, senderEndPoint); return; case NetMessageType.ConnectResponse: lock (m_handshakes) { foreach (var hs in m_handshakes) { if (hs.Key.Address.Equals(senderEndPoint.Address)) { if (hs.Value.m_connectionInitiator) { // // We are currently trying to connection to XX.XX.XX.XX:Y // ... but we just received a ConnectResponse from XX.XX.XX.XX:Z // Lets just assume the router decided to use this port instead // var hsconn = hs.Value; m_connectionLookup.Remove(hs.Key); m_handshakes.Remove(hs.Key); LogDebug("Detected host port change; rerouting connection to " + senderEndPoint); hsconn.MutateEndPoint(senderEndPoint); m_connectionLookup.Add(senderEndPoint, hsconn); m_handshakes.Add(senderEndPoint, hsconn); hsconn.ReceivedHandshake(now, tp, ptr, payloadByteLength); return; } } } } LogWarning("Received unhandled library message " + tp + " from " + senderEndPoint); return; case NetMessageType.Connect: // proceed break; case NetMessageType.Disconnect: // this is probably ok LogVerbose("Received Disconnect from unconnected source: " + senderEndPoint); return; default: LogWarning("Received unhandled library message " + tp + " from " + senderEndPoint); return; } // It's someone wanting to shake hands with us! int reservedSlots = m_handshakes.Count + m_connections.Count; if (reservedSlots >= m_configuration.m_maximumConnections) { // server full NetOutgoingMessage full = CreateMessage("Server full"); full.m_messageType = NetMessageType.Disconnect; SendLibrary(full, senderEndPoint); return; } // Ok, start handshake! NetConnection conn = new NetConnection(this, senderEndPoint); conn.m_status = NetConnectionStatus.ReceivedInitiation; m_handshakes.Add(senderEndPoint, conn); conn.ReceivedHandshake(now, tp, ptr, payloadByteLength); return; }
// call this regularely internal override void SendQueuedMessages(double now) { // // resends // m_anyStoredResends = false; for (int i = 0; i < m_storedMessages.Length; i++) { var storedMsg = m_storedMessages[i]; NetOutgoingMessage om = storedMsg.Message; if (om == null) { continue; } m_anyStoredResends = true; double t = storedMsg.LastSent; if (t > 0 && (now - t) > m_resendDelay) { // deduce sequence number /* * int startSlot = m_windowStart % m_windowSize; * int seqNr = m_windowStart; * while (startSlot != i) * { * startSlot--; * if (startSlot < 0) * startSlot = m_windowSize - 1; * seqNr--; * } */ //m_connection.m_peer.LogVerbose("Resending due to delay #" + m_storedMessages[i].SequenceNumber + " " + om.ToString()); m_connection.m_statistics.MessageResent(MessageResendReason.Delay); Interlocked.Increment(ref om.m_recyclingCount); // increment this since it's being decremented in QueueSendMessage m_connection.QueueSendMessage(om, storedMsg.SequenceNumber); m_storedMessages[i].LastSent = now; m_storedMessages[i].NumSent++; } } int num = GetAllowedSends(); if (num < 1) { return; } // queued sends while (num > 0 && m_queuedSends.Count > 0) { NetOutgoingMessage om; if (m_queuedSends.TryDequeue(out om)) { ExecuteSend(now, om); } num--; NetException.Assert(num == GetAllowedSends()); } }
// on user thread private NetSendResult SendFragmentedMessage(NetOutgoingMessage msg, IList <NetConnection> recipients, NetDeliveryMethod method, int sequenceChannel) { // Note: this group id is PER SENDING/NetPeer; ie. same id is sent to all recipients; // this should be ok however; as long as recipients differentiate between same id but different sender int group = Interlocked.Increment(ref m_lastUsedFragmentGroup); if (group >= NetConstants.MaxFragmentationGroups) { // @TODO: not thread safe; but in practice probably not an issue m_lastUsedFragmentGroup = 1; group = 1; } msg.m_fragmentGroup = group; // do not send msg; but set fragmentgroup in case user tries to recycle it immediately // create fragmentation specifics int totalBytes = msg.LengthBytes; // determine minimum mtu for all recipients int mtu = GetMTU(recipients); int bytesPerChunk = NetFragmentationHelper.GetBestChunkSize(group, totalBytes, mtu); int numChunks = totalBytes / bytesPerChunk; if (numChunks * bytesPerChunk < totalBytes) { numChunks++; } NetSendResult retval = NetSendResult.Sent; int bitsPerChunk = bytesPerChunk * 8; int bitsLeft = msg.LengthBits; for (int i = 0; i < numChunks; i++) { NetOutgoingMessage chunk = CreateMessage(0); chunk.m_bitLength = (bitsLeft > bitsPerChunk ? bitsPerChunk : bitsLeft); chunk.m_buf = msg.m_buf; chunk.m_fragmentGroup = group; chunk.m_fragmentGroupTotalBits = totalBytes * 8; chunk.m_fragmentChunkByteSize = bytesPerChunk; chunk.m_fragmentChunkNumber = i; NetException.Assert(chunk.m_bitLength != 0); NetException.Assert(chunk.GetEncodedSize() < mtu); Interlocked.Add(ref chunk.m_recyclingCount, recipients.Count); foreach (NetConnection recipient in recipients) { var res = recipient.EnqueueMessage(chunk, method, sequenceChannel); if (res == NetSendResult.Dropped) { Interlocked.Decrement(ref chunk.m_recyclingCount); } if ((int)res > (int)retval) { retval = res; // return "worst" result } } bitsLeft -= bitsPerChunk; } return(retval); }
/// <summary> /// Send a message to all connections /// </summary> /// <param name="msg">The message to send</param> /// <param name="method">How to deliver the message</param> public void SendToAll(NetOutgoingMessage msg, NetDeliveryMethod method) { SendMessage(msg, this.Connections, method, 0); }
/// <summary> /// Encrypt an outgoing message in place /// </summary> public abstract bool Encrypt(NetOutgoingMessage msg);
private void Heartbeat() { VerifyNetworkThread(); double now = NetTime.Now; double delta = now - m_lastHeartbeat; int maxCHBpS = 1250 - m_connections.Count; if (maxCHBpS < 250) { maxCHBpS = 250; } if (delta > (1.0 / (double)maxCHBpS) || delta < 0.0) // max connection heartbeats/second max { m_frameCounter++; m_lastHeartbeat = now; // do handshake heartbeats if ((m_frameCounter % 3) == 0) { foreach (var kvp in m_handshakes) { NetConnection conn = kvp.Value as NetConnection; #if DEBUG // sanity check if (kvp.Key != kvp.Key) { LogWarning("Sanity fail! Connection in handshake list under wrong key!"); } #endif conn.UnconnectedHeartbeat(now); if (conn.m_status == NetConnectionStatus.Connected || conn.m_status == NetConnectionStatus.Disconnected) { #if DEBUG // sanity check if (conn.m_status == NetConnectionStatus.Disconnected && m_handshakes.ContainsKey(conn.RemoteEndPoint)) { LogWarning("Sanity fail! Handshakes list contained disconnected connection!"); m_handshakes.Remove(conn.RemoteEndPoint); } #endif break; // collection has been modified } } } #if DEBUG SendDelayedPackets(); #endif // update m_executeFlushSendQueue if (m_configuration.m_autoFlushSendQueue && m_needFlushSendQueue == true) { m_executeFlushSendQueue = true; m_needFlushSendQueue = false; // a race condition to this variable will simply result in a single superfluous call to FlushSendQueue() } // do connection heartbeats lock (m_connections) { for (int i = m_connections.Count - 1; i >= 0; i--) { var conn = m_connections[i]; conn.Heartbeat(now, m_frameCounter); if (conn.m_status == NetConnectionStatus.Disconnected) { // // remove connection // m_connections.RemoveAt(i); m_connectionLookup.Remove(conn.RemoteEndPoint); } } } m_executeFlushSendQueue = false; // send unsent unconnected messages NetTuple <NetEndPoint, NetOutgoingMessage> unsent; while (m_unsentUnconnectedMessages.TryDequeue(out unsent)) { NetOutgoingMessage om = unsent.Item2; int len = om.Encode(m_sendBuffer, 0, 0); Interlocked.Decrement(ref om.m_recyclingCount); if (om.m_recyclingCount <= 0) { Recycle(om); } bool connReset; SendPacket(len, unsent.Item1, 1, out connReset); } } if (m_upnp != null) { m_upnp.CheckForDiscoveryTimeout(); } // // read from socket // if (m_socket == null) { return; } if (!m_socket.Poll(1000, SelectMode.SelectRead)) // wait up to 1 ms for data to arrive { return; } //if (m_socket == null || m_socket.Available < 1) // return; // update now now = NetTime.Now; do { int bytesReceived = 0; try { bytesReceived = m_socket.ReceiveFrom(m_receiveBuffer, 0, m_receiveBuffer.Length, SocketFlags.None, ref m_senderRemote); } catch (SocketException sx) { switch (sx.SocketErrorCode) { case SocketError.ConnectionReset: // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable" // we should shut down the connection; but m_senderRemote seemingly cannot be trusted, so which connection should we shut down?! // So, what to do? LogWarning("ConnectionReset"); return; case SocketError.NotConnected: // socket is unbound; try to rebind it (happens on mobile when process goes to sleep) BindSocket(true); return; default: LogWarning("Socket exception: " + sx.ToString()); return; } } if (bytesReceived < NetConstants.HeaderByteSize) { return; } //LogVerbose("Received " + bytesReceived + " bytes"); var ipsender = (NetEndPoint)m_senderRemote; if (m_upnp != null && now < m_upnp.m_discoveryResponseDeadline && bytesReceived > 32) { // is this an UPnP response? string resp = System.Text.Encoding.UTF8.GetString(m_receiveBuffer, 0, bytesReceived); if (resp.Contains("upnp:rootdevice") || resp.Contains("UPnP/1.0")) { try { resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9); resp = resp.Substring(0, resp.IndexOf("\r")).Trim(); m_upnp.ExtractServiceUrl(resp); return; } catch (Exception ex) { LogDebug("Failed to parse UPnP response: " + ex.ToString()); // don't try to parse this packet further return; } } } NetConnection sender = null; m_connectionLookup.TryGetValue(ipsender, out sender); // // parse packet into messages // int numMessages = 0; int numFragments = 0; int ptr = 0; while ((bytesReceived - ptr) >= NetConstants.HeaderByteSize) { // decode header // 8 bits - NetMessageType // 1 bit - Fragment? // 15 bits - Sequence number // 16 bits - Payload length in bits numMessages++; NetMessageType tp = (NetMessageType)m_receiveBuffer[ptr++]; byte low = m_receiveBuffer[ptr++]; byte high = m_receiveBuffer[ptr++]; bool isFragment = ((low & 1) == 1); ushort sequenceNumber = (ushort)((low >> 1) | (((int)high) << 7)); if (isFragment) { numFragments++; } ushort payloadBitLength = (ushort)(m_receiveBuffer[ptr++] | (m_receiveBuffer[ptr++] << 8)); int payloadByteLength = NetUtility.BytesToHoldBits(payloadBitLength); if (bytesReceived - ptr < payloadByteLength) { LogWarning("Malformed packet; stated payload length " + payloadByteLength + ", remaining bytes " + (bytesReceived - ptr)); return; } if (tp >= NetMessageType.Unused1 && tp <= NetMessageType.Unused29) { ThrowOrLog("Unexpected NetMessageType: " + tp); return; } try { if (tp >= NetMessageType.LibraryError) { if (sender != null) { sender.ReceivedLibraryMessage(tp, ptr, payloadByteLength); } else { ReceivedUnconnectedLibraryMessage(now, ipsender, tp, ptr, payloadByteLength); } } else { if (sender == null && !m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.UnconnectedData)) { return; // dropping unconnected message since it's not enabled } NetIncomingMessage msg = CreateIncomingMessage(NetIncomingMessageType.Data, payloadByteLength); msg.m_isFragment = isFragment; msg.m_receiveTime = now; msg.m_sequenceNumber = sequenceNumber; msg.m_receivedMessageType = tp; msg.m_senderConnection = sender; msg.m_senderEndPoint = ipsender; msg.m_bitLength = payloadBitLength; Buffer.BlockCopy(m_receiveBuffer, ptr, msg.m_data, 0, payloadByteLength); if (sender != null) { if (tp == NetMessageType.Unconnected) { // We're connected; but we can still send unconnected messages to this peer msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData; ReleaseMessage(msg); } else { // connected application (non-library) message sender.ReceivedMessage(msg); } } else { // at this point we know the message type is enabled // unconnected application (non-library) message msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData; ReleaseMessage(msg); } } } catch (Exception ex) { LogError("Packet parsing error: " + ex.Message + " from " + ipsender); } ptr += payloadByteLength; } m_statistics.PacketReceived(bytesReceived, numMessages, numFragments); if (sender != null) { sender.m_statistics.PacketReceived(bytesReceived, numMessages, numFragments); } } while (m_socket.Available > 0); }
/// <summary> /// Отправить сообщение для списка соединений. /// </summary> /// <param name="msg">Сообщение для отправки.</param> /// <param name="recipients">Список получателей для отправки.</param> /// <param name="method">Как доставить сообщение.</param> /// <param name="sequenceChannel">Последовательность каналов внутри метода доставки.</param> public void SendMessage(NetOutgoingMessage msg, IList <NetConnection> recipients, NetDeliveryMethod method, int sequenceChannel) { if (msg == null) { throw new ArgumentNullException("msg"); } if (recipients == null) { if (msg.m_isSent == false) { Recycle(msg); } throw new ArgumentNullException("recipients"); } if (recipients.Count < 1) { if (msg.m_isSent == false) { Recycle(msg); } throw new NetException("recipients must contain at least one item"); } if (method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered) { NetException.Assert(sequenceChannel == 0, "Delivery method " + method + " cannot use sequence channels other than 0!"); } if (msg.m_isSent) { throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently"); } msg.m_isSent = true; int mtu = GetMTU(recipients); int len = msg.GetEncodedSize(); if (len <= mtu) { Interlocked.Add(ref msg.m_recyclingCount, recipients.Count); foreach (NetConnection conn in recipients) { if (conn == null) { Interlocked.Decrement(ref msg.m_recyclingCount); continue; } NetSendResult res = conn.EnqueueMessage(msg, method, sequenceChannel); if (res == NetSendResult.Dropped) { Interlocked.Decrement(ref msg.m_recyclingCount); } } } else { // message must be fragmented! SendFragmentedMessage(msg, recipients, method, sequenceChannel); } return; }
/// <summary> /// Send a message to a specific connection /// </summary> /// <param name="msg">The message to send</param> /// <param name="recipient">The recipient connection</param> /// <param name="method">How to deliver the message</param> public NetSendResult SendMessage(NetOutgoingMessage msg, NetConnection recipient, NetDeliveryMethod method) { return(SendMessage(msg, recipient, method, 0)); }
internal abstract NetSendResult Enqueue(NetOutgoingMessage message);
public static void SendMessageToAll(Lidgren.Network.NetOutgoingMessage msg, Lidgren.Network.NetDeliveryMethod deliveryMethod = Lidgren.Network.NetDeliveryMethod.ReliableOrdered) { GameServer.UsingPeer.SendMessage(msg, GameServer.GetUserConnections(), deliveryMethod, 0); }
static void Main(string[] args) { var config = new NetPeerConfiguration("ConquerLeague") { Port = 47410 }; config.EnableMessageType(NetIncomingMessageType.DiscoveryRequest); server = new NetServer(config); server.Start(); SessionManager sessionManager = new SessionManager(); while (true) { NetIncomingMessage message; while ((message = server.ReadMessage()) != null) { switch (message.MessageType) { case NetIncomingMessageType.DiscoveryRequest: NetOutgoingMessage response = server.CreateMessage(); // Create a response and write some example data to it response.Write("ConquerLeagueServer"); server.SendDiscoveryResponse(response, message.SenderEndPoint); // Send the response to the sender of the request break; case NetIncomingMessageType.Data: var dataLength = message.ReadInt32(); var data = message.ReadBytes(dataLength); sessionManager.ForwardMessageToSession(message.SenderConnection, dataLength, data); break; case NetIncomingMessageType.StatusChanged: Console.WriteLine(message.SenderConnection.Status); switch (message.SenderConnection.Status) { case NetConnectionStatus.Connected: Console.WriteLine("Client " + message.SenderConnection.RemoteEndPoint.ToString() + " connected!"); sessionManager.AddPlayerToMatchmaking(message.SenderConnection); break; case NetConnectionStatus.RespondedConnect: Console.WriteLine(message.SenderConnection.Status.ToString()); break; default: Console.WriteLine("Unhandled status change with type: " + message.SenderConnection.Status.ToString()); break; } break; case NetIncomingMessageType.ConnectionApproval: message.SenderConnection.Approve(); break; case NetIncomingMessageType.DebugMessage: Console.WriteLine(message.ReadString()); break; case NetIncomingMessageType.WarningMessage: Console.WriteLine("Warning: " + message.ReadString()); break; default: Console.WriteLine("unhandled message with type: " + message.MessageType); break; } server.Recycle(message); } } }
private void ReceivedUnconnectedLibraryMessage(double now, NetEndPoint senderEndPoint, long connectionId, NetMessageType tp, int ptr, int payloadByteLength) { NetConnection shake; if (m_handshakes.TryGetValue(connectionId, out shake)) { shake.ReceivedHandshake(now, tp, ptr, payloadByteLength); return; } // // Library message from a completely unknown sender; lets just accept Connect // switch (tp) { case NetMessageType.Discovery: HandleIncomingDiscoveryRequest(now, senderEndPoint, ptr, payloadByteLength); return; case NetMessageType.DiscoveryResponse: HandleIncomingDiscoveryResponse(now, senderEndPoint, ptr, payloadByteLength); return; case NetMessageType.NatIntroduction: if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.NatIntroductionSuccess)) { HandleNatIntroduction(ptr); } return; case NetMessageType.NatPunchMessage: if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.NatIntroductionSuccess)) { HandleNatPunch(ptr, senderEndPoint); } return; case NetMessageType.NatIntroductionConfirmRequest: if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.NatIntroductionSuccess)) { HandleNatPunchConfirmRequest(ptr, senderEndPoint); } return; case NetMessageType.NatIntroductionConfirmed: if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.NatIntroductionSuccess)) { HandleNatPunchConfirmed(ptr, senderEndPoint); } return; case NetMessageType.ConnectResponse: LogWarning("Received unhandled library message " + tp + " from " + senderEndPoint); return; case NetMessageType.Connect: if (m_configuration.AcceptIncomingConnections == false) { LogWarning("Received Connect, but we're not accepting incoming connections!"); return; } // handle connect // It's someone wanting to shake hands with us! int reservedSlots = m_handshakes.Count + m_connections.Count; if (reservedSlots >= m_configuration.m_maximumConnections) { // server full NetOutgoingMessage full = CreateMessage("Server full"); full.m_messageType = NetMessageType.Disconnect; SendLibrary(connectionId, full, senderEndPoint); return; } if (connectionId == 0 || m_handshakes.ContainsKey(connectionId) || m_connectionLookup.ContainsKey(connectionId)) { // duplicate connection id NetOutgoingMessage full = CreateMessage("Duplicate connection id"); full.m_messageType = NetMessageType.Disconnect; SendLibrary(connectionId, full, senderEndPoint); return; } // Ok, start handshake! NetConnection conn = new NetConnection(this, senderEndPoint, connectionId); conn.m_status = NetConnectionStatus.ReceivedInitiation; m_handshakes.Add(connectionId, conn); conn.ReceivedHandshake(now, tp, ptr, payloadByteLength); return; case NetMessageType.Disconnect: // this is probably ok LogVerbose("Received Disconnect from unconnected source: " + senderEndPoint); return; default: LogWarning("Received unhandled library message " + tp + " from " + senderEndPoint); return; } }
/// <summary> /// Create a connection to a remote endpoint. /// </summary> public NetConnection Connect(ReadOnlySpan <char> host, int port, NetOutgoingMessage hailMessage) { return(Connect(new IPEndPoint(NetUtility.Resolve(host), port), hailMessage)); }
private void Heartbeat() { VerifyNetworkThread(); double now = NetTime.Now; double delta = now - m_lastHeartbeat; int maxCHBpS = 1250 - m_connections.Count; if (maxCHBpS < 250) { maxCHBpS = 250; } if (delta > (1.0 / (double)maxCHBpS) || delta < 0.0) // max connection heartbeats/second max { m_frameCounter++; m_lastHeartbeat = now; // do handshake heartbeats if ((m_frameCounter % 3) == 0) { foreach (var kvp in m_handshakes) { NetConnection conn = kvp.Value as NetConnection; #if DEBUG // sanity check if (kvp.Key != kvp.Key) { LogWarning("Sanity fail! Connection in handshake list under wrong key!"); } #endif conn.UnconnectedHeartbeat(now); if (conn.m_status == NetConnectionStatus.Connected || conn.m_status == NetConnectionStatus.Disconnected) { #if DEBUG // sanity check if (conn.m_status == NetConnectionStatus.Disconnected && m_handshakes.ContainsKey(conn.RemoteEndPoint)) { LogWarning("Sanity fail! Handshakes list contained disconnected connection!"); m_handshakes.Remove(conn.RemoteEndPoint); } #endif break; // collection has been modified } } } #if DEBUG SendDelayedPackets(); #endif // update m_executeFlushSendQueue if (m_configuration.m_autoFlushSendQueue && m_needFlushSendQueue == true) { m_executeFlushSendQueue = true; m_needFlushSendQueue = false; // a race condition to this variable will simply result in a single superfluous call to FlushSendQueue() } // do connection heartbeats lock (m_connections) { for (int i = m_connections.Count - 1; i >= 0; i--) { var conn = m_connections[i]; conn.Heartbeat(now, m_frameCounter); if (conn.m_status == NetConnectionStatus.Disconnected) { // // remove connection // m_connections.RemoveAt(i); m_connectionLookup.Remove(conn.RemoteEndPoint); } } } m_executeFlushSendQueue = false; // send unsent unconnected messages NetTuple <NetEndPoint, NetOutgoingMessage> unsent; while (m_unsentUnconnectedMessages.TryDequeue(out unsent)) { NetOutgoingMessage om = unsent.Item2; int len = om.Encode(m_sendBuffer, 0, 0); Interlocked.Decrement(ref om.m_recyclingCount); if (om.m_recyclingCount <= 0) { Recycle(om); } bool connReset; SendPacket(len, unsent.Item1, 1, out connReset); } } if (m_upnp != null) { m_upnp.CheckForDiscoveryTimeout(); } // // read from socket // if (m_socket == null) { return; } if (!m_socket.Poll(1000, SelectMode.SelectRead)) // wait up to 1 ms for data to arrive { return; } //if (m_socket == null || m_socket.Available < 1) // return; // update now now = NetTime.Now; try { do { ReceiveSocketData(now); } while (m_socket.Available > 0); } catch (SocketException sx) { switch (sx.SocketErrorCode) { case SocketError.ConnectionReset: // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable" // we should shut down the connection; but m_senderRemote seemingly cannot be trusted, so which connection should we shut down?! // So, what to do? LogWarning("ConnectionReset"); return; case SocketError.NotConnected: // socket is unbound; try to rebind it (happens on mobile when process goes to sleep) BindSocket(true); return; default: LogWarning("Socket exception: " + sx.ToString()); return; } } }