/// <summary> /// Recycles a NetIncomingMessage instance for reuse; taking pressure off the garbage collector /// </summary> public void Recycle(NetIncomingMessage msg) { if (m_incomingMessagesPool == null) { return; } NetException.Assert(m_incomingMessagesPool.Contains(msg) == false, "Recyling already recycled message! Thread race?"); byte[] storage = msg.m_data; msg.m_data = null; Recycle(storage); msg.Reset(); m_incomingMessagesPool.Enqueue(msg); }
/// <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; lock (m_receivedMessages) m_receivedMessages.Enqueue(msg); }
/// <summary> /// Recycle the message to the library for reuse /// </summary> public void Recycle(NetIncomingMessage msg) { if (msg == null) { throw new ArgumentNullException("msg"); } if (msg.m_status != NetIncomingMessageReleaseStatus.ReleasedToApplication) { throw new NetException("Message not under application control; recycled more than once?"); } msg.m_status = NetIncomingMessageReleaseStatus.RecycledByApplication; if (msg.m_data != null) { lock (m_storagePool) { #if DEBUG if (m_storagePool.Contains(msg.m_data)) { throw new NetException("Storage pool object recycled twice!"); } #endif m_storedBytes += msg.m_data.Length; m_storagePool.Add(msg.m_data); } msg.m_data = null; } m_incomingMessagesPool.Enqueue(msg); }
internal void Recycle(NetOutgoingMessage msg) { if (m_outgoingMessagesPool == null) { return; } NetException.Assert(msg.m_recyclingCount == 0, "Wrong recycling count! Should be zero"); NetException.Assert(m_outgoingMessagesPool.Contains(msg) == false, "Recyling already recycled message! Thread race?"); byte[] storage = msg.m_data; msg.m_data = null; // message fragments cannot be recycled // TODO: find a way to recycle large message after all fragments has been acknowledged; or? possibly better just to garbage collect them if (msg.m_fragmentGroup == 0) { Recycle(storage); } msg.Reset(); if (m_outgoingMessagesPool.Count < m_maxCacheCount) { m_outgoingMessagesPool.Enqueue(msg); } }
internal void Recycle(NetOutgoingMessage msg) { if (m_outgoingMessagesPool == null) { return; } #if DEBUG NetException.Assert(m_outgoingMessagesPool.Contains(msg) == false, "Recyling already recycled outgoing message! Thread race?"); if (msg.m_recyclingCount != 0) { LogWarning("Wrong recycling count! should be zero; found " + msg.m_recyclingCount); } #endif // setting m_recyclingCount to zero SHOULD be an unnecessary maneuver, if it's not zero something is wrong // however, in RELEASE, we'll just have to accept this and move on with life msg.m_recyclingCount = 0; byte[] storage = msg.m_data; msg.m_data = null; // message fragments cannot be recycled // TODO: find a way to recycle large message after all fragments has been acknowledged; or? possibly better just to garbage collect them if (msg.m_fragmentGroup == 0) { Recycle(storage); } msg.Reset(); if (m_outgoingMessagesPool.Count < m_maxCacheCount) { m_outgoingMessagesPool.Enqueue(msg); } }
internal void ReleaseMessage(NetIncomingMessage msg) { NetException.Assert(msg.m_incomingMessageType != NetIncomingMessageType.Error); if (msg.m_isFragment) { HandleReleasedFragment(msg); return; } m_releasedIncomingMessages.Enqueue(msg); if (m_messageReceivedEvent != null) { m_messageReceivedEvent.Set(); } if (m_receiveCallbacks != null) { foreach (var tuple in m_receiveCallbacks) { tuple.Item1.Post(tuple.Item2, this); } } }
internal void ReleaseMessage(NetIncomingMessage msg) { NetException.Assert(msg.m_incomingMessageType != NetIncomingMessageType.Error); if (msg.m_isFragment) { HandleReleasedFragment(msg); return; } m_releasedIncomingMessages.Enqueue(msg); if (m_messageReceivedEvent != null) { m_messageReceivedEvent.Set(); } if (m_receiveCallbacks != null) { int ct = m_receiveCallbacks.Count; for (int i = 0; i < ct; ++i) { var tuple = m_receiveCallbacks[i]; tuple.Item1.Post(tuple.Item2, this); } } }
internal void Recycle(NetOutgoingMessage msg) { if (m_outgoingMessagesPool == null) { return; } #if DEBUG if (m_outgoingMessagesPool.Contains(msg)) { throw new NetException("Recyling already recycled message! Thread race?"); } #endif byte[] storage = msg.m_data; msg.m_data = null; // message fragments cannot be recycled // TODO: find a way to recycle large message after all fragments has been acknowledged; or? possibly better just to garbage collect them if (msg.m_fragmentGroup == 0) { Recycle(storage); } msg.Reset(); m_outgoingMessagesPool.Enqueue(msg); }
/// <summary> /// Send a single, out-of-band unreliable message /// </summary> public void SendOutOfBandMessage(NetBuffer data, IPEndPoint recipient) { lock (m_unsentOutOfBandMessages) { m_unsentOutOfBandMessages.Enqueue(data); m_unsentOutOfBandRecipients.Enqueue(recipient); } }
internal void EnqueueReceivedMessage(IncomingNetMessage msg) { lock (m_receivedMessages) { m_receivedMessages.Enqueue(msg); } m_dataReceivedEvent.Set(); }
/// <summary> /// Recycles a NetIncomingMessage instance for reuse; taking pressure off the garbage collector /// </summary> public void Recycle(NetIncomingMessage msg) { if (m_incomingMessagesPool == null) { return; } #if DEBUG if (m_incomingMessagesPool.Contains(msg)) { throw new NetException("Recyling already recycled message! Thread race?"); } #endif byte[] storage = msg.m_data; msg.m_data = null; Recycle(storage); msg.Reset(); m_incomingMessagesPool.Enqueue(msg); }
// received a library message while Connected internal void ReceivedLibraryMessage(NetMessageType tp, int ptr, int payloadLength) { m_peer.VerifyNetworkThread(); float now = (float)NetTime.Now; switch (tp) { case NetMessageType.Disconnect: NetIncomingMessage msg = m_peer.SetupReadHelperMessage(ptr, payloadLength); ExecuteDisconnect(msg.ReadString(), false); break; case NetMessageType.Acknowledge: for (int i = 0; i < payloadLength; i += 3) { NetMessageType acktp = (NetMessageType)m_peer.m_receiveBuffer[ptr++]; // netmessagetype int seqNr = m_peer.m_receiveBuffer[ptr++]; seqNr |= (m_peer.m_receiveBuffer[ptr++] << 8); // need to enqueue this and handle it in the netconnection heartbeat; so be able to send resends together with normal sends m_queuedIncomingAcks.Enqueue(new NetTuple <NetMessageType, int>(acktp, seqNr)); } break; case NetMessageType.Ping: int pingNr = m_peer.m_receiveBuffer[ptr++]; SendPong(pingNr); break; case NetMessageType.Pong: NetIncomingMessage pmsg = m_peer.SetupReadHelperMessage(ptr, payloadLength); int pongNr = pmsg.ReadByte(); float remoteSendTime = pmsg.ReadSingle(); ReceivedPong(now, pongNr, remoteSendTime); break; case NetMessageType.ExpandMTURequest: SendMTUSuccess(payloadLength); break; case NetMessageType.ExpandMTUSuccess: NetIncomingMessage emsg = m_peer.SetupReadHelperMessage(ptr, payloadLength); int size = emsg.ReadInt32(); HandleExpandMTUSuccess(now, size); break; case NetMessageType.NatIntroduction: // Unusual situation where server is actually already known, but got a nat introduction - oh well, lets handle it as usual m_peer.HandleNatIntroduction(ptr); break; default: m_peer.LogWarning("Connection received unhandled library message: " + tp); break; } }
internal void ReleaseMessage(NetIncomingMessage msg) { NetException.Assert(msg.m_incomingMessageType != NetIncomingMessageType.Error); if (msg.m_isFragment) { HandleReleasedFragment(msg); return; } m_releasedIncomingMessages.Enqueue(msg); if (m_messageReceivedEvent != null) { m_messageReceivedEvent.Set(); } }
/// <summary> /// Recycle the message to the library for reuse /// </summary> internal void Recycle(NetOutgoingMessage msg) { VerifyNetworkThread(); #if DEBUG lock (m_connections) { foreach (NetConnection conn in m_connections) { for (int i = 0; i < conn.m_unsentMessages.Count; i++) { NetSending send = conn.m_unsentMessages.TryPeek(i); if (send != null && send.Message == msg) { throw new NetException("Ouch! Recycling unsent message!"); } foreach (NetSending asend in conn.m_unackedSends) { if (asend.Message == msg) { throw new NetException("Ouch! Recycling stored message!"); } } } } } #endif NetException.Assert(msg.m_numUnfinishedSendings == 0, "Recycling m_numUnfinishedSendings is " + msg.m_numUnfinishedSendings + " (expected 0)"); if (msg.m_data != null) { lock (m_storagePool) { if (!m_storagePool.Contains(msg.m_data)) { m_storedBytes += msg.m_data.Length; m_storagePool.Add(msg.m_data); } } msg.m_data = null; } m_outgoingMessagesPool.Enqueue(msg); }
/// <summary> /// Recycles a NetIncomingMessage instance for reuse; taking pressure off the garbage collector /// </summary> public void Recycle(NetIncomingMessage msg) { if (m_incomingMessagesPool == null || msg == null) { return; } NetException.Assert(m_incomingMessagesPool.Contains(msg) == false, "Recyling already recycled incoming message! Thread race?"); byte[] storage = msg.m_buf; msg.m_buf = null; Recycle(storage); msg.Reset(); if (m_incomingMessagesPool.Count < m_maxCacheCount) { m_incomingMessagesPool.Enqueue(msg); } }
internal void ReleaseMessage(NetIncomingMessage msg) { NetException.Assert(msg.m_incomingMessageType != NetIncomingMessageType.Error); if (msg.m_isFragment) { HandleReleasedFragment(msg); return; } if (msg.SenderConnection != null && msg.SenderConnection.MessageHandler != null) { var handled = msg.SenderConnection.MessageHandler(msg); if (handled) { return; } } m_releasedIncomingMessages.Enqueue(msg); if (m_messageReceivedEvent != null) { m_messageReceivedEvent.Set(); } if (m_receiveCallbacks != null) { foreach (var tuple in m_receiveCallbacks) { try { tuple.Item1.Post(tuple.Item2, this); } catch (Exception ex) { LogWarning("Receive callback exception:" + ex); } } } }
// TODO: Use this with TRUE isLibraryThread for internal sendings (acks etc) internal void SendMessage(NetBuffer data, NetChannel channel, NetBuffer receiptData, bool isLibraryThread) { if (m_status != NetConnectionStatus.Connected) { throw new NetException("Status must be Connected to send messages"); } if (data.LengthBytes > m_owner.m_config.m_maximumTransmissionUnit) { // // Fragmented message // int dataLen = data.LengthBytes; int chunkSize = m_owner.m_config.m_maximumTransmissionUnit - 10; // header int numFragments = dataLen / chunkSize; if (chunkSize * numFragments < dataLen) { numFragments++; } ushort fragId = m_nextSendFragmentId++; for (int i = 0; i < numFragments; i++) { OutgoingNetMessage fmsg = m_owner.CreateOutgoingMessage(); fmsg.m_type = NetMessageLibraryType.UserFragmented; fmsg.m_msgType = NetMessageType.Data; NetBuffer fragBuf = m_owner.CreateBuffer(); fragBuf.Write(fragId); fragBuf.WriteVariableUInt32((uint)i); fragBuf.WriteVariableUInt32((uint)numFragments); if (i < numFragments - 1) { // normal fragment fragBuf.Write(data.Data, i * chunkSize, chunkSize); } else { // last fragment int bitsInLast = data.LengthBits - (chunkSize * (numFragments - 1) * 8); int bytesInLast = dataLen - (chunkSize * (numFragments - 1)); fragBuf.Write(data.Data, i * chunkSize, bytesInLast); // add receipt only to last message fmsg.m_receiptData = receiptData; } fmsg.m_data = fragBuf; fmsg.m_data.m_refCount = 1; // since it's just been created fmsg.m_numSent = 0; fmsg.m_nextResend = double.MaxValue; fmsg.m_sequenceChannel = channel; fmsg.m_sequenceNumber = -1; if (isLibraryThread) { m_unsentMessages.Enqueue(fmsg); } else { lock (m_lockedUnsentMessages) m_lockedUnsentMessages.Enqueue(fmsg); } } // TODO: recycle the original, unfragmented data return; } // // Normal, unfragmented, message // OutgoingNetMessage msg = m_owner.CreateOutgoingMessage(); msg.m_msgType = NetMessageType.Data; msg.m_type = NetMessageLibraryType.User; msg.m_data = data; msg.m_data.m_refCount++; // it could have been sent earlier also msg.m_numSent = 0; msg.m_nextResend = double.MaxValue; msg.m_sequenceChannel = channel; msg.m_sequenceNumber = -1; msg.m_receiptData = receiptData; if (isLibraryThread) { m_unsentMessages.Enqueue(msg); } else { lock (m_lockedUnsentMessages) m_lockedUnsentMessages.Enqueue(msg); } }
internal void QueueAck(NetMessageType tp, int sequenceNumber) { m_queuedOutgoingAcks.Enqueue(new NetTuple <NetMessageType, int>(tp, sequenceNumber)); }
// received a library message while Connected internal void ReceivedLibraryMessage(NetMessageType tp, int ptr, int payloadLength) { m_peer.VerifyNetworkThread(); float now = (float)NetTime.Now; switch (tp) { case NetMessageType.Connect: m_peer.LogDebug("Received handshake message (" + tp + ") despite connection being in place"); break; case NetMessageType.ConnectResponse: // handshake message must have been lost HandleConnectResponse(now, tp, ptr, payloadLength); break; case NetMessageType.ConnectionEstablished: // do nothing, all's well break; case NetMessageType.LibraryError: m_peer.ThrowOrLog("LibraryError received by ReceivedLibraryMessage; this usually indicates a malformed message"); break; case NetMessageType.Disconnect: NetIncomingMessage msg = m_peer.SetupReadHelperMessage(ptr, payloadLength); m_disconnectRequested = true; m_disconnectMessage = msg.ReadString(); m_disconnectReqSendBye = false; //ExecuteDisconnect(msg.ReadString(), false); break; case NetMessageType.Acknowledge: for (int i = 0; i < payloadLength; i += 3) { NetMessageType acktp = (NetMessageType)m_peer.m_receiveBuffer[ptr++]; // netmessagetype int seqNr = m_peer.m_receiveBuffer[ptr++]; seqNr |= (m_peer.m_receiveBuffer[ptr++] << 8); // need to enqueue this and handle it in the netconnection heartbeat; so be able to send resends together with normal sends m_queuedIncomingAcks.Enqueue(new NetTuple <NetMessageType, int>(acktp, seqNr)); } break; case NetMessageType.Ping: int pingNr = m_peer.m_receiveBuffer[ptr++]; SendPong(pingNr); break; case NetMessageType.Pong: NetIncomingMessage pmsg = m_peer.SetupReadHelperMessage(ptr, payloadLength); int pongNr = pmsg.ReadByte(); float remoteSendTime = pmsg.ReadSingle(); ReceivedPong(now, pongNr, remoteSendTime); break; case NetMessageType.ExpandMTURequest: SendMTUSuccess(payloadLength); break; case NetMessageType.ExpandMTUSuccess: if (m_peer.Configuration.AutoExpandMTU == false) { m_peer.LogDebug("Received ExpandMTURequest altho AutoExpandMTU is turned off!"); break; } NetIncomingMessage emsg = m_peer.SetupReadHelperMessage(ptr, payloadLength); int size = emsg.ReadInt32(); HandleExpandMTUSuccess(now, size); break; case NetMessageType.NatIntroduction: // Unusual situation where server is actually already known, but got a nat introduction - oh well, lets handle it as usual m_peer.HandleNatIntroduction(ptr); break; default: m_peer.LogWarning("Connection received unhandled library message: " + tp); break; } }
internal void EnqueueReceivedMessage(IncomingNetMessage msg) { m_receivedMessages.Enqueue(msg); }