/// <summary> /// Creates an incoming message with the required capacity for releasing to the application /// </summary> internal NetIncomingMessage CreateIncomingMessage(NetIncomingMessageType tp, int requiredCapacity) { NetIncomingMessage retval; if (m_incomingMessagesPool.TryDequeue(out retval)) { retval.Reset(); } else { retval = new NetIncomingMessage(); } NetException.Assert(retval.m_status == NetIncomingMessageReleaseStatus.NotReleased); retval.m_incomingType = tp; retval.m_senderConnection = null; retval.m_senderEndpoint = null; retval.m_status = NetIncomingMessageReleaseStatus.NotReleased; if (requiredCapacity > 0) { byte[] storage = GetStorage(requiredCapacity); retval.m_data = storage; } else { retval.m_data = null; } return(retval); }
internal NetIncomingMessage CreateIncomingMessage(NetIncomingMessageType tp, byte[] useStorageData) { NetIncomingMessage retval; if (m_incomingMessagesPool == null || !m_incomingMessagesPool.TryDequeue(out retval)) { retval = new NetIncomingMessage(tp); } else { retval.m_incomingMessageType = tp; } retval.m_data = useStorageData; return(retval); }
internal NetIncomingMessage CreateIncomingMessage(NetIncomingMessageType tp, ArraySegment <byte> useStorageData) { NetIncomingMessage retval; if (m_incomingMessagesPool == null || !m_incomingMessagesPool.TryDequeue(out retval)) { retval = new NetIncomingMessage(tp); } else { retval.m_incomingMessageType = tp; } retval.m_buf = useStorageData.Array; return(retval); }
/// <summary> /// Creates a new message for sending /// </summary> /// <param name="initialCapacity">initial capacity in bytes</param> public NetOutgoingMessage CreateMessage(int initialCapacity) { NetOutgoingMessage retval; if (m_outgoingMessagesPool == null || !m_outgoingMessagesPool.TryDequeue(out retval)) { retval = new NetOutgoingMessage(); } byte[] storage = GetStorage(initialCapacity); retval.m_data = storage; return(retval); }
/// <summary> /// Creates a new message for sending /// </summary> /// <param name="initialCapacity">initial capacity in bytes</param> public NetOutgoingMessage CreateMessage(int initialCapacity) { NetOutgoingMessage retval; if (m_outgoingMessagesPool == null || !m_outgoingMessagesPool.TryDequeue(out retval)) { retval = new NetOutgoingMessage(); } NetException.Assert(retval.m_recyclingCount == 0, "Wrong recycling count! Should be zero" + retval.m_recyclingCount); if (initialCapacity > 0) { retval.m_data = GetStorage(initialCapacity); } return(retval); }
private void ProcessConnectionUpdates(double now) { // 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); } }
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)) // 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; } //if (m_socket == null || m_socket.Available < 1) // 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; } //LogVerbose("Received " + bytesReceived + " bytes"); 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); }
internal void Heartbeat(float now, uint frameCounter) { m_peer.VerifyNetworkThread(); NetException.Assert(m_status != NetConnectionStatus.InitiatedConnect && m_status != NetConnectionStatus.RespondedConnect); if ((frameCounter % m_infrequentEventsSkipFrames) == 0) { if (now > m_timeoutDeadline) { // // connection timed out // m_peer.LogVerbose("Connection timed out at " + now + " deadline was " + m_timeoutDeadline); ExecuteDisconnect("Connection timed out", true); return; } // send ping? if (m_status == NetConnectionStatus.Connected) { if (now > m_sentPingTime + m_peer.m_configuration.m_pingInterval) { SendPing(); } // handle expand mtu MTUExpansionHeartbeat(now); } if (m_disconnectRequested) { ExecuteDisconnect(m_disconnectMessage, m_disconnectReqSendBye); return; } } bool connectionReset; // TODO: handle connection reset // // Note: at this point m_sendBufferWritePtr and m_sendBufferNumMessages may be non-null; resends may already be queued up // byte[] sendBuffer = m_peer.m_sendBuffer; int mtu = m_currentMTU; if ((frameCounter % m_messageCoalesceFrames) == 0) // coalesce a few frames { // // send ack messages // while (m_queuedOutgoingAcks.Count > 0) { int acks = (mtu - (m_sendBufferWritePtr + 5)) / 3; // 3 bytes per actual ack if (acks > m_queuedOutgoingAcks.Count) { acks = m_queuedOutgoingAcks.Count; } NetException.Assert(acks > 0); m_sendBufferNumMessages++; // write acks header sendBuffer[m_sendBufferWritePtr++] = (byte)NetMessageType.Acknowledge; sendBuffer[m_sendBufferWritePtr++] = 0; // no sequence number sendBuffer[m_sendBufferWritePtr++] = 0; // no sequence number int len = (acks * 3) * 8; // bits sendBuffer[m_sendBufferWritePtr++] = (byte)len; sendBuffer[m_sendBufferWritePtr++] = (byte)(len >> 8); // write acks for (int i = 0; i < acks; i++) { NetTuple <NetMessageType, int> tuple; m_queuedOutgoingAcks.TryDequeue(out tuple); //m_peer.LogVerbose("Sending ack for " + tuple.Item1 + "#" + tuple.Item2); sendBuffer[m_sendBufferWritePtr++] = (byte)tuple.Item1; sendBuffer[m_sendBufferWritePtr++] = (byte)tuple.Item2; sendBuffer[m_sendBufferWritePtr++] = (byte)(tuple.Item2 >> 8); } if (m_queuedOutgoingAcks.Count > 0) { // send packet and go for another round of acks NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0); m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndPoint, m_sendBufferNumMessages, out connectionReset); m_statistics.PacketSent(m_sendBufferWritePtr, 1); m_sendBufferWritePtr = 0; m_sendBufferNumMessages = 0; } } // // Parse incoming acks (may trigger resends) // NetTuple <NetMessageType, int> incAck; while (m_queuedIncomingAcks.TryDequeue(out incAck)) { //m_peer.LogVerbose("Received ack for " + acktp + "#" + seqNr); NetSenderChannelBase chan = m_sendChannels[(int)incAck.Item1 - 1]; // If we haven't sent a message on this channel there is no reason to ack it if (chan == null) { continue; } chan.ReceiveAcknowledge(now, incAck.Item2); } } // // send queued messages // if (m_peer.m_executeFlushSendQueue) { for (int i = m_sendChannels.Length - 1; i >= 0; i--) // Reverse order so reliable messages are sent first { var channel = m_sendChannels[i]; NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0); if (channel != null) { channel.SendQueuedMessages(now); } NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0); } } // // Put on wire data has been written to send buffer but not yet sent // if (m_sendBufferWritePtr > 0) { m_peer.VerifyNetworkThread(); NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0); m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndPoint, m_sendBufferNumMessages, out connectionReset); m_statistics.PacketSent(m_sendBufferWritePtr, m_sendBufferNumMessages); m_sendBufferWritePtr = 0; m_sendBufferNumMessages = 0; } }
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; } } }
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); //UnityEngine.Debug.Log($"recv from {m_senderRemote}, bytes {bytesReceived}, local {m_socket.LocalEndPoint}"); } 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); }
internal void Heartbeat(float now, uint frameCounter) { m_peer.VerifyNetworkThread(); NetException.Assert(m_status != NetConnectionStatus.InitiatedConnect && m_status != NetConnectionStatus.RespondedConnect); if ((frameCounter % 5) == 0) { if (now > m_timeoutDeadline) { // // connection timed out // m_peer.LogVerbose("Connection timed out at " + now + " deadline was " + m_timeoutDeadline); ExecuteDisconnect("Connection timed out", true); } // send ping? if (m_status == NetConnectionStatus.Connected) { if (now > m_sentPingTime + m_peer.m_configuration.m_pingInterval) { SendPing(); } } if (m_disconnectRequested) { ExecuteDisconnect(m_disconnectMessage, true); return; } } bool connectionReset; // TODO: handle connection reset // // Note: at this point m_sendBufferWritePtr and m_sendBufferNumMessages may be non-null; resends may already be queued up // byte[] sendBuffer = m_peer.m_sendBuffer; int mtu = m_peerConfiguration.m_maximumTransmissionUnit; if ((frameCounter % 3) == 0) // coalesce a few frames { // // send ack messages // while (m_queuedAcks.Count > 0) { int acks = (mtu - (m_sendBufferWritePtr + 5)) / 3; // 3 bytes per actual ack if (acks > m_queuedAcks.Count) { acks = m_queuedAcks.Count; } NetException.Assert(acks > 0); m_sendBufferNumMessages++; // write acks header sendBuffer[m_sendBufferWritePtr++] = (byte)NetMessageType.Acknowledge; sendBuffer[m_sendBufferWritePtr++] = 0; // no sequence number sendBuffer[m_sendBufferWritePtr++] = 0; // no sequence number int len = (acks * 3) * 8; // bits sendBuffer[m_sendBufferWritePtr++] = (byte)len; sendBuffer[m_sendBufferWritePtr++] = (byte)(len >> 8); // write acks for (int i = 0; i < acks; i++) { NetTuple <NetMessageType, int> tuple; m_queuedAcks.TryDequeue(out tuple); //m_peer.LogVerbose("Sending ack for " + tuple.Item1 + "#" + tuple.Item2); sendBuffer[m_sendBufferWritePtr++] = (byte)tuple.Item1; sendBuffer[m_sendBufferWritePtr++] = (byte)tuple.Item2; sendBuffer[m_sendBufferWritePtr++] = (byte)(tuple.Item2 >> 8); } if (m_queuedAcks.Count > 0) { // send packet and go for another round of acks NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0); m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndpoint, m_sendBufferNumMessages, out connectionReset); m_statistics.PacketSent(m_sendBufferWritePtr, 1); m_sendBufferWritePtr = 0; m_sendBufferNumMessages = 0; } } } // // send queued messages // for (int i = m_sendChannels.Length - 1; i >= 0; i--) // Reverse order so reliable messages are sent first { var channel = m_sendChannels[i]; NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0); if (channel != null) { channel.SendQueuedMessages(now); } NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0); } // // Put on wire data has been written to send buffer but not yet sent // if (m_sendBufferWritePtr > 0) { m_peer.VerifyNetworkThread(); NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0); m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndpoint, m_sendBufferNumMessages, out connectionReset); m_statistics.PacketSent(m_sendBufferWritePtr, m_sendBufferNumMessages); m_sendBufferWritePtr = 0; m_sendBufferNumMessages = 0; } }