private void SendQueuedOutOfBandMessages() { if (m_unsentOutOfBandMessages.Count > 0) { while (m_unsentOutOfBandMessages.Count > 0) { NetBuffer buf = m_unsentOutOfBandMessages.Dequeue(); NetworkEndPoint ep = m_unsentOutOfBandRecipients.Dequeue(); DoSendOutOfBandMessage(buf, ep); } } }
/// <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); } }
internal void SendUnsentMessages(double now) { // Add any acknowledges to unsent messages if (m_acknowledgesToSend.Count > 0) { if (m_unsentMessages.Count < 1) { // Wait before sending acknowledges? if (m_ackMaxDelayTime > 0.0f) { if (m_ackWithholdingStarted == 0.0) { m_ackWithholdingStarted = now; } else { if (now - m_ackWithholdingStarted < m_ackMaxDelayTime) { return; // don't send (only) acks just yet } // send acks "explicitly" ie. without any other message being sent m_ackWithholdingStarted = 0.0; } } } // create ack messages and add to m_unsentMessages CreateAckMessages(); } if (m_unsentMessages.Count < 1) { return; } // throttling float throttle = m_owner.m_config.ThrottleBytesPerSecond; float maxSendBytes = float.MaxValue; if (throttle > 0) { double frameLength = now - m_lastSentUnsentMessages; //int wasDebt = (int)m_throttleDebt; if (m_throttleDebt > 0) { m_throttleDebt -= (float)(frameLength * (double)m_owner.m_config.ThrottleBytesPerSecond); } //int nowDebt = (int)m_throttleDebt; //if (nowDebt != wasDebt) // LogWrite("THROTTLE worked off -" + (nowDebt - wasDebt) + " bytes = " + m_throttleDebt); m_lastSentUnsentMessages = now; maxSendBytes = throttle - m_throttleDebt; if (maxSendBytes < 0) { return; // throttling; no bytes allowed to be sent } } int mtu = m_owner.Configuration.MaximumTransmissionUnit; bool useCoalescing = m_owner.Configuration.UseMessageCoalescing; int messagesInPacket = 0; NetBuffer sendBuffer = m_owner.m_sendBuffer; sendBuffer.Reset(); while (m_unsentMessages.Count > 0) { OutgoingNetMessage msg = m_unsentMessages.Peek(); int estimatedMessageSize = msg.m_data.LengthBytes + 5; // check if this message fits the throttle window if (estimatedMessageSize > maxSendBytes) // TODO: Allow at last one message if no debt { break; } // need to send packet and start a new one? if (messagesInPacket > 0) { if (!useCoalescing || (sendBuffer.LengthBytes + estimatedMessageSize > mtu)) { m_owner.SendPacket(m_remoteEndPoint); int sendLen = sendBuffer.LengthBytes; m_statistics.CountPacketSent(sendLen); //LogWrite("THROTTLE Send packet +" + sendLen + " bytes = " + m_throttleDebt + " (maxSendBytes " + maxSendBytes + " estimated " + estimatedMessageSize + ")"); m_throttleDebt += sendLen; sendBuffer.Reset(); } } if (msg.m_sequenceNumber == -1) { AssignSequenceNumber(msg); } // pop and encode message m_unsentMessages.Dequeue(); int pre = sendBuffer.m_bitLength; msg.m_data.m_readPosition = 0; msg.Encode(sendBuffer); int encLen = (sendBuffer.m_bitLength - pre) / 8; m_statistics.CountMessageSent(msg, encLen); maxSendBytes -= encLen; if (msg.m_sequenceChannel >= NetChannel.ReliableUnordered) { // reliable; store message (incl. buffer) msg.m_numSent++; StoreMessage(now, msg); } else { // not reliable, don't store - recycle... NetBuffer b = msg.m_data; b.m_refCount--; msg.m_data = null; // ... unless someone else is using the buffer if (b.m_refCount <= 0) { m_owner.RecycleBuffer(b); } //m_owner.m_messagePool.Push(msg); } messagesInPacket++; } // send current packet if (messagesInPacket > 0) { m_owner.SendPacket(m_remoteEndPoint); int sendLen = sendBuffer.LengthBytes; m_statistics.CountPacketSent(sendLen); //LogWrite("THROTTLE Send packet +" + sendLen + " bytes = " + m_throttleDebt); m_throttleDebt += sendLen; } }
internal void Heartbeat(double now) { if (m_status == NetConnectionStatus.Disconnected) { return; } //CongestionHeartbeat(now); // drain messages from application into main unsent list lock (m_lockedUnsentMessages) { OutgoingNetMessage lm; while ((lm = m_lockedUnsentMessages.Dequeue()) != null) { m_unsentMessages.Enqueue(lm); } } if (m_status == NetConnectionStatus.Connecting) { if (now - m_handshakeInitiated > m_owner.Configuration.HandshakeAttemptRepeatDelay) { if (m_handshakeAttempts >= m_owner.Configuration.HandshakeAttemptsMaxCount) { Disconnect("No answer from remote host", 0, false, true); return; } m_handshakeAttempts++; if (m_isInitiator) { m_owner.LogWrite("Re-sending Connect", this); Connect(); } else { m_owner.LogWrite("Re-sending ConnectResponse", this); m_handshakeInitiated = now; OutgoingNetMessage response = m_owner.CreateSystemMessage(NetSystemType.ConnectResponse); if (m_localHailData != null) { response.m_data.Write(m_localHailData); } m_unsentMessages.Enqueue(response); } } } else if (m_status == NetConnectionStatus.Connected) { // send ping? CheckPing(now); } if (m_requestDisconnect) { InitiateDisconnect(); } if (now > m_futureClose) { FinalizeDisconnect(); } // Resend all packets that has reached a mature age ResendMessages(now); // send all unsent messages SendUnsentMessages(now); }
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); }