internal void EnqueueReceivedMessage(IncomingNetMessage msg) { lock (m_receivedMessages) { m_receivedMessages.Enqueue(msg); } m_dataReceivedEvent.Set(); }
/// <summary> /// Creates an incoming net message /// </summary> internal IncomingNetMessage CreateIncomingMessage() { // no recycling for messages IncomingNetMessage msg = new IncomingNetMessage(); msg.m_msgType = NetMessageType.Data; msg.m_data = CreateBuffer(); return(msg); }
internal void NotifyApplication(NetMessageType tp, NetBuffer buffer, NetConnection conn, IPEndPoint ep) { IncomingNetMessage msg = new IncomingNetMessage(); msg.m_data = buffer; msg.m_msgType = tp; msg.m_sender = conn; msg.m_senderEndPoint = ep; EnqueueReceivedMessage(msg); }
/// <summary> /// Returns a NetMessage to return to application; or null if nothing /// </summary> internal IncomingNetMessage HandleResponse( IncomingNetMessage message, NetworkEndPoint endPoint ) { if ((m_netBase.m_enabledMessageTypes & NetMessageType.ServerDiscovered) != NetMessageType.ServerDiscovered) { return(null); // disabled } if (message.m_data == null || m_requests == null) { return(null); } ushort number = message.m_data.ReadUInt16(); // find corresponding request NetDiscoveryRequest found = null; foreach (NetDiscoveryRequest request in m_requests) { if (request.Number == number) { found = request; break; } } if (found == null) { m_netBase.LogVerbose("Received discovery response to request " + number + " - unknown/old request!"); return(null); // Timed out request or not found } if (found.HasDiscovered(endPoint)) { m_netBase.LogVerbose("Received discovery response to request " + number + " - previously known response!"); return(null); // Already discovered in this request, else stored it } m_netBase.LogVerbose("Received discovery response to request " + number + " - passing on to app..."); IncomingNetMessage resMsg = m_netBase.CreateIncomingMessage(); resMsg.m_msgType = NetMessageType.ServerDiscovered; // write sender, assume ipv4 resMsg.m_data.Write(endPoint); return(resMsg); }
/// <summary> /// Emit receipt event /// </summary> internal void FireReceipt(NetConnection connection, NetBuffer receiptData) { if ((m_enabledMessageTypes & NetMessageType.Receipt) != NetMessageType.Receipt) { return; // disabled } IncomingNetMessage msg = CreateIncomingMessage(); msg.m_sender = connection; msg.m_msgType = NetMessageType.Receipt; msg.m_data = receiptData; EnqueueReceivedMessage(msg); }
/// <summary> /// Returns true if message should be dropped /// </summary> internal bool HandleNATIntroduction(IncomingNetMessage message) { if (message.m_type == NetMessageLibraryType.System) { if (message.m_data.LengthBytes > 4 && message.m_data.PeekByte() == (byte)NetSystemType.NatIntroduction) { if ((m_enabledMessageTypes & NetMessageType.NATIntroduction) != NetMessageType.NATIntroduction) { return(true); // drop } try { message.m_data.ReadByte(); // step past system type byte IPEndPoint presented = message.m_data.ReadIPEndPoint(); LogVerbose("Received NATIntroduction to " + presented + "; sending punching ping..."); double now = NetTime.Now; NetConnection.SendPing(this, presented, now); if (m_holePunches == null) { m_holePunches = new List <IPEndPoint>(); } for (int i = 0; i < 5; i++) { m_holePunches.Add(new IPEndPoint(presented.Address, presented.Port)); } NetBuffer info = CreateBuffer(); info.Write(presented); NotifyApplication(NetMessageType.NATIntroduction, info, message.m_sender, message.m_senderEndPoint); return(true); } catch (Exception ex) { NotifyApplication(NetMessageType.BadMessageReceived, "Bad NAT introduction message received: " + ex.Message, message.m_sender, message.m_senderEndPoint); return(true); } } } return(false); }
internal bool VerifyIdentifiers( IncomingNetMessage message, NetworkEndPoint endPoint, out ushort number ) { number = 0; int payLen = message.m_data.LengthBytes; if (payLen < 13) { if ((m_netBase.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { m_netBase.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed Discovery message received from " + endPoint, null, message.m_senderEndPoint); } return(false); } // check app identifier string appIdent2 = message.m_data.ReadString(); if (appIdent2 != m_netBase.m_config.ApplicationIdentifier) { if ((m_netBase.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { m_netBase.NotifyApplication(NetMessageType.BadMessageReceived, "Discovery for different application identification received: " + appIdent2, null, message.m_senderEndPoint); } return(false); } // check netbase identifier byte[] nbid = message.m_data.ReadBytes(m_netBase.m_localRndSignature.Length); if (NetUtility.CompareElements(nbid, m_netBase.m_localRndSignature)) { return(false); // don't respond to your own discovery request } // retrieve number number = message.m_data.ReadUInt16(); // it's ok return(true); }
/// <summary> /// Notify application that a connection changed status /// </summary> internal void NotifyStatusChange(NetConnection connection, string reason) { if ((m_enabledMessageTypes & NetMessageType.StatusChanged) != NetMessageType.StatusChanged) { return; // disabled } //NotifyApplication(NetMessageType.StatusChanged, reason, connection); NetBuffer buffer = CreateBuffer(reason.Length + 2); buffer.Write(reason); buffer.Write((byte)connection.Status); IncomingNetMessage msg = new IncomingNetMessage(); msg.m_data = buffer; msg.m_msgType = NetMessageType.StatusChanged; msg.m_sender = connection; msg.m_senderEndPoint = null; EnqueueReceivedMessage(msg); }
/// <summary> /// Handle a discovery request /// </summary> internal void HandleRequest(IncomingNetMessage message, IPEndPoint senderEndpoint) { ushort number; if (!VerifyIdentifiers(message, senderEndpoint, out number)) return; // bad app ident or self discovery NetBuffer buf = m_netBase.CreateBuffer(2); buf.Write(number); m_netBase.LogVerbose("Sending discovery response to request " + number); // send discovery response m_netBase.SendSingleUnreliableSystemMessage( NetSystemType.DiscoveryResponse, buf, senderEndpoint, false ); m_netBase.RecycleBuffer(buf); }
/// <summary> /// Handle a discovery request /// </summary> internal void HandleRequest(IncomingNetMessage message, NetworkEndPoint senderEndpoint) { ushort number; if (!VerifyIdentifiers(message, senderEndpoint, out number)) { return; // bad app ident or self discovery } NetBuffer buf = m_netBase.CreateBuffer(2); buf.Write(number); m_netBase.LogWrite("Sending discovery response to " + senderEndpoint + " request " + number); // send discovery response m_netBase.SendSingleUnreliableSystemMessage( NetSystemType.DiscoveryResponse, buf, senderEndpoint, null ); m_netBase.RecycleBuffer(buf); }
internal override void HandleReceivedMessage(IncomingNetMessage message, NetworkEndPoint senderEndpoint, double localTimeRecv) { //LogWrite("NetClient received message " + message); double now = NetTime.Now; int payLen = message.m_data.LengthBytes; // Discovery response? if (message.m_type == NetMessageLibraryType.System && payLen > 0) { NetSystemType sysType = (NetSystemType)message.m_data.PeekByte(); if (sysType == NetSystemType.DiscoveryResponse) { message.m_data.ReadByte(); // step past system type byte IncomingNetMessage resMsg = m_discovery.HandleResponse(message, senderEndpoint); if (resMsg != null) { resMsg.m_senderEndPoint = senderEndpoint; EnqueueReceivedMessage(resMsg); } return; } } // Out of band? if (message.m_type == NetMessageLibraryType.OutOfBand) { if ((m_enabledMessageTypes & NetMessageType.OutOfBandData) != NetMessageType.OutOfBandData) { return; // drop } // just deliver message.m_msgType = NetMessageType.OutOfBandData; message.m_senderEndPoint = senderEndpoint; EnqueueReceivedMessage(message); return; } if (message.m_sender != m_serverConnection && m_serverConnection != null) { return; // don't talk to strange senders after this } if (message.m_type == NetMessageLibraryType.Acknowledge) { m_serverConnection.HandleAckMessage(now, message); return; } // Handle system types if (message.m_type == NetMessageLibraryType.System) { if (payLen < 1) { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Received malformed system message: " + message, m_serverConnection, senderEndpoint); } return; } NetSystemType sysType = (NetSystemType)message.m_data.Data[0]; switch (sysType) { case NetSystemType.ConnectResponse: case NetSystemType.Ping: case NetSystemType.Pong: case NetSystemType.Disconnect: case NetSystemType.ConnectionRejected: case NetSystemType.StringTableAck: if (m_serverConnection != null) { m_serverConnection.HandleSystemMessage(message, localTimeRecv); } return; case NetSystemType.Connect: case NetSystemType.ConnectionEstablished: case NetSystemType.Discovery: case NetSystemType.Error: default: if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for client and " + sysType, m_serverConnection, senderEndpoint); } return; } } Debug.Assert( message.m_type == NetMessageLibraryType.User || message.m_type == NetMessageLibraryType.UserFragmented ); if (m_serverConnection.Status == NetConnectionStatus.Connecting) { m_serverConnection.Disconnect("Received user message before ConnectResponse", 0.0f, true, true); return; /* * // lost connectresponse packet? * // Emulate it; * LogVerbose("Received user message before ConnectResponse; emulating ConnectResponse...", m_serverConnection); * IncomingNetMessage emuMsg = CreateIncomingMessage(); * emuMsg.m_type = NetMessageLibraryType.System; * emuMsg.m_data.Reset(); * emuMsg.m_data.Write((byte)NetSystemType.ConnectResponse); * m_serverConnection.HandleSystemMessage(emuMsg, now); */ // ... and proceed to pick up user message } // add to pick-up queue m_serverConnection.HandleUserMessage(message, now); }
/// <summary> /// Creates an incoming net message /// </summary> internal IncomingNetMessage CreateIncomingMessage() { // no recycling for messages IncomingNetMessage msg = new IncomingNetMessage(); msg.m_msgType = NetMessageType.Data; msg.m_data = CreateBuffer(); return msg; }
/* internal void HandleUserMessage(NetMessage msg) { int seqNr = msg.m_sequenceNumber; int chanNr = (int)msg.m_sequenceChannel; bool isDuplicate = false; int relation = RelateToExpected(seqNr, chanNr, out isDuplicate); // // Unreliable // if (msg.m_sequenceChannel == NetChannel.Unreliable) { // It's all good; add message if (isDuplicate) { m_statistics.CountDuplicateMessage(msg); m_owner.LogVerbose("Rejecting duplicate " + msg, this); } else { AcceptMessage(msg); } return; } // // Reliable unordered // if (msg.m_sequenceChannel == NetChannel.ReliableUnordered) { // send acknowledge (even if duplicate) m_acknowledgesToSend.Enqueue((chanNr << 16) | msg.m_sequenceNumber); if (isDuplicate) { m_statistics.CountDuplicateMessage(msg); m_owner.LogVerbose("Rejecting duplicate " + msg, this); return; // reject duplicates } // It's good; add message AcceptMessage(msg); return; } ushort nextSeq = (ushort)(seqNr + 1); if (chanNr < (int)NetChannel.ReliableInOrder1) { // // Sequenced // if (relation < 0) { // late sequenced message m_statistics.CountDroppedSequencedMessage(); m_owner.LogVerbose("Dropping late sequenced " + msg, this); return; } // It's good; add message AcceptMessage(msg); m_nextExpectedSequence[chanNr] = nextSeq; return; } else { // // Ordered // // send ack (regardless) m_acknowledgesToSend.Enqueue((chanNr << 16) | msg.m_sequenceNumber); if (relation < 0) { // late ordered message #if DEBUG if (!isDuplicate) m_owner.LogWrite("Ouch, weird! Late ordered message that's NOT a duplicate?! seqNr: " + seqNr + " expecting: " + m_nextExpectedSequence[chanNr], this); #endif // must be duplicate m_owner.LogVerbose("Dropping duplicate message " + seqNr, this); m_statistics.CountDuplicateMessage(msg); return; // rejected; don't advance next expected } if (relation > 0) { // early message; withhold ordered m_owner.LogVerbose("Withholding " + msg + " (expecting " + m_nextExpectedSequence[chanNr] + ")", this); m_withheldMessages.Add(msg); return; // return without advancing next expected } // It's right on time! AcceptMessage(msg); // ordered; release other withheld messages? bool released = false; do { released = false; foreach (NetMessage wm in m_withheldMessages) { if ((int)wm.m_sequenceChannel == chanNr && wm.m_sequenceNumber == nextSeq) { m_owner.LogVerbose("Releasing withheld message " + wm, this); m_withheldMessages.Remove(wm); AcceptMessage(wm); // no need to set rounds for this message; it was one when first related() and withheld nextSeq++; if (nextSeq >= NetConstants.NumSequenceNumbers) nextSeq -= NetConstants.NumSequenceNumbers; released = true; break; } } } while (released); } // Common to Sequenced and Ordered //m_owner.LogVerbose("Setting next expected for " + (NetChannel)chanNr + " to " + nextSeq); m_nextExpectedSequence[chanNr] = nextSeq; return; } */ internal void HandleSystemMessage(IncomingNetMessage msg, double now) { msg.m_data.Position = 0; NetSystemType sysType = (NetSystemType)msg.m_data.ReadByte(); OutgoingNetMessage response = null; switch (sysType) { case NetSystemType.Disconnect: if (m_status == NetConnectionStatus.Disconnected) return; Disconnect(msg.m_data.ReadString(), 0.75f + ((float)m_currentAvgRoundtrip * 4), false, false); break; case NetSystemType.ConnectionRejected: m_owner.NotifyApplication(NetMessageType.ConnectionRejected, msg.m_data.ReadString(), msg.m_sender, msg.m_senderEndPoint); break; case NetSystemType.Connect: // ConnectReponse must have been losts string appIdent = msg.m_data.ReadString(); if (appIdent != m_owner.m_config.ApplicationIdentifier) { if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Connect for different application identification received: " + appIdent, null, msg.m_senderEndPoint); return; } // read random identifer byte[] rnd = msg.m_data.ReadBytes(8); if (NetUtility.CompareElements(rnd, m_owner.m_randomIdentifier)) { // don't allow self-connect if ((m_owner.m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected) m_owner.NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null, msg.m_senderEndPoint); return; } // read hail data m_remoteHailData = null; int hailBytesCount = (msg.m_data.LengthBits - msg.m_data.Position) / 8; if (hailBytesCount > 0) m_remoteHailData = msg.m_data.ReadBytes(hailBytesCount); // finalize disconnect if it's in process if (m_status == NetConnectionStatus.Disconnecting) FinalizeDisconnect(); // send response; even if connected response = m_owner.CreateSystemMessage(NetSystemType.ConnectResponse); if (m_localHailData != null) response.m_data.Write(m_localHailData); m_unsentMessages.Enqueue(response); break; case NetSystemType.ConnectResponse: if (m_status != NetConnectionStatus.Connecting && m_status != NetConnectionStatus.Connected) { m_owner.LogWrite("Received connection response but we're not connecting...", this); return; } // read hail data m_remoteHailData = null; int numHailBytes = (msg.m_data.LengthBits - msg.m_data.Position) / 8; if (numHailBytes > 0) m_remoteHailData = msg.m_data.ReadBytes(numHailBytes); // Send connectionestablished response = m_owner.CreateSystemMessage(NetSystemType.ConnectionEstablished); if (m_localHailData != null) response.m_data.Write(m_localHailData); m_unsentMessages.Enqueue(response); // send first ping 250ms after connected m_lastSentPing = now - m_owner.Configuration.PingFrequency + 0.1 + (NetRandom.Instance.NextFloat() * 0.25f); m_statistics.Reset(); SetInitialAveragePing(now - m_handshakeInitiated); SetStatus(NetConnectionStatus.Connected, "Connected"); break; case NetSystemType.ConnectionEstablished: if (m_status != NetConnectionStatus.Connecting) { if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Received connection response but we're not connecting...", this, msg.m_senderEndPoint); return; } // read hail data if (m_remoteHailData == null) { int hbc = (msg.m_data.LengthBits - msg.m_data.Position) / 8; if (hbc > 0) m_remoteHailData = msg.m_data.ReadBytes(hbc); } // send first ping 100-350ms after connected m_lastSentPing = now - m_owner.Configuration.PingFrequency + 0.1 + (NetRandom.Instance.NextFloat() * 0.25f); m_statistics.Reset(); SetInitialAveragePing(now - m_handshakeInitiated); SetStatus(NetConnectionStatus.Connected, "Connected"); break; case NetSystemType.Ping: // also accepted as ConnectionEstablished if (m_isInitiator == false && m_status == NetConnectionStatus.Connecting) { m_owner.LogWrite("Received ping; interpreted as ConnectionEstablished", this); m_statistics.Reset(); SetInitialAveragePing(now - m_handshakeInitiated); SetStatus(NetConnectionStatus.Connected, "Connected"); } //LogWrite("Received ping; sending pong..."); SendPong(m_owner, m_remoteEndPoint, now); break; case NetSystemType.Pong: double twoWayLatency = now - m_lastSentPing; if (twoWayLatency < 0) break; ReceivedPong(twoWayLatency, msg); break; case NetSystemType.StringTableAck: ushort val = msg.m_data.ReadUInt16(); StringTableAcknowledgeReceived(val); break; default: m_owner.LogWrite("Undefined behaviour in NetConnection for system message " + sysType, this); break; } }
/// <summary> /// Called when a message should be released to the application /// </summary> private void AcceptMessage(IncomingNetMessage msg) { if (msg.m_type == NetMessageLibraryType.UserFragmented) { // parse int id = msg.m_data.ReadUInt16(); int number = (int)msg.m_data.ReadVariableUInt32(); // 0 to total-1 int total = (int)msg.m_data.ReadVariableUInt32(); int bytePtr = msg.m_data.Position / 8; int payloadLen = msg.m_data.LengthBytes - bytePtr; FragmentedMessage fmsg; if (!m_fragments.TryGetValue(id, out fmsg)) { fmsg = new FragmentedMessage(); fmsg.TotalFragments = total; fmsg.FragmentsReceived = 0; fmsg.ChunkSize = payloadLen; fmsg.Data = new byte[payloadLen * total]; m_fragments[id] = fmsg; } // insert this fragment Array.Copy( msg.m_data.Data, bytePtr, fmsg.Data, number * fmsg.ChunkSize, payloadLen ); fmsg.BitLength += (msg.m_data.m_bitLength - msg.m_data.Position); fmsg.FragmentsReceived++; m_owner.LogVerbose("Fragment " + id + " - " + (number+1) + "/" + total + " received; chunksize " + fmsg.ChunkSize + " this size " + payloadLen, this); if (fmsg.FragmentsReceived < fmsg.TotalFragments) { // Not yet complete return; } // Done! Release it as a complete message NetBuffer buf = new NetBuffer(false); buf.Data = fmsg.Data; //int bitLen = (fmsg.TotalFragments - 1) * fmsg.ChunkSize * 8; //bitLen += msg.m_data.m_bitLength - (bytePtr * 8); buf.m_bitLength = fmsg.BitLength; m_fragments.Remove(id); // reuse "msg" m_owner.LogVerbose("All fragments received; complete length is " + buf.LengthBytes, this); msg.m_data = buf; } // release // m_owner.LogVerbose("Accepted " + msg, this); // Debug.Assert(msg.m_type == NetMessageLibraryType.User); lock(m_owner.m_receivedMessages) m_owner.m_receivedMessages.Enqueue(msg); }
internal void EnqueueReceivedMessage(IncomingNetMessage msg) { m_receivedMessages.Enqueue(msg); }
internal override void HandleReceivedMessage(IncomingNetMessage message, IPEndPoint senderEndpoint) { double now = NetTime.Now; int payLen = message.m_data.LengthBytes; // NAT introduction? if (HandleNATIntroduction(message)) return; // Out of band? if (message.m_type == NetMessageLibraryType.OutOfBand) { if ((m_enabledMessageTypes & NetMessageType.OutOfBandData) != NetMessageType.OutOfBandData) return; // drop // just deliever message.m_msgType = NetMessageType.OutOfBandData; message.m_senderEndPoint = senderEndpoint; EnqueueReceivedMessage(message); return; } if (message.m_sender == null) { // // Handle unconnected message // // not a connected sender; only allow System messages if (message.m_type != NetMessageLibraryType.System) { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) NotifyApplication(NetMessageType.BadMessageReceived, "Rejecting non-system message from unconnected source: " + message, null, message.m_senderEndPoint); return; } // read type of system message NetSystemType sysType = (NetSystemType)message.m_data.ReadByte(); switch (sysType) { case NetSystemType.Connect: LogVerbose("Connection request received from " + senderEndpoint); // check app ident if (payLen < 4) { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) NotifyApplication(NetMessageType.BadMessageReceived, "Malformed Connect message received from " + senderEndpoint, null, senderEndpoint); return; } string appIdent = message.m_data.ReadString(); if (appIdent != m_config.ApplicationIdentifier) { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) NotifyApplication(NetMessageType.BadMessageReceived, "Connect for different application identification received: " + appIdent, null, senderEndpoint); return; } // read random identifer byte[] rnd = message.m_data.ReadBytes(8); if (NetUtility.CompareElements(rnd, m_randomIdentifier)) { // don't allow self-connect if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected) NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null, senderEndpoint); return; } int bytesReadSoFar = (message.m_data.Position / 8); int hailLen = message.m_data.LengthBytes - bytesReadSoFar; byte[] hailData = null; if (hailLen > 0) { hailData = new byte[hailLen]; Buffer.BlockCopy(message.m_data.Data, bytesReadSoFar, hailData, 0, hailLen); } if (m_connections.Count >= m_config.m_maxConnections) { if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected) NotifyApplication(NetMessageType.ConnectionRejected, "Server full; rejecting connect from " + senderEndpoint, null, senderEndpoint); return; } // Create connection LogWrite("New connection: " + senderEndpoint); NetConnection conn = new NetConnection(this, senderEndpoint, null, hailData); // Connection approval? if ((m_enabledMessageTypes & NetMessageType.ConnectionApproval) == NetMessageType.ConnectionApproval) { // Ask application if this connection is allowed to proceed IncomingNetMessage app = CreateIncomingMessage(); app.m_msgType = NetMessageType.ConnectionApproval; if (hailData != null) app.m_data.Write(hailData); app.m_sender = conn; conn.m_approved = false; EnqueueReceivedMessage(app); // Don't add connection; it's done as part of the approval procedure return; } // it's ok AddConnection(now, conn); break; case NetSystemType.ConnectionEstablished: if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) NotifyApplication(NetMessageType.BadMessageReceived, "Connection established received from non-connection! " + senderEndpoint, null, senderEndpoint); return; case NetSystemType.Discovery: if (m_config.AnswerDiscoveryRequests) m_discovery.HandleRequest(message, senderEndpoint); break; case NetSystemType.DiscoveryResponse: if (m_allowOutgoingConnections) { // NetPeer IncomingNetMessage resMsg = m_discovery.HandleResponse(message, senderEndpoint); if (resMsg != null) { resMsg.m_senderEndPoint = senderEndpoint; EnqueueReceivedMessage(resMsg); } } break; default: if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for " + this + " receiving system type " + sysType + ": " + message + " from unconnected source", null, senderEndpoint); break; } // done return; } // ok, we have a sender if (message.m_type == NetMessageLibraryType.Acknowledge) { message.m_sender.HandleAckMessage(message); return; } if (message.m_type == NetMessageLibraryType.System) { // // Handle system messages from connected source // if (payLen < 1) { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) NotifyApplication(NetMessageType.BadMessageReceived, "Received malformed system message; payload length less than 1 byte", null, senderEndpoint); return; } NetSystemType sysType = (NetSystemType)message.m_data.ReadByte(); switch (sysType) { case NetSystemType.Connect: case NetSystemType.ConnectionEstablished: case NetSystemType.Ping: case NetSystemType.Pong: case NetSystemType.Disconnect: case NetSystemType.ConnectionRejected: case NetSystemType.StringTableAck: message.m_sender.HandleSystemMessage(message, now); break; case NetSystemType.ConnectResponse: if (m_allowOutgoingConnections) { message.m_sender.HandleSystemMessage(message, now); } else { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for server and system type " + sysType, null, senderEndpoint); } break; case NetSystemType.Discovery: // Allow discovery even if connected if (m_config.AnswerDiscoveryRequests) m_discovery.HandleRequest(message, senderEndpoint); break; default: if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for server and system type " + sysType, null, senderEndpoint); break; } return; } message.m_sender.HandleUserMessage(message); }
internal override void HandleReceivedMessage(IncomingNetMessage message, IPEndPoint senderEndpoint) { //LogWrite("NetClient received message " + message); double now = NetTime.Now; int payLen = message.m_data.LengthBytes; // Discovery response? if (message.m_type == NetMessageLibraryType.System && payLen > 0) { NetSystemType sysType = (NetSystemType)message.m_data.PeekByte(); // NAT introduction? if (HandleNATIntroduction(message)) return; if (sysType == NetSystemType.DiscoveryResponse) { message.m_data.ReadByte(); // step past system type byte IncomingNetMessage resMsg = m_discovery.HandleResponse(message, senderEndpoint); if (resMsg != null) { resMsg.m_senderEndPoint = senderEndpoint; lock (m_receivedMessages) m_receivedMessages.Enqueue(resMsg); } return; } } // Out of band? if (message.m_type == NetMessageLibraryType.OutOfBand) { if ((m_enabledMessageTypes & NetMessageType.OutOfBandData) != NetMessageType.OutOfBandData) return; // drop // just deliever message.m_msgType = NetMessageType.OutOfBandData; message.m_senderEndPoint = senderEndpoint; lock (m_receivedMessages) m_receivedMessages.Enqueue(message); return; } if (message.m_sender != m_serverConnection && m_serverConnection != null) return; // don't talk to strange senders after this if (message.m_type == NetMessageLibraryType.Acknowledge) { m_serverConnection.HandleAckMessage(message); return; } // Handle system types if (message.m_type == NetMessageLibraryType.System) { if (payLen < 1) { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) NotifyApplication(NetMessageType.BadMessageReceived, "Received malformed system message: " + message, m_serverConnection, senderEndpoint); return; } NetSystemType sysType = (NetSystemType)message.m_data.Data[0]; switch (sysType) { case NetSystemType.ConnectResponse: case NetSystemType.Ping: case NetSystemType.Pong: case NetSystemType.Disconnect: case NetSystemType.ConnectionRejected: case NetSystemType.StringTableAck: if (m_serverConnection != null) m_serverConnection.HandleSystemMessage(message, now); return; case NetSystemType.Connect: case NetSystemType.ConnectionEstablished: case NetSystemType.Discovery: case NetSystemType.Error: default: if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for client and " + sysType, m_serverConnection, senderEndpoint); return; } } Debug.Assert( message.m_type == NetMessageLibraryType.User || message.m_type == NetMessageLibraryType.UserFragmented ); if (m_serverConnection.Status == NetConnectionStatus.Connecting) { // lost connectresponse packet? // Emulate it; LogVerbose("Received user message before ConnectResponse; emulating ConnectResponse...", m_serverConnection); IncomingNetMessage emuMsg = CreateIncomingMessage(); emuMsg.m_type = NetMessageLibraryType.System; emuMsg.m_data.Reset(); emuMsg.m_data.Write((byte)NetSystemType.ConnectResponse); m_serverConnection.HandleSystemMessage(emuMsg, now); // ... and proceed to pick up user message } // add to pick-up queue m_serverConnection.HandleUserMessage(message); }
internal override void HandleReceivedMessage(IncomingNetMessage message, IPEndPoint senderEndpoint) { double now = NetTime.Now; int payLen = message.m_data.LengthBytes; // NAT introduction? if (HandleNATIntroduction(message)) { return; } // Out of band? if (message.m_type == NetMessageLibraryType.OutOfBand) { if ((m_enabledMessageTypes & NetMessageType.OutOfBandData) != NetMessageType.OutOfBandData) { return; // drop } // just deliever message.m_msgType = NetMessageType.OutOfBandData; message.m_senderEndPoint = senderEndpoint; lock (m_receivedMessages) m_receivedMessages.Enqueue(message); return; } if (message.m_sender == null) { // // Handle unconnected message // // not a connected sender; only allow System messages if (message.m_type != NetMessageLibraryType.System) { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Rejecting non-system message from unconnected source: " + message, null, message.m_senderEndPoint); } return; } // read type of system message NetSystemType sysType = (NetSystemType)message.m_data.ReadByte(); switch (sysType) { case NetSystemType.Connect: LogVerbose("Connection request received from " + senderEndpoint); // check app ident if (payLen < 4) { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Malformed Connect message received from " + senderEndpoint, null, senderEndpoint); } return; } string appIdent = message.m_data.ReadString(); if (appIdent != m_config.ApplicationIdentifier) { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Connect for different application identification received: " + appIdent, null, senderEndpoint); } return; } // read random identifer byte[] rnd = message.m_data.ReadBytes(8); if (NetUtility.CompareElements(rnd, m_randomIdentifier)) { // don't allow self-connect if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected) { NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null, senderEndpoint); } return; } int bytesReadSoFar = (message.m_data.Position / 8); int hailLen = message.m_data.LengthBytes - bytesReadSoFar; byte[] hailData = null; if (hailLen > 0) { hailData = new byte[hailLen]; Buffer.BlockCopy(message.m_data.Data, bytesReadSoFar, hailData, 0, hailLen); } if (m_connections.Count >= m_config.m_maxConnections) { if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected) { NotifyApplication(NetMessageType.ConnectionRejected, "Server full; rejecting connect from " + senderEndpoint, null, senderEndpoint); } return; } // Create connection LogWrite("New connection: " + senderEndpoint); NetConnection conn = new NetConnection(this, senderEndpoint, null, hailData); // Connection approval? if ((m_enabledMessageTypes & NetMessageType.ConnectionApproval) == NetMessageType.ConnectionApproval) { // Ask application if this connection is allowed to proceed IncomingNetMessage app = CreateIncomingMessage(); app.m_msgType = NetMessageType.ConnectionApproval; if (hailData != null) { app.m_data.Write(hailData); } app.m_sender = conn; conn.m_approved = false; lock (m_receivedMessages) m_receivedMessages.Enqueue(app); // Don't add connection; it's done as part of the approval procedure return; } // it's ok AddConnection(now, conn); break; case NetSystemType.ConnectionEstablished: if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Connection established received from non-connection! " + senderEndpoint, null, senderEndpoint); } return; case NetSystemType.Discovery: if (m_config.AnswerDiscoveryRequests) { m_discovery.HandleRequest(message, senderEndpoint); } break; case NetSystemType.DiscoveryResponse: if (m_allowOutgoingConnections) { // NetPeer IncomingNetMessage resMsg = m_discovery.HandleResponse(message, senderEndpoint); resMsg.m_senderEndPoint = senderEndpoint; if (resMsg != null) { lock (m_receivedMessages) m_receivedMessages.Enqueue(resMsg); } } break; default: if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for " + this + " receiving system type " + sysType + ": " + message + " from unconnected source", null, senderEndpoint); } break; } // done return; } // ok, we have a sender if (message.m_type == NetMessageLibraryType.Acknowledge) { message.m_sender.HandleAckMessage(message); return; } if (message.m_type == NetMessageLibraryType.System) { // // Handle system messages from connected source // if (payLen < 1) { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Received malformed system message; payload length less than 1 byte", null, senderEndpoint); } return; } NetSystemType sysType = (NetSystemType)message.m_data.ReadByte(); switch (sysType) { case NetSystemType.Connect: case NetSystemType.ConnectionEstablished: case NetSystemType.Ping: case NetSystemType.Pong: case NetSystemType.Disconnect: case NetSystemType.ConnectionRejected: case NetSystemType.StringTableAck: message.m_sender.HandleSystemMessage(message, now); break; case NetSystemType.ConnectResponse: if (m_allowOutgoingConnections) { message.m_sender.HandleSystemMessage(message, now); } else { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for server and system type " + sysType, null, senderEndpoint); } } break; case NetSystemType.Discovery: // Allow discovery even if connected if (m_config.AnswerDiscoveryRequests) { m_discovery.HandleRequest(message, senderEndpoint); } break; default: if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for server and system type " + sysType, null, senderEndpoint); } break; } return; } message.m_sender.HandleUserMessage(message); }
public bool ReadMessage( NetBuffer intoBuffer, out NetMessageType type, out NetConnection sender, out NetworkEndPoint senderEndPoint, out NetChannel channel, out double localTimeRecv) { if (intoBuffer == null) { throw new ArgumentNullException("intoBuffer"); } if (m_receivedMessages.Count < 1) { type = NetMessageType.None; sender = null; senderEndPoint = NetworkEndPoint.unassigned; channel = NetChannel.Unreliable; localTimeRecv = 0; return(false); } IncomingNetMessage msg = m_receivedMessages.Dequeue(); if (msg == null) { type = NetMessageType.None; sender = null; senderEndPoint = NetworkEndPoint.unassigned; channel = NetChannel.Unreliable; localTimeRecv = 0; return(false); } senderEndPoint = msg.m_senderEndPoint; sender = msg.m_sender; localTimeRecv = NetTime.Now; // TODO: this is a ugly hack, should instead get value when reading from socket. Merging/switching to Speedgren will solve that. channel = msg.m_sequenceChannel; // recycle NetMessage object var content = msg.m_data; msg.m_data = null; type = msg.m_msgType; if (content == null) { intoBuffer.m_bitLength = 0; intoBuffer.m_readPosition = 0; return(true); } // swap content of buffers byte[] tmp = intoBuffer.Data; intoBuffer.Data = content.Data; content.Data = tmp; // set correct values for returning value (ignore the other, it's being recycled anyway) intoBuffer.m_bitLength = content.m_bitLength; intoBuffer.m_readPosition = 0; // recycle buffer RecycleBuffer(content); return(true); }
/// <summary> /// Called when a message should be released to the application /// </summary> private void AcceptMessage(IncomingNetMessage msg) { if (msg.m_type == NetMessageLibraryType.UserFragmented) { // parse int id = msg.m_data.ReadUInt16(); int number = (int)msg.m_data.ReadVariableUInt32(); // 0 to total-1 int total = (int)msg.m_data.ReadVariableUInt32(); int bytePtr = msg.m_data.Position / 8; int payloadLen = msg.m_data.LengthBytes - bytePtr; FragmentedMessage fmsg; if (!m_fragments.TryGetValue(id, out fmsg)) { fmsg = new FragmentedMessage(); fmsg.TotalFragments = total; fmsg.FragmentsReceived = 0; fmsg.ChunkSize = payloadLen; fmsg.Data = new byte[payloadLen * total]; m_fragments[id] = fmsg; } // insert this fragment Array.Copy( msg.m_data.Data, bytePtr, fmsg.Data, number * fmsg.ChunkSize, payloadLen ); fmsg.BitLength += (msg.m_data.m_bitLength - msg.m_data.Position); fmsg.FragmentsReceived++; m_owner.LogVerbose("Fragment " + id + " - " + (number + 1) + "/" + total + " received; chunksize " + fmsg.ChunkSize + " this size " + payloadLen, this); if (fmsg.FragmentsReceived < fmsg.TotalFragments) { // Not yet complete return; } // Done! Release it as a complete message NetBuffer buf = new NetBuffer(false); buf.Data = fmsg.Data; //int bitLen = (fmsg.TotalFragments - 1) * fmsg.ChunkSize * 8; //bitLen += msg.m_data.m_bitLength - (bytePtr * 8); buf.m_bitLength = fmsg.BitLength; m_fragments.Remove(id); // reuse "msg" m_owner.LogVerbose("All fragments received; complete length is " + buf.LengthBytes, this); msg.m_data = buf; } // release // m_owner.LogVerbose("Accepted " + msg, this); // Debug.Assert(msg.m_type == NetMessageLibraryType.User); // do custom handling on networking thread m_owner.ProcessReceived(msg.m_data); m_owner.EnqueueReceivedMessage(msg); }
/* * internal void HandleUserMessage(NetMessage msg) * { * int seqNr = msg.m_sequenceNumber; * int chanNr = (int)msg.m_sequenceChannel; * bool isDuplicate = false; * * int relation = RelateToExpected(seqNr, chanNr, out isDuplicate); * * // * // Unreliable * // * if (msg.m_sequenceChannel == NetChannel.Unreliable) * { * // It's all good; add message * if (isDuplicate) * { * m_statistics.CountDuplicateMessage(msg); * m_owner.LogVerbose("Rejecting duplicate " + msg, this); * } * else * { * AcceptMessage(msg); * } * return; * } * * // * // Reliable unordered * // * if (msg.m_sequenceChannel == NetChannel.ReliableUnordered) * { * // send acknowledge (even if duplicate) * m_acknowledgesToSend.Enqueue((chanNr << 16) | msg.m_sequenceNumber); * * if (isDuplicate) * { * m_statistics.CountDuplicateMessage(msg); * m_owner.LogVerbose("Rejecting duplicate " + msg, this); * return; // reject duplicates * } * * // It's good; add message * AcceptMessage(msg); * * return; * } * * ushort nextSeq = (ushort)(seqNr + 1); * * if (chanNr < (int)NetChannel.ReliableInOrder1) * { * // * // Sequenced * // * if (relation < 0) * { * // late sequenced message * m_statistics.CountDroppedSequencedMessage(); * m_owner.LogVerbose("Dropping late sequenced " + msg, this); * return; * } * * // It's good; add message * AcceptMessage(msg); * * m_nextExpectedSequence[chanNr] = nextSeq; * return; * } * else * { * // * // Ordered * // * * // send ack (regardless) * m_acknowledgesToSend.Enqueue((chanNr << 16) | msg.m_sequenceNumber); * * if (relation < 0) * { * // late ordered message #if DEBUG * if (!isDuplicate) * m_owner.LogWrite("Ouch, weird! Late ordered message that's NOT a duplicate?! seqNr: " + seqNr + " expecting: " + m_nextExpectedSequence[chanNr], this); #endif * // must be duplicate * m_owner.LogVerbose("Dropping duplicate message " + seqNr, this); * m_statistics.CountDuplicateMessage(msg); * return; // rejected; don't advance next expected * } * * if (relation > 0) * { * // early message; withhold ordered * m_owner.LogVerbose("Withholding " + msg + " (expecting " + m_nextExpectedSequence[chanNr] + ")", this); * m_withheldMessages.Add(msg); * return; // return without advancing next expected * } * * // It's right on time! * AcceptMessage(msg); * * // ordered; release other withheld messages? * bool released = false; * do * { * released = false; * foreach (NetMessage wm in m_withheldMessages) * { * if ((int)wm.m_sequenceChannel == chanNr && wm.m_sequenceNumber == nextSeq) * { * m_owner.LogVerbose("Releasing withheld message " + wm, this); * m_withheldMessages.Remove(wm); * AcceptMessage(wm); * // no need to set rounds for this message; it was one when first related() and withheld * nextSeq++; * if (nextSeq >= NetConstants.NumSequenceNumbers) * nextSeq -= NetConstants.NumSequenceNumbers; * released = true; * break; * } * } * } while (released); * } * * // Common to Sequenced and Ordered * * //m_owner.LogVerbose("Setting next expected for " + (NetChannel)chanNr + " to " + nextSeq); * m_nextExpectedSequence[chanNr] = nextSeq; * * return; * } */ internal void HandleSystemMessage(IncomingNetMessage msg, double timestamp) { msg.m_data.PositionBits = 0; NetSystemType sysType = (NetSystemType)msg.m_data.ReadByte(); switch (sysType) { case NetSystemType.Disconnect: if (m_status == NetConnectionStatus.Disconnected) { return; } Disconnect(msg.m_data.ReadString(), NetConstants.DisconnectLingerTime, false, false); break; case NetSystemType.ConnectionRejected: string reason = msg.m_data.ReadString(); m_owner.NotifyApplication(NetMessageType.ConnectionRejected, reason, msg.m_sender, msg.m_senderEndPoint); Disconnect(reason, 0.0f, false, true); break; case NetSystemType.Connect: { // ConnectReponse must have been losts /*if (m_isInitiator) // this might be useful in the future * { * m_owner.LogWrite("Received connect but we're the initiator...", this); * return; // ignore * }*/ if (Status != NetConnectionStatus.Connecting && Status != NetConnectionStatus.Connected) { m_owner.LogWrite("Received connect but we're not connecting or connected...", this); return; // ignore if disconnecting } string appIdent = msg.m_data.ReadString(); if (appIdent != m_owner.m_config.ApplicationIdentifier) { if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Connect for different application identification received: " + appIdent, null, msg.m_senderEndPoint); } return; } // read random identifier var remoteRndSignature = msg.m_data.ReadBytes(NetConstants.SignatureByteSize); if (!m_owner.Configuration.AllowConnectionToSelf && NetUtility.CompareElements(remoteRndSignature, m_owner.m_localRndSignature)) { // don't allow self-connect if ((m_owner.m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected) { m_owner.NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null, msg.m_senderEndPoint); } return; } int remoteRndSeqNr = msg.m_data.ReadInt32(); if (m_remoteRndSignature != null) { if (!NetUtility.CompareElements(remoteRndSignature, m_remoteRndSignature) || remoteRndSeqNr != m_remoteRndSeqNr) { // this is not the same connection. Disconnect("Not the same connection", 0, false, true); return; } } else // this might happen if both try and connect at the same time. { m_remoteRndSignature = remoteRndSignature; m_remoteRndSeqNr = remoteRndSeqNr; ResetReliability(); } m_connectLocalSentTime = msg.m_data.ReadDouble(); m_connectRemoteRecvTime = timestamp + m_owner.m_localTimeOffset; // read hail data m_remoteHailData = null; int hailBytesCount = (msg.m_data.LengthBits - msg.m_data.PositionBits) / 8; if (hailBytesCount > 0) { m_remoteHailData = msg.m_data.ReadBytes(hailBytesCount); } // send response; even if connected var responseBuffer = m_owner.GetTempBuffer(); responseBuffer.Write(m_owner.m_localRndSignature); responseBuffer.Write(m_localRndSeqNr); responseBuffer.Write(m_remoteRndSignature); responseBuffer.Write(m_remoteRndSeqNr); double localTimeSent = m_connectLocalSentTime; responseBuffer.Write(localTimeSent); double remoteTimeRecv = m_connectRemoteRecvTime; responseBuffer.Write(remoteTimeRecv); double remoteTimeSent = NetTime.Now + m_owner.m_localTimeOffset; responseBuffer.Write(remoteTimeSent); if (m_localHailData != null) { responseBuffer.Write(m_localHailData); } m_handshakeInitiated = remoteTimeSent; SendSingleUnreliableSystemMessage(NetSystemType.ConnectResponse, responseBuffer); break; } case NetSystemType.ConnectResponse: { /*if (m_isInitiator) // this might be useful in the future * { * m_owner.LogWrite("Received connect but we're the initiator...", this); * return; // ignore * }*/ if (m_status != NetConnectionStatus.Connecting && m_status != NetConnectionStatus.Connected) { m_owner.LogWrite("Received connection response but we're not connecting or connected...", this); return; } var remoteRndSignature = msg.m_data.ReadBytes(NetConstants.SignatureByteSize); if (!m_owner.Configuration.AllowConnectionToSelf && NetUtility.CompareElements(remoteRndSignature, m_owner.m_localRndSignature)) { // don't allow self-connect if ((m_owner.m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected) { m_owner.NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null, msg.m_senderEndPoint); } return; } int remoteRndSeqNr = msg.m_data.ReadInt32(); if (m_remoteRndSignature != null) { if (!NetUtility.CompareElements(remoteRndSignature, m_remoteRndSignature) || remoteRndSeqNr != m_remoteRndSeqNr) { // this is not the same connection. Disconnect("Not the same connection", 0, false, true); return; } } else // this might happen if both try and connect at the same time. { m_remoteRndSignature = remoteRndSignature; m_remoteRndSeqNr = remoteRndSeqNr; ResetReliability(); } var myRndSignature = msg.m_data.ReadBytes(NetConstants.SignatureByteSize); var myRndSeqNr = msg.m_data.ReadInt32(); if (!NetUtility.CompareElements(myRndSignature, m_owner.m_localRndSignature) || myRndSeqNr != m_localRndSeqNr) { // this is not the same connection. Disconnect("Not the same connection", 0, false, true); return; } double localTimeSent = msg.m_data.ReadDouble(); double remoteTimeRecv = msg.m_data.ReadDouble(); double remoteTimeSent = msg.m_data.ReadDouble(); double localTimeRecv = timestamp + m_owner.m_localTimeOffset; // read hail data m_remoteHailData = null; int numHailBytes = (msg.m_data.LengthBits - msg.m_data.PositionBits) / 8; if (numHailBytes > 0) { m_remoteHailData = msg.m_data.ReadBytes(numHailBytes); } // Send connection established var responseBuffer = m_owner.GetTempBuffer(); responseBuffer.Write(m_owner.m_localRndSignature); responseBuffer.Write(m_localRndSeqNr); responseBuffer.Write(m_remoteRndSignature); responseBuffer.Write(m_remoteRndSeqNr); double intiatorLocalTimeSent = remoteTimeSent; responseBuffer.Write(intiatorLocalTimeSent); double intiatorRemoteTimeRecv = localTimeRecv; responseBuffer.Write(intiatorRemoteTimeRecv); double intiatorRemoteTimeSent = NetTime.Now + m_owner.m_localTimeOffset; responseBuffer.Write(intiatorRemoteTimeSent); if (m_localHailData != null) { responseBuffer.Write(m_localHailData); } SendSingleUnreliableSystemMessage(NetSystemType.ConnectionEstablished, responseBuffer); // send first ping 250ms after connected m_lastSentPing = timestamp - m_owner.Configuration.PingFrequency + 0.1 + (NetRandom.Instance.NextFloat() * 0.25f); m_statistics.Reset(); SetInitialPongEntry(new PongEntry(localTimeSent, remoteTimeRecv, remoteTimeSent, localTimeRecv)); SetStatus(NetConnectionStatus.Connected, "Connected"); break; } case NetSystemType.ConnectionEstablished: { if (m_status != NetConnectionStatus.Connecting) { if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Received connection response but we're not connecting...", this, msg.m_senderEndPoint); } return; } var remoteRndSignature = msg.m_data.ReadBytes(NetConstants.SignatureByteSize); if (!m_owner.Configuration.AllowConnectionToSelf && NetUtility.CompareElements(remoteRndSignature, m_owner.m_localRndSignature)) { // don't allow self-connect if ((m_owner.m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected) { m_owner.NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null, msg.m_senderEndPoint); } return; } int remoteRndSeqNr = msg.m_data.ReadInt32(); if (m_remoteRndSignature != null) { if (!NetUtility.CompareElements(remoteRndSignature, m_remoteRndSignature) || remoteRndSeqNr != m_remoteRndSeqNr) { // this is not the same connection. Disconnect("Not the same connection", 0, false, true); return; } } else // this might happen if both try and connect at the same time. { m_remoteRndSignature = remoteRndSignature; m_remoteRndSeqNr = remoteRndSeqNr; ResetReliability(); } var myRndSignature = msg.m_data.ReadBytes(NetConstants.SignatureByteSize); var myRndSeqNr = msg.m_data.ReadInt32(); if (!NetUtility.CompareElements(myRndSignature, m_owner.m_localRndSignature) || myRndSeqNr != m_localRndSeqNr) { // this is not the same connection. Disconnect("Not the same connection", 0, false, true); return; } double localTimeSent = msg.m_data.ReadDouble(); double remoteTimeRecv = msg.m_data.ReadDouble(); double remoteTimeSent = msg.m_data.ReadDouble(); double localTimeRecv = timestamp + m_owner.m_localTimeOffset; // read hail data if (m_remoteHailData == null) { int hbc = (msg.m_data.LengthBits - msg.m_data.PositionBits) / 8; if (hbc > 0) { m_remoteHailData = msg.m_data.ReadBytes(hbc); } } // send first ping 100-350ms after connected m_lastSentPing = timestamp - m_owner.Configuration.PingFrequency + 0.1 + (NetRandom.Instance.NextFloat() * 0.25f); m_statistics.Reset(); SetInitialPongEntry(new PongEntry(localTimeSent, remoteTimeRecv, remoteTimeSent, localTimeRecv)); SetStatus(NetConnectionStatus.Connected, "Connected"); break; } case NetSystemType.Ping: // also accepted as ConnectionEstablished if (m_isInitiator == false && m_status == NetConnectionStatus.Connecting) { m_owner.LogWrite("Received ping; interpreted as ConnectionEstablished", this); m_statistics.Reset(); SetInitialPongEntryApprox(timestamp - m_handshakeInitiated); SetStatus(NetConnectionStatus.Connected, "Connected"); } if (m_status != NetConnectionStatus.Connected) { m_owner.LogWrite("Received ping but we're not connected...", this); if (m_status == NetConnectionStatus.Disconnected) { // this might cause a issue (especially if both are trying to connect at the same time). Disconnect("We're not connected", 0, true, true); } return; } ReceivedPing(msg, timestamp + m_owner.m_localTimeOffset); break; case NetSystemType.Pong: ReceivedPong(msg, timestamp + m_owner.m_localTimeOffset); break; case NetSystemType.StringTableAck: ushort val = msg.m_data.ReadUInt16(); StringTableAcknowledgeReceived(val); break; default: m_owner.LogWrite("Undefined behavior in NetConnection for system message " + sysType, this); break; } }
internal void NotifyApplication(NetMessageType tp, NetBuffer buffer, NetConnection conn, IPEndPoint ep) { IncomingNetMessage msg = new IncomingNetMessage(); msg.m_data = buffer; msg.m_msgType = tp; msg.m_sender = conn; msg.m_senderEndPoint = ep; lock (m_receivedMessages) m_receivedMessages.Enqueue(msg); }
internal abstract void HandleReceivedMessage(IncomingNetMessage message, IPEndPoint senderEndpoint);
/// <summary> /// Returns true if message should be dropped /// </summary> internal bool HandleNATIntroduction(IncomingNetMessage message) { if (message.m_type == NetMessageLibraryType.System) { if (message.m_data.LengthBytes > 4 && message.m_data.PeekByte() == (byte)NetSystemType.NatIntroduction) { if ((m_enabledMessageTypes & NetMessageType.NATIntroduction) != NetMessageType.NATIntroduction) return true; // drop try { message.m_data.ReadByte(); // step past system type byte IPEndPoint presented = message.m_data.ReadIPEndPoint(); LogVerbose("Received NATIntroduction to " + presented + "; sending punching ping..."); double now = NetTime.Now; NetConnection.SendPing(this, presented, now); if (m_holePunches == null) m_holePunches = new List<IPEndPoint>(); for (int i = 0; i < 5; i++) m_holePunches.Add(new IPEndPoint(presented.Address, presented.Port)); NetBuffer info = CreateBuffer(); info.Write(presented); NotifyApplication(NetMessageType.NATIntroduction, info, message.m_sender, message.m_senderEndPoint); return true; } catch (Exception ex) { NotifyApplication(NetMessageType.BadMessageReceived, "Bad NAT introduction message received: " + ex.Message, message.m_sender, message.m_senderEndPoint); return true; } } } return false; }
/// <summary> /// Process a user message /// </summary> internal void HandleUserMessage(IncomingNetMessage msg, double now) { // also accepted as ConnectionEstablished if (m_isInitiator == false && m_status == NetConnectionStatus.Connecting) { m_owner.LogWrite("Received user message; interpreted as ConnectionEstablished", this); m_statistics.Reset(); SetInitialPongEntryApprox(now - m_handshakeInitiated); SetStatus(NetConnectionStatus.Connected, "Connected"); } if (m_status != NetConnectionStatus.Connected && m_status != NetConnectionStatus.Disconnecting) { m_owner.LogWrite("Received user message but we're not connected...", this); //Disconnect("We're not connected", 0, true, true); // we can't send disconnect because then we fail the redirect test for a reason that needs to be investigated. return; } // // Unreliable // if (msg.m_sequenceChannel == NetChannel.Unreliable) { AcceptMessage(msg); return; } // // Unreliable Sequenced // if (msg.m_sequenceChannel >= NetChannel.UnreliableInOrder1 && msg.m_sequenceChannel <= NetChannel.UnreliableInOrder15) { // relate to expected int seqChanNr = (int)msg.m_sequenceChannel - (int)NetChannel.UnreliableInOrder1; int sdiff = Relate(msg.m_sequenceNumber, m_nextExpectedSequenced[seqChanNr]); if (sdiff < 0) { // Reject late sequenced message m_owner.LogVerbose("Rejecting late sequenced " + msg); m_statistics.CountDroppedSequencedMessage(); return; } AcceptMessage(msg); int nextExpected = msg.m_sequenceNumber + 1; if (nextExpected > NetConstants.NumSequenceNumbers) { nextExpected = 0; } m_nextExpectedSequenced[seqChanNr] = nextExpected; return; } // // Reliable and ReliableOrdered // // Send ack, regardless of anything m_acknowledgesToSend.Enqueue(((int)msg.m_sequenceChannel << 16) | msg.m_sequenceNumber); // relate to all received up to int relChanNr = (int)msg.m_sequenceChannel - (int)NetChannel.ReliableUnordered; int arut = m_allReliableReceivedUpTo[relChanNr]; int diff = Relate(msg.m_sequenceNumber, arut); if (diff < 0) { // Reject duplicate m_statistics.CountDuplicateMessage(msg); m_owner.LogVerbose("Rejecting(1) duplicate reliable " + msg, this); return; } bool isOrdered = (msg.m_sequenceChannel >= NetChannel.ReliableInOrder1); if (arut == msg.m_sequenceNumber) { // Right on time AcceptMessage(msg); PostAcceptReliableMessage(msg, arut); return; } // get bools list we must check BitArray recList = m_reliableReceived[relChanNr]; if (recList == null) { recList = new BitArray(NetConstants.NumSequenceNumbers); m_reliableReceived[relChanNr] = recList; } if (recList[msg.m_sequenceNumber]) { // Reject duplicate m_statistics.CountDuplicateMessage(msg); m_owner.LogVerbose("Rejecting(2) duplicate reliable " + msg, this); return; } // It's an early reliable message if (m_reliableReceived[relChanNr] == null) { m_reliableReceived[relChanNr] = new BitArray(NetConstants.NumSequenceNumbers); } m_reliableReceived[relChanNr][msg.m_sequenceNumber] = true; if (!isOrdered) { AcceptMessage(msg); return; } // Early ordered message; withhold List <IncomingNetMessage> wmlist = m_withheldMessages[relChanNr]; if (wmlist == null) { wmlist = new List <IncomingNetMessage>(); m_withheldMessages[relChanNr] = wmlist; } m_owner.LogVerbose("Withholding " + msg + " (waiting for " + arut + ")", this); wmlist.Add(msg); return; }
/// <summary> /// Process a user message /// </summary> internal void HandleUserMessage(IncomingNetMessage msg) { #if DEBUG if (System.Threading.Thread.CurrentThread != m_owner.m_heartbeatThread) throw new Exception("Threading error; should be heartbeat thread. Please check callstack!"); #endif // // Unreliable // if (msg.m_sequenceChannel == NetChannel.Unreliable) { AcceptMessage(msg); return; } // // Sequenced // if (msg.m_sequenceChannel >= NetChannel.UnreliableInOrder1 && msg.m_sequenceChannel <= NetChannel.UnreliableInOrder15) { // relate to expected int seqChanNr = (int)msg.m_sequenceChannel - (int)NetChannel.UnreliableInOrder1; int sdiff = Relate(msg.m_sequenceNumber, m_nextExpectedSequenced[seqChanNr]); if (sdiff < 0) { // Reject late sequenced message m_owner.LogVerbose("Rejecting late sequenced " + msg); m_statistics.CountDroppedSequencedMessage(); return; } AcceptMessage(msg); int nextExpected = msg.m_sequenceNumber + 1; if (nextExpected > NetConstants.NumSequenceNumbers) nextExpected = 0; m_nextExpectedSequenced[seqChanNr] = nextExpected; return; } // // Reliable and ReliableOrdered // // Send ack, regardless of anything m_acknowledgesToSend.Enqueue(((int)msg.m_sequenceChannel << 16) | msg.m_sequenceNumber); // relate to all received up to int relChanNr = (int)msg.m_sequenceChannel - (int)NetChannel.ReliableUnordered; int arut = m_allReliableReceivedUpTo[relChanNr]; int diff = Relate(msg.m_sequenceNumber, arut); if (diff < 0) { // Reject duplicate m_statistics.CountDuplicateMessage(msg); m_owner.LogVerbose("Rejecting(1) duplicate reliable " + msg, this); return; } bool isOrdered = (msg.m_sequenceChannel >= NetChannel.ReliableInOrder1); if (arut == msg.m_sequenceNumber) { // Right on time AcceptMessage(msg); PostAcceptReliableMessage(msg, arut); return; } // get bools list we must check bool[] recList = m_reliableReceived[relChanNr]; if (recList == null) { recList = new bool[NetConstants.NumSequenceNumbers]; m_reliableReceived[relChanNr] = recList; } if (recList[msg.m_sequenceNumber]) { // Reject duplicate m_statistics.CountDuplicateMessage(msg); m_owner.LogVerbose("Rejecting(2) duplicate reliable " + msg, this); return; } // It's an early reliable message if (m_reliableReceived[relChanNr] == null) m_reliableReceived[relChanNr] = new bool[NetConstants.NumSequenceNumbers]; m_reliableReceived[relChanNr][msg.m_sequenceNumber] = true; if (!isOrdered) { AcceptMessage(msg); return; } // Early ordered message; withhold List<IncomingNetMessage> wmlist = m_withheldMessages[relChanNr]; if (wmlist == null) { wmlist = new List<IncomingNetMessage>(); m_withheldMessages[relChanNr] = wmlist; } m_owner.LogVerbose("Withholding " + msg + " (waiting for " + arut + ")", this); wmlist.Add(msg); return; }
internal void HandleAckMessage(double now, IncomingNetMessage ackMessage) { int len = ackMessage.m_data.LengthBytes; if ((len % 3) != 0) { if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed ack message; length must be multiple of 3; it's " + len, this, ackMessage.m_senderEndPoint); } return; } for (int i = 0; i < len; i += 3) //for each channel + seq nbr in ACK { NetChannel chan = (NetChannel)ackMessage.m_data.ReadByte(); int seqNr = ackMessage.m_data.ReadUInt16(); // LogWrite("Acknowledgement received: " + chan + "|" + seqNr); m_statistics.CountAcknowledgesReceived(1); // remove saved message int relChanNr = (int)chan - (int)NetChannel.ReliableUnordered; if (relChanNr < 0) { if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed ack message; indicated netchannel " + chan, this, ackMessage.m_senderEndPoint); } continue; } List <OutgoingNetMessage> list = m_storedMessages[relChanNr]; if (list != null) { int cnt = list.Count; if (cnt > 0) { for (int j = 0; j < cnt; j++) //for each stored message on channel { OutgoingNetMessage msg = list[j]; if (msg.m_sequenceNumber == seqNr) //find correct message { // if (msg.m_numSent >= 10) UnityEngine.Debug.Log(now + ": Ack for " + msg.m_numSent + ": " + NetUtility.BytesToHex(msg.m_data.ToArray())); //LogWrite("Removed stored message: " + msg); list.RemoveAt(j); // reduce estimated amount of packets on wire //CongestionCountAck(msg.m_packetNumber); // fire receipt if (msg.m_receiptData != null) { m_owner.LogVerbose("Got ack, removed from storage: " + msg + " firing receipt; " + msg.m_receiptData, this); m_owner.FireReceipt(this, msg.m_receiptData); } else { m_owner.LogVerbose("Got ack, removed from storage: " + msg, this); } // recycle msg.m_data.m_refCount--; if (msg.m_data.m_refCount <= 0) { m_owner.RecycleBuffer(msg.m_data); // time to recycle buffer } msg.m_data = null; //m_owner.m_messagePool.Push(msg); #if !NO_NAK if (j > 0) { int k; for (k = 0; k < j; k++) //for each message stored prior to the one matching seq nbr { var m = list[k]; if (m.m_sequenceNumber > seqNr) { break; } // Re-enqueue message in unsent list m_owner.LogVerbose("Implicit NAK Resending " + m + " now: " + NetTime.NowInMillis + " nextResend: " + NetTime.ToMillis(m.m_nextResend), this); m_statistics.CountMessageResent(m.m_type); m_unsentMessages.Enqueue(m); } list.RemoveRange(0, k); } #endif break; //exit stored message loop since this was the message corresponding to seq nbr //now returning to next sequence number in ACK packet } } } } } // recycle NetBuffer rb = ackMessage.m_data; rb.m_refCount = 0; // ack messages can't be used by more than one message ackMessage.m_data = null; m_owner.RecycleBuffer(rb); //m_owner.m_messagePool.Push(ackMessage); }
/// <summary> /// Notify application that a connection changed status /// </summary> internal void NotifyStatusChange(NetConnection connection, string reason) { if ((m_enabledMessageTypes & NetMessageType.StatusChanged) != NetMessageType.StatusChanged) return; // disabled //NotifyApplication(NetMessageType.StatusChanged, reason, connection); NetBuffer buffer = CreateBuffer(reason.Length + 2); buffer.Write(reason); buffer.Write((byte)connection.Status); IncomingNetMessage msg = new IncomingNetMessage(); msg.m_data = buffer; msg.m_msgType = NetMessageType.StatusChanged; msg.m_sender = connection; msg.m_senderEndPoint = null; EnqueueReceivedMessage(msg); }
internal bool VerifyIdentifiers( IncomingNetMessage message, IPEndPoint endPoint, out ushort number ) { number = 0; int payLen = message.m_data.LengthBytes; if (payLen < 13) { if ((m_netBase.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) m_netBase.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed Discovery message received from " + endPoint, null, message.m_senderEndPoint); return false; } // check app identifier string appIdent2 = message.m_data.ReadString(); if (appIdent2 != m_netBase.m_config.ApplicationIdentifier) { if ((m_netBase.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) m_netBase.NotifyApplication(NetMessageType.BadMessageReceived, "Discovery for different application identification received: " + appIdent2, null, message.m_senderEndPoint); return false; } // check netbase identifier byte[] nbid = message.m_data.ReadBytes(m_netBase.m_randomIdentifier.Length); if (NetUtility.CompareElements(nbid, m_netBase.m_randomIdentifier)) return false; // don't respond to your own discovery request // retrieve number number = message.m_data.ReadUInt16(); // it's ok return true; }
internal abstract void HandleReceivedMessage(IncomingNetMessage message, IPEndPoint senderEndpoint);
/// <summary> /// Returns a NetMessage to return to application; or null if nothing /// </summary> internal IncomingNetMessage HandleResponse( IncomingNetMessage message, IPEndPoint endPoint ) { if ((m_netBase.m_enabledMessageTypes & NetMessageType.ServerDiscovered) != NetMessageType.ServerDiscovered) return null; // disabled if (message.m_data == null || m_requests == null) return null; ushort number = message.m_data.ReadUInt16(); // find corresponding request NetDiscoveryRequest found = null; foreach (NetDiscoveryRequest request in m_requests) { if (request.Number == number) { found = request; break; } } if (found == null) { m_netBase.LogVerbose("Received discovery response to request " + number + " - unknown/old request!"); return null; // Timed out request or not found } if (found.HasDiscovered(endPoint)) { m_netBase.LogVerbose("Received discovery response to request " + number + " - previously known response!"); return null; // Already discovered in this request, else stored it } m_netBase.LogVerbose("Received discovery response to request " + number + " - passing on to app..."); IncomingNetMessage resMsg = m_netBase.CreateIncomingMessage(); resMsg.m_msgType = NetMessageType.ServerDiscovered; // write sender, assume ipv4 resMsg.m_data.Write(endPoint); return resMsg; }
internal void HandleAckMessage(IncomingNetMessage ackMessage) { int len = ackMessage.m_data.LengthBytes; if ((len % 3) != 0) { if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed ack message; length must be multiple of 3; it's " + len, this, ackMessage.m_senderEndPoint); } return; } for (int i = 0; i < len; i += 3) { NetChannel chan = (NetChannel)ackMessage.m_data.ReadByte(); int seqNr = ackMessage.m_data.ReadUInt16(); // LogWrite("Acknowledgement received: " + chan + "|" + seqNr); m_statistics.CountAcknowledgesReceived(1); // remove saved message int chanIdx = (int)chan - (int)NetChannel.ReliableUnordered; if (chanIdx < 0) { if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed ack message; indicated netchannel " + chan, this, ackMessage.m_senderEndPoint); } continue; } List <OutgoingNetMessage> list = m_storedMessages[chanIdx]; if (list != null) { int cnt = list.Count; if (cnt > 0) { for (int o = 0; o < cnt; o++) { OutgoingNetMessage msg = list[o]; if (msg.m_sequenceNumber == seqNr) { //LogWrite("Removed stored message: " + msg); list.RemoveAt(o); // reduce estimated amount of packets on wire //CongestionCountAck(msg.m_packetNumber); // fire receipt if (msg.m_receiptData != null) { m_owner.LogVerbose("Got ack, removed from storage: " + msg + " firing receipt; " + msg.m_receiptData, this); m_owner.FireReceipt(this, msg.m_receiptData); } else { m_owner.LogVerbose("Got ack, removed from storage: " + msg, this); } // recycle msg.m_data.m_refCount--; if (msg.m_data.m_refCount <= 0) { m_owner.RecycleBuffer(msg.m_data); // time to recycle buffer } msg.m_data = null; //m_owner.m_messagePool.Push(msg); break; } } } } } // recycle NetBuffer rb = ackMessage.m_data; rb.m_refCount = 0; // ack messages can't be used by more than one message ackMessage.m_data = null; m_owner.RecycleBuffer(rb); //m_owner.m_messagePool.Push(ackMessage); }
/* * internal void HandleUserMessage(NetMessage msg) * { * int seqNr = msg.m_sequenceNumber; * int chanNr = (int)msg.m_sequenceChannel; * bool isDuplicate = false; * * int relation = RelateToExpected(seqNr, chanNr, out isDuplicate); * * // * // Unreliable * // * if (msg.m_sequenceChannel == NetChannel.Unreliable) * { * // It's all good; add message * if (isDuplicate) * { * m_statistics.CountDuplicateMessage(msg); * m_owner.LogVerbose("Rejecting duplicate " + msg, this); * } * else * { * AcceptMessage(msg); * } * return; * } * * // * // Reliable unordered * // * if (msg.m_sequenceChannel == NetChannel.ReliableUnordered) * { * // send acknowledge (even if duplicate) * m_acknowledgesToSend.Enqueue((chanNr << 16) | msg.m_sequenceNumber); * * if (isDuplicate) * { * m_statistics.CountDuplicateMessage(msg); * m_owner.LogVerbose("Rejecting duplicate " + msg, this); * return; // reject duplicates * } * * // It's good; add message * AcceptMessage(msg); * * return; * } * * ushort nextSeq = (ushort)(seqNr + 1); * * if (chanNr < (int)NetChannel.ReliableInOrder1) * { * // * // Sequenced * // * if (relation < 0) * { * // late sequenced message * m_statistics.CountDroppedSequencedMessage(); * m_owner.LogVerbose("Dropping late sequenced " + msg, this); * return; * } * * // It's good; add message * AcceptMessage(msg); * * m_nextExpectedSequence[chanNr] = nextSeq; * return; * } * else * { * // * // Ordered * // * * // send ack (regardless) * m_acknowledgesToSend.Enqueue((chanNr << 16) | msg.m_sequenceNumber); * * if (relation < 0) * { * // late ordered message #if DEBUG * if (!isDuplicate) * m_owner.LogWrite("Ouch, weird! Late ordered message that's NOT a duplicate?! seqNr: " + seqNr + " expecting: " + m_nextExpectedSequence[chanNr], this); #endif * // must be duplicate * m_owner.LogVerbose("Dropping duplicate message " + seqNr, this); * m_statistics.CountDuplicateMessage(msg); * return; // rejected; don't advance next expected * } * * if (relation > 0) * { * // early message; withhold ordered * m_owner.LogVerbose("Withholding " + msg + " (expecting " + m_nextExpectedSequence[chanNr] + ")", this); * m_withheldMessages.Add(msg); * return; // return without advancing next expected * } * * // It's right on time! * AcceptMessage(msg); * * // ordered; release other withheld messages? * bool released = false; * do * { * released = false; * foreach (NetMessage wm in m_withheldMessages) * { * if ((int)wm.m_sequenceChannel == chanNr && wm.m_sequenceNumber == nextSeq) * { * m_owner.LogVerbose("Releasing withheld message " + wm, this); * m_withheldMessages.Remove(wm); * AcceptMessage(wm); * // no need to set rounds for this message; it was one when first related() and withheld * nextSeq++; * if (nextSeq >= NetConstants.NumSequenceNumbers) * nextSeq -= NetConstants.NumSequenceNumbers; * released = true; * break; * } * } * } while (released); * } * * // Common to Sequenced and Ordered * * //m_owner.LogVerbose("Setting next expected for " + (NetChannel)chanNr + " to " + nextSeq); * m_nextExpectedSequence[chanNr] = nextSeq; * * return; * } */ internal void HandleSystemMessage(IncomingNetMessage msg, double now) { msg.m_data.Position = 0; NetSystemType sysType = (NetSystemType)msg.m_data.ReadByte(); OutgoingNetMessage response = null; switch (sysType) { case NetSystemType.Disconnect: if (m_status == NetConnectionStatus.Disconnected) { return; } Disconnect(msg.m_data.ReadString(), 0.75f + ((float)m_currentAvgRoundtrip * 4), false, false); break; case NetSystemType.ConnectionRejected: string reason = msg.m_data.ReadString(); m_owner.NotifyApplication(NetMessageType.ConnectionRejected, reason, msg.m_sender, msg.m_senderEndPoint); Disconnect(reason, 0.0f, false, true); break; case NetSystemType.Connect: // ConnectReponse must have been losts string appIdent = msg.m_data.ReadString(); if (appIdent != m_owner.m_config.ApplicationIdentifier) { if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Connect for different application identification received: " + appIdent, null, msg.m_senderEndPoint); } return; } // read random identifer byte[] rnd = msg.m_data.ReadBytes(8); if (NetUtility.CompareElements(rnd, m_owner.m_randomIdentifier)) { // don't allow self-connect if ((m_owner.m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected) { m_owner.NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null, msg.m_senderEndPoint); } return; } // read hail data m_remoteHailData = null; int hailBytesCount = (msg.m_data.LengthBits - msg.m_data.Position) / 8; if (hailBytesCount > 0) { m_remoteHailData = msg.m_data.ReadBytes(hailBytesCount); } // finalize disconnect if it's in process if (m_status == NetConnectionStatus.Disconnecting) { FinalizeDisconnect(); } // send response; even if connected response = m_owner.CreateSystemMessage(NetSystemType.ConnectResponse); if (m_localHailData != null) { response.m_data.Write(m_localHailData); } m_unsentMessages.Enqueue(response); break; case NetSystemType.ConnectResponse: if (m_status != NetConnectionStatus.Connecting && m_status != NetConnectionStatus.Connected) { m_owner.LogWrite("Received connection response but we're not connecting...", this); return; } // read hail data m_remoteHailData = null; int numHailBytes = (msg.m_data.LengthBits - msg.m_data.Position) / 8; if (numHailBytes > 0) { m_remoteHailData = msg.m_data.ReadBytes(numHailBytes); } // Send connectionestablished response = m_owner.CreateSystemMessage(NetSystemType.ConnectionEstablished); if (m_localHailData != null) { response.m_data.Write(m_localHailData); } m_unsentMessages.Enqueue(response); // send first ping 250ms after connected m_lastSentPing = now - m_owner.Configuration.PingFrequency + 0.1 + (NetRandom.Instance.NextFloat() * 0.25f); m_statistics.Reset(); SetInitialAveragePing(now - m_handshakeInitiated); SetStatus(NetConnectionStatus.Connected, "Connected"); break; case NetSystemType.ConnectionEstablished: if (m_status != NetConnectionStatus.Connecting) { if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Received connection response but we're not connecting...", this, msg.m_senderEndPoint); } return; } // read hail data if (m_remoteHailData == null) { int hbc = (msg.m_data.LengthBits - msg.m_data.Position) / 8; if (hbc > 0) { m_remoteHailData = msg.m_data.ReadBytes(hbc); } } // send first ping 100-350ms after connected m_lastSentPing = now - m_owner.Configuration.PingFrequency + 0.1 + (NetRandom.Instance.NextFloat() * 0.25f); m_statistics.Reset(); SetInitialAveragePing(now - m_handshakeInitiated); SetStatus(NetConnectionStatus.Connected, "Connected"); break; case NetSystemType.Ping: // also accepted as ConnectionEstablished if (m_isInitiator == false && m_status == NetConnectionStatus.Connecting) { m_owner.LogWrite("Received ping; interpreted as ConnectionEstablished", this); m_statistics.Reset(); SetInitialAveragePing(now - m_handshakeInitiated); SetStatus(NetConnectionStatus.Connected, "Connected"); } //LogWrite("Received ping; sending pong..."); SendPong(m_owner, m_remoteEndPoint, now); break; case NetSystemType.Pong: double twoWayLatency = now - m_lastSentPing; if (twoWayLatency < 0) { break; } ReceivedPong(twoWayLatency, msg); break; case NetSystemType.StringTableAck: ushort val = msg.m_data.ReadUInt16(); StringTableAcknowledgeReceived(val); break; default: m_owner.LogWrite("Undefined behaviour in NetConnection for system message " + sysType, this); break; } }
internal abstract void HandleReceivedMessage(IncomingNetMessage message, NetworkEndPoint senderEndpoint, double timestamp);
/// <summary> /// Reads all packets and create messages /// </summary> protected void BaseHeartbeat(double now) { if (!m_isBound) { return; } // discovery m_discovery.Heartbeat(now); // hole punching if (m_holePunches != null) { if (now > m_lastHolePunch + NetConstants.HolePunchingFrequency) { if (m_holePunches.Count <= 0) { m_holePunches = null; } else { IPEndPoint dest = m_holePunches[0]; m_holePunches.RemoveAt(0); NotifyApplication(NetMessageType.DebugMessage, "Sending hole punch to " + dest, null); NetConnection.SendPing(this, dest, now); if (m_holePunches.Count < 1) { m_holePunches = null; } m_lastHolePunch = now; } } } // Send queued system messages if (m_susmQueue.Count > 0) { lock (m_susmQueue) { while (m_susmQueue.Count > 0) { SUSystemMessage su = m_susmQueue.Dequeue(); SendSingleUnreliableSystemMessage(su.Type, su.Data, su.Destination, su.UseBroadcast); } } } // Send out-of-band messages if (m_unsentOutOfBandMessages.Count > 0) { lock (m_unsentOutOfBandMessages) { while (m_unsentOutOfBandMessages.Count > 0) { NetBuffer buf = m_unsentOutOfBandMessages.Dequeue(); IPEndPoint ep = m_unsentOutOfBandRecipients.Dequeue(); DoSendOutOfBandMessage(buf, ep); } } } try { #if DEBUG SendDelayedPackets(now); #endif while (true) { if (m_socket == null || m_socket.Available < 1) { return; } m_receiveBuffer.Reset(); int bytesReceived = 0; try { bytesReceived = m_socket.ReceiveFrom(m_receiveBuffer.Data, 0, m_receiveBuffer.Data.Length, SocketFlags.None, ref m_senderRemote); } catch (SocketException) { // no good response to this yet return; } if (bytesReceived < 1) { return; } if (bytesReceived > 0) { m_statistics.CountPacketReceived(bytesReceived); } m_receiveBuffer.LengthBits = bytesReceived * 8; //LogVerbose("Read packet: " + bytesReceived + " bytes"); IPEndPoint ipsender = (IPEndPoint)m_senderRemote; NetConnection sender = GetConnection(ipsender); if (sender != null) { sender.m_statistics.CountPacketReceived(bytesReceived, now); } // create messages from packet while (m_receiveBuffer.Position < m_receiveBuffer.LengthBits) { int beginPosition = m_receiveBuffer.Position; // read message header IncomingNetMessage msg = CreateIncomingMessage(); msg.m_sender = sender; msg.ReadFrom(m_receiveBuffer, ipsender); // statistics if (sender != null) { sender.m_statistics.CountMessageReceived(msg.m_type, msg.m_sequenceChannel, (m_receiveBuffer.Position - beginPosition) / 8, now); } // handle message HandleReceivedMessage(msg, ipsender); } } } catch (SocketException sex) { if (sex.ErrorCode == 10054) { // forcibly closed; but m_senderRemote is unreliable, we can't trust it! //NetConnection conn = GetConnection((IPEndPoint)m_senderRemote); //HandleConnectionForciblyClosed(conn, sex); return; } } catch (Exception ex) { throw new NetException("ReadPacket() exception", ex); } }
/* * /// <summary> * /// Read any received message in any connection queue * /// </summary> * public NetBuffer ReadMessage(out NetConnection sender) * { * if (m_receivedMessages.Count < 1) * { * sender = null; * return null; * } * * NetMessage msg = m_receivedMessages.Dequeue(); * sender = msg.m_sender; * * NetBuffer retval = msg.m_data; * msg.m_data = null; * m_messagePool.Push(msg); * * Debug.Assert(retval.Position == 0); * * return retval; * } */ /// <summary> /// Read any received message in any connection queue /// </summary> public bool ReadMessage( NetBuffer intoBuffer, IList <NetConnection> onlyFor, bool includeNullConnectionMessages, out NetMessageType type, out NetConnection sender) { if (m_receivedMessages.Count < 1) { sender = null; type = NetMessageType.None; return(false); } IncomingNetMessage msg = null; lock (m_receivedMessages) { int sz = m_receivedMessages.Count; for (int i = 0; i < sz; i++) { msg = m_receivedMessages.Peek(i); if (msg != null) { if ((msg.m_sender == null && includeNullConnectionMessages) || onlyFor.Contains(msg.m_sender)) { m_receivedMessages.Dequeue(i); break; } msg = null; } } } if (msg == null) { sender = null; type = NetMessageType.None; return(false); } sender = msg.m_sender; // recycle NetMessage object NetBuffer content = msg.m_data; msg.m_data = null; type = msg.m_msgType; // m_messagePool.Push(msg); Debug.Assert(content.Position == 0); // swap content of buffers byte[] tmp = intoBuffer.Data; intoBuffer.Data = content.Data; content.Data = tmp; // set correct values for returning value (ignore the other, it's being recycled anyway) intoBuffer.m_bitLength = content.m_bitLength; intoBuffer.m_readPosition = 0; // recycle NetBuffer object (incl. old intoBuffer byte array) RecycleBuffer(content); return(true); }
internal override void HandleReceivedMessage(IncomingNetMessage message, NetworkEndPoint senderEndpoint, double timestamp) { double now = NetTime.Now; int payLen = message.m_data.LengthBytes; // Out of band? if (message.m_type == NetMessageLibraryType.OutOfBand) { if ((m_enabledMessageTypes & NetMessageType.OutOfBandData) != NetMessageType.OutOfBandData) { return; // drop } // just deliver message.m_msgType = NetMessageType.OutOfBandData; message.m_senderEndPoint = senderEndpoint; EnqueueReceivedMessage(message); return; } if (message.m_sender == null) { // // Handle unconnected message // // not a connected sender; only allow System messages if (message.m_type != NetMessageLibraryType.System) { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Rejecting non-system message from unconnected source: " + message, null, message.m_senderEndPoint); } return; } // read type of system message NetSystemType sysType = (NetSystemType)message.m_data.ReadByte(); switch (sysType) { case NetSystemType.Connect: LogVerbose("Connection request received from " + senderEndpoint); NetConnection conn; if (m_pendingLookup.TryGetValue(senderEndpoint, out conn)) { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Ignore connection request received because already pending", conn, senderEndpoint); } return; } if (m_connectionLookup.TryGetValue(senderEndpoint, out conn)) { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Ignore connection request received because already connected", conn, senderEndpoint); } return; } // check app id if (payLen < 4) { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Malformed Connect message received from " + senderEndpoint, null, senderEndpoint); } return; } string appIdent = message.m_data.ReadString(); if (appIdent != m_config.ApplicationIdentifier) { if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected) { NotifyApplication(NetMessageType.ConnectionRejected, "Bad app id", null, senderEndpoint); } // send connection rejected NetBuffer rejreason = new NetBuffer("Bad app id"); QueueSingleUnreliableSystemMessage( NetSystemType.ConnectionRejected, rejreason, senderEndpoint, false ); return; } // read random identifer var rndSignature = message.m_data.ReadBytes(NetConstants.SignatureByteSize); if (NetUtility.CompareElements(rndSignature, m_localRndSignature)) { // don't allow self-connect if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected) { NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null, senderEndpoint); } return; } int rndSeqNr = message.m_data.ReadInt32(); double localTimeSent = message.m_data.ReadDouble(); double remoteTimeRecv = timestamp + m_localTimeOffset; int bytesReadSoFar = message.m_data.PositionBytes; int hailLen = message.m_data.LengthBytes - bytesReadSoFar; byte[] hailData = null; if (hailLen > 0) { hailData = new byte[hailLen]; Buffer.BlockCopy(message.m_data.Data, bytesReadSoFar, hailData, 0, hailLen); } if (m_config.m_maxConnections != -1 && m_connections.Count >= m_config.m_maxConnections) { if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected) { NotifyApplication(NetMessageType.ConnectionRejected, "Max connections", null, senderEndpoint); } // send connection rejected NetBuffer rejreason = new NetBuffer("Server full"); QueueSingleUnreliableSystemMessage( NetSystemType.ConnectionRejected, rejreason, senderEndpoint, false ); return; } #if LIMITED_BUILD if (m_connections.Count >= 2) { if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected) { NotifyApplication(NetMessageType.ConnectionRejected, "I'm special", null, senderEndpoint); } // send connection rejected NetBuffer rejreason = new NetBuffer("Special server"); QueueSingleUnreliableSystemMessage( NetSystemType.ConnectionRejected, rejreason, senderEndpoint, false ); return; } #endif // Create connection LogWrite("New connection: " + senderEndpoint); conn = new NetConnection(this, senderEndpoint, null, hailData, rndSignature, rndSeqNr); m_pendingLookup.Add(senderEndpoint, conn); conn.m_connectLocalSentTime = localTimeSent; conn.m_connectRemoteRecvTime = remoteTimeRecv; // Connection approval? if ((m_enabledMessageTypes & NetMessageType.ConnectionApproval) == NetMessageType.ConnectionApproval) { // Ask application if this connection is allowed to proceed IncomingNetMessage app = CreateIncomingMessage(); app.m_msgType = NetMessageType.ConnectionApproval; if (hailData != null) { app.m_data.Write(hailData); } app.m_sender = conn; conn.m_approved = false; EnqueueReceivedMessage(app); // Don't add connection; it's done as part of the approval procedure return; } // it's ok AddConnection(now, conn); break; case NetSystemType.ConnectionEstablished: if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Connection established received from non-connection! " + senderEndpoint, null, senderEndpoint); } return; case NetSystemType.Discovery: if (m_config.AnswerDiscoveryRequests) { m_discovery.HandleRequest(message, senderEndpoint); } break; case NetSystemType.DiscoveryResponse: if (m_allowOutgoingConnections) { // NetPeer IncomingNetMessage resMsg = m_discovery.HandleResponse(message, senderEndpoint); if (resMsg != null) { resMsg.m_senderEndPoint = senderEndpoint; EnqueueReceivedMessage(resMsg); } } break; case NetSystemType.Ping: { var tempBuffer = GetTempBuffer(); tempBuffer.Write("We're not connected"); SendSingleUnreliableSystemMessage( NetSystemType.Disconnect, tempBuffer, senderEndpoint, null ); if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Ignore " + this + " receiving system type " + sysType + ": " + message + " from unconnected source", null, senderEndpoint); } break; } default: if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Ignore " + this + " receiving system type " + sysType + ": " + message + " from unconnected source", null, senderEndpoint); } break; } // done return; } // ok, we have a sender if (message.m_type == NetMessageLibraryType.Acknowledge) { message.m_sender.HandleAckMessage(now, message); return; } if (message.m_type == NetMessageLibraryType.System) { // // Handle system messages from connected source // if (payLen < 1) { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Received malformed system message; payload length less than 1 byte", null, senderEndpoint); } return; } NetSystemType sysType = (NetSystemType)message.m_data.ReadByte(); switch (sysType) { case NetSystemType.Connect: case NetSystemType.ConnectionEstablished: case NetSystemType.Ping: case NetSystemType.Pong: case NetSystemType.Disconnect: case NetSystemType.ConnectionRejected: case NetSystemType.StringTableAck: message.m_sender.HandleSystemMessage(message, now); break; case NetSystemType.ConnectResponse: if (m_allowOutgoingConnections) { message.m_sender.HandleSystemMessage(message, now); } else { if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for server and system type " + sysType, null, senderEndpoint); } } break; case NetSystemType.Discovery: // Allow discovery even if connected if (m_config.AnswerDiscoveryRequests) { m_discovery.HandleRequest(message, senderEndpoint); } break; default: if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) { NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for server and system type " + sysType, null, senderEndpoint); } break; } return; } message.m_sender.HandleUserMessage(message, now); }
/// <summary> /// Process a user message /// </summary> internal void HandleUserMessage(IncomingNetMessage msg) { #if DEBUG if (System.Threading.Thread.CurrentThread != m_owner.m_heartbeatThread) { throw new Exception("Threading error; should be heartbeat thread. Please check callstack!"); } #endif // // Unreliable // if (msg.m_sequenceChannel == NetChannel.Unreliable) { AcceptMessage(msg); return; } // // Sequenced // if (msg.m_sequenceChannel >= NetChannel.UnreliableInOrder1 && msg.m_sequenceChannel <= NetChannel.UnreliableInOrder15) { // relate to expected int seqChanNr = (int)msg.m_sequenceChannel - (int)NetChannel.UnreliableInOrder1; int sdiff = Relate(msg.m_sequenceNumber, m_nextExpectedSequenced[seqChanNr]); if (sdiff < 0) { // Reject late sequenced message m_owner.LogVerbose("Rejecting late sequenced " + msg); m_statistics.CountDroppedSequencedMessage(); return; } AcceptMessage(msg); int nextExpected = msg.m_sequenceNumber + 1; if (nextExpected > NetConstants.NumSequenceNumbers) { nextExpected = 0; } m_nextExpectedSequenced[seqChanNr] = nextExpected; return; } // // Reliable and ReliableOrdered // // Send ack, regardless of anything m_acknowledgesToSend.Enqueue(((int)msg.m_sequenceChannel << 16) | msg.m_sequenceNumber); // relate to all received up to int relChanNr = (int)msg.m_sequenceChannel - (int)NetChannel.ReliableUnordered; int arut = m_allReliableReceivedUpTo[relChanNr]; int diff = Relate(msg.m_sequenceNumber, arut); if (diff < 0) { // Reject duplicate m_statistics.CountDuplicateMessage(msg); m_owner.LogVerbose("Rejecting(1) duplicate reliable " + msg, this); return; } bool isOrdered = (msg.m_sequenceChannel >= NetChannel.ReliableInOrder1); if (arut == msg.m_sequenceNumber) { // Right on time AcceptMessage(msg); PostAcceptReliableMessage(msg, arut); return; } // get bools list we must check bool[] recList = m_reliableReceived[relChanNr]; if (recList == null) { recList = new bool[NetConstants.NumSequenceNumbers]; m_reliableReceived[relChanNr] = recList; } if (recList[msg.m_sequenceNumber]) { // Reject duplicate m_statistics.CountDuplicateMessage(msg); m_owner.LogVerbose("Rejecting(2) duplicate reliable " + msg, this); return; } // It's an early reliable message if (m_reliableReceived[relChanNr] == null) { m_reliableReceived[relChanNr] = new bool[NetConstants.NumSequenceNumbers]; } m_reliableReceived[relChanNr][msg.m_sequenceNumber] = true; if (!isOrdered) { AcceptMessage(msg); return; } // Early ordered message; withhold List <IncomingNetMessage> wmlist = m_withheldMessages[relChanNr]; if (wmlist == null) { wmlist = new List <IncomingNetMessage>(); m_withheldMessages[relChanNr] = wmlist; } m_owner.LogVerbose("Withholding " + msg + " (waiting for " + arut + ")", this); wmlist.Add(msg); return; }
internal void HandleAckMessage(IncomingNetMessage ackMessage) { int len = ackMessage.m_data.LengthBytes; if ((len % 3) != 0) { if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed ack message; length must be multiple of 3; it's " + len, this, ackMessage.m_senderEndPoint); return; } for (int i = 0; i < len; i += 3) { NetChannel chan = (NetChannel)ackMessage.m_data.ReadByte(); int seqNr = ackMessage.m_data.ReadUInt16(); // LogWrite("Acknowledgement received: " + chan + "|" + seqNr); m_statistics.CountAcknowledgesReceived(1); // remove saved message int chanIdx = (int)chan - (int)NetChannel.ReliableUnordered; if (chanIdx < 0) { if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived) m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed ack message; indicated netchannel " + chan, this, ackMessage.m_senderEndPoint); continue; } List<OutgoingNetMessage> list = m_storedMessages[chanIdx]; if (list != null) { int cnt = list.Count; if (cnt > 0) { for (int o = 0; o < cnt; o++) { OutgoingNetMessage msg = list[o]; if (msg.m_sequenceNumber == seqNr) { //LogWrite("Removed stored message: " + msg); list.RemoveAt(o); // reduce estimated amount of packets on wire //CongestionCountAck(msg.m_packetNumber); // fire receipt if (msg.m_receiptData != null) { m_owner.LogVerbose("Got ack, removed from storage: " + msg + " firing receipt; " + msg.m_receiptData, this); m_owner.FireReceipt(this, msg.m_receiptData); } else { m_owner.LogVerbose("Got ack, removed from storage: " + msg, this); } // recycle msg.m_data.m_refCount--; if (msg.m_data.m_refCount <= 0) m_owner.RecycleBuffer(msg.m_data); // time to recycle buffer msg.m_data = null; //m_owner.m_messagePool.Push(msg); break; } } } } } // recycle NetBuffer rb = ackMessage.m_data; rb.m_refCount = 0; // ack messages can't be used by more than one message ackMessage.m_data = null; m_owner.RecycleBuffer(rb); //m_owner.m_messagePool.Push(ackMessage); }
internal void EnqueueReceivedMessage(IncomingNetMessage msg) { lock (m_receivedMessages) { m_receivedMessages.Enqueue(msg); } m_dataReceivedEvent.Set(); }