internal void ExecuteDisconnect(string reason, bool sendByeMessage) { // clear send queues for (int i = 0; i < m_sendChannels.Length; i++) { NetSenderChannelBase channel = m_sendChannels[i]; if (channel != null) { channel.Reset(); } } if (sendByeMessage) { SendDisconnect(reason, true); } if (m_status == NetConnectionStatus.ReceivedInitiation) { // nothing much has happened yet; no need to send disconnected status message m_status = NetConnectionStatus.Disconnected; } else { SetStatus(NetConnectionStatus.Disconnected, reason); } // in case we're still in handshake m_peer._handshakeManager.RemoveHandshake(m_remoteEndPoint); m_disconnectRequested = false; m_connectRequested = false; m_handshakeAttempts = 0; }
internal void ExecuteDisconnect(string reason, bool sendByeMessage) { m_peer.VerifyNetworkThread(); //m_peer.LogDebug("Executing disconnect"); // clear send queues for (int i = 0; i < m_sendChannels.Length; i++) { NetSenderChannelBase channel = m_sendChannels[i]; if (channel != null) { channel.Reset(); } } if (sendByeMessage) { SendDisconnect(reason, true); } SetStatus(NetConnectionStatus.Disconnected, reason); // in case we're still in handshake lock (m_peer.m_handshakes) m_peer.m_handshakes.Remove(m_remoteEndPoint); m_disconnectRequested = false; m_connectRequested = false; m_handshakeAttempts = 0; }
// called by SendMessage() and NetPeer.SendMessage; ie. may be user thread internal NetSendResult EnqueueMessage(NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel) { if (m_status != NetConnectionStatus.Connected) { return(NetSendResult.FailedNotConnected); } NetMessageType tp = (NetMessageType)((int)method + sequenceChannel); msg.m_messageType = tp; // TODO: do we need to make this more thread safe? int channelSlot = (int)method - 1 + sequenceChannel; NetSenderChannelBase chan = m_sendChannels[channelSlot]; if (chan == null) { chan = CreateSenderChannel(tp); } if ((method != NetDeliveryMethod.Unreliable && method != NetDeliveryMethod.UnreliableSequenced) && msg.GetEncodedSize() > m_currentMTU) { m_peer.ThrowOrLog("Reliable message too large! Fragmentation failure?"); } var retval = chan.Enqueue(msg); //if (retval == NetSendResult.Sent && m_peerConfiguration.m_autoFlushSendQueue == false) // retval = NetSendResult.Queued; // queued since we're not autoflushing return(retval); }
internal void ExecuteDisconnect(string reason, bool sendByeMessage) { m_peer.VerifyNetworkThread(); // m_peer.LogDebug("Executing disconnect"); // clear send queues for (int i = 0; i < m_sendChannels.Length; i++) { NetSenderChannelBase channel = m_sendChannels[i]; if (channel != null) { channel.Reset(); } } if (sendByeMessage) { SendDisconnect(reason, true); } SetStatus(NetConnectionStatus.Disconnected, reason); m_disconnectRequested = false; m_connectRequested = false; }
// called by SendMessage() and NetPeer.SendMessage; ie. may be user thread internal NetSendResult EnqueueMessage(NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel) { NetMessageType tp = (NetMessageType)((int)method + sequenceChannel); msg.m_messageType = tp; // TODO: do we need to make this more thread safe? int channelSlot = (int)method - 1 + sequenceChannel; NetSenderChannelBase chan = m_sendChannels[channelSlot]; if (chan == null) { chan = CreateSenderChannel(tp); } if (msg.GetEncodedSize() > m_currentMTU) { throw new NetException("Message too large! Fragmentation failure?"); } var retval = chan.Enqueue(msg); if (retval == NetSendResult.Sent && m_peerConfiguration.m_autoFlushSendQueue == false) { retval = NetSendResult.Queued; // queued since we're not autoflushing } return(retval); }
// 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); NetSenderChannelBase chan = m_sendChannels[(int)acktp - 1]; if (chan == null) { chan = CreateSenderChannel(acktp); } //m_peer.LogVerbose("Received ack for " + acktp + "#" + seqNr); chan.ReceiveAcknowledge(now, 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; default: m_peer.LogWarning("Connection received unhandled library message: " + tp); break; } }
// called by SendMessage() and NetPeer.SendMessage; ie. may be user thread internal NetSendResult EnqueueMessage(NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel) { NetMessageType tp = (NetMessageType)((int)method + sequenceChannel); msg.m_messageType = tp; // TODO: do we need to make this more thread safe? int channelSlot = (int)method - 1 + sequenceChannel; NetSenderChannelBase chan = m_sendChannels[channelSlot]; if (chan == null) { chan = CreateSenderChannel(tp); } if (msg.GetEncodedSize() > m_currentMTU) { throw new NetException("Message too large! Fragmentation failure?"); } return(chan.Enqueue(msg)); }
internal void Heartbeat(float now, uint frameCounter) { m_peer.VerifyNetworkThread(); NetException.Assert(m_status != NetConnectionStatus.InitiatedConnect && m_status != NetConnectionStatus.RespondedConnect); if ((frameCounter % m_infrequentEventsSkipFrames) == 0) { if (now > m_timeoutDeadline) { // // connection timed out // m_peer.LogVerbose("Connection timed out at " + now + " deadline was " + m_timeoutDeadline); ExecuteDisconnect("Connection timed out", true); return; } // send ping? if (m_status == NetConnectionStatus.Connected) { if (now > m_sentPingTime + m_peer.m_configuration.m_pingInterval) { SendPing(); } // handle expand mtu MTUExpansionHeartbeat(now); } if (m_disconnectRequested) { ExecuteDisconnect(m_disconnectMessage, m_disconnectReqSendBye); return; } } bool connectionReset; // TODO: handle connection reset // // Note: at this point m_sendBufferWritePtr and m_sendBufferNumMessages may be non-null; resends may already be queued up // byte[] sendBuffer = m_peer.m_sendBuffer; int mtu = m_currentMTU; if ((frameCounter % m_messageCoalesceFrames) == 0) // coalesce a few frames { // // send ack messages // while (m_queuedOutgoingAcks.Count > 0) { int acks = (mtu - (m_sendBufferWritePtr + 5)) / 3; // 3 bytes per actual ack if (acks > m_queuedOutgoingAcks.Count) { acks = m_queuedOutgoingAcks.Count; } NetException.Assert(acks > 0); m_sendBufferNumMessages++; // write acks header sendBuffer[m_sendBufferWritePtr++] = (byte)NetMessageType.Acknowledge; sendBuffer[m_sendBufferWritePtr++] = 0; // no sequence number sendBuffer[m_sendBufferWritePtr++] = 0; // no sequence number int len = (acks * 3) * 8; // bits sendBuffer[m_sendBufferWritePtr++] = (byte)len; sendBuffer[m_sendBufferWritePtr++] = (byte)(len >> 8); // write acks for (int i = 0; i < acks; i++) { NetTuple <NetMessageType, int> tuple; m_queuedOutgoingAcks.TryDequeue(out tuple); //m_peer.LogVerbose("Sending ack for " + tuple.Item1 + "#" + tuple.Item2); sendBuffer[m_sendBufferWritePtr++] = (byte)tuple.Item1; sendBuffer[m_sendBufferWritePtr++] = (byte)tuple.Item2; sendBuffer[m_sendBufferWritePtr++] = (byte)(tuple.Item2 >> 8); } if (m_queuedOutgoingAcks.Count > 0) { // send packet and go for another round of acks NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0); m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndPoint, m_sendBufferNumMessages, out connectionReset); m_statistics.PacketSent(m_sendBufferWritePtr, 1); m_sendBufferWritePtr = 0; m_sendBufferNumMessages = 0; } } // // Parse incoming acks (may trigger resends) // NetTuple <NetMessageType, int> incAck; while (m_queuedIncomingAcks.TryDequeue(out incAck)) { //m_peer.LogVerbose("Received ack for " + acktp + "#" + seqNr); NetSenderChannelBase chan = m_sendChannels[(int)incAck.Item1 - 1]; // If we haven't sent a message on this channel there is no reason to ack it if (chan == null) { continue; } chan.ReceiveAcknowledge(now, incAck.Item2); } } // // send queued messages // if (m_peer.m_executeFlushSendQueue) { for (int i = m_sendChannels.Length - 1; i >= 0; i--) // Reverse order so reliable messages are sent first { var channel = m_sendChannels[i]; NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0); if (channel != null) { channel.SendQueuedMessages(now); } NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0); } } // // Put on wire data has been written to send buffer but not yet sent // if (m_sendBufferWritePtr > 0) { m_peer.VerifyNetworkThread(); NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0); m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndPoint, m_sendBufferNumMessages, out connectionReset); m_statistics.PacketSent(m_sendBufferWritePtr, m_sendBufferNumMessages); m_sendBufferWritePtr = 0; m_sendBufferNumMessages = 0; } }