/// <summary> /// Called when receiving a NatPunchMessage from a remote endpoint /// </summary> private void HandleNatPunch(int ptr, IPEndPoint senderEndpoint) { NetIncomingMessage tmp = SetupReadHelperMessage(ptr, 1000); // never mind length byte fromHostByte = tmp.ReadByte(); if (fromHostByte == 0) { // it's from client LogDebug("NAT punch received from " + senderEndpoint + " we're host, so we ignore this"); return; // don't alert hosts about nat punch successes; only clients } string token = tmp.ReadString(); LogDebug("NAT punch received from " + senderEndpoint + " we're client, so we've succeeded - token is " + token); // // Release punch success to client; enabling him to Connect() to msg.SenderIPEndPoint if token is ok // NetIncomingMessage punchSuccess = CreateIncomingMessage(NetIncomingMessageType.NatIntroductionSuccess, 10); punchSuccess.m_senderEndpoint = senderEndpoint; punchSuccess.Write(token); ReleaseMessage(punchSuccess); }
internal void ReceivedPong(float now, int pongNumber, float remoteSendTime) { if ((byte)pongNumber != (byte)m_sentPingNumber) { m_peer.LogVerbose("Ping/Pong mismatch; dropped message?"); return; } m_timeoutDeadline = now + m_peerConfiguration.m_connectionTimeout; float rtt = now - m_sentPingTime; NetException.Assert(rtt >= 0); double diff = (remoteSendTime + (rtt / 2.0)) - now; if (m_averageRoundtripTime < 0) { m_remoteTimeOffset = diff; m_averageRoundtripTime = rtt; m_peer.LogDebug("Initiated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime) + " Remote time is: " + (now + diff)); } else { m_averageRoundtripTime = (m_averageRoundtripTime * 0.7f) + (float)(rtt * 0.3f); m_remoteTimeOffset = ((m_remoteTimeOffset * (double)(m_sentPingNumber - 1)) + diff) / (double)m_sentPingNumber; m_peer.LogVerbose("Updated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime) + ", remote time to " + (now + m_remoteTimeOffset) + " (ie. diff " + m_remoteTimeOffset + ")"); } // update resend delay for all channels float resendDelay = GetResendDelay(); foreach (var chan in m_sendChannels) { var rchan = chan as NetReliableSenderChannel; if (rchan != null) { rchan.m_resendDelay = resendDelay; } } // m_peer.LogVerbose("Timeout deadline pushed to " + m_timeoutDeadline); // notify the application that average rtt changed if (m_peer.m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.ConnectionLatencyUpdated)) { NetIncomingMessage update = m_peer.CreateIncomingMessage(NetIncomingMessageType.ConnectionLatencyUpdated, 4); update.m_senderConnection = this; update.m_senderEndpoint = this.m_remoteEndpoint; update.Write(rtt); m_peer.ReleaseMessage(update); } }
internal void SetStatus(NetConnectionStatus status, string reason) { // user or library thread if (status == m_status) { return; } m_status = status; if (reason == null) { reason = string.Empty; } if (m_status == NetConnectionStatus.Connected) { m_timeoutDeadline = (float)NetTime.Now + m_peerConfiguration.m_connectionTimeout; m_peer.LogVerbose("Timeout deadline initialized to " + m_timeoutDeadline); } if (m_peerConfiguration.IsMessageTypeEnabled(NetIncomingMessageType.StatusChanged)) { NetIncomingMessage info = m_peer.CreateIncomingMessage(NetIncomingMessageType.StatusChanged, 4 + reason.Length + (reason.Length > 126 ? 2 : 1)); info.m_senderConnection = this; info.m_senderEndpoint = m_remoteEndpoint; info.Write((byte)m_status); info.Write(reason); m_peer.ReleaseMessage(info); } else { // app dont want those messages, update visible status immediately m_visibleStatus = m_status; } }
internal void ReceivedHandshake(double now, NetMessageType tp, int ptr, int payloadLength) { m_peer.VerifyNetworkThread(); byte[] hail; switch (tp) { case NetMessageType.Connect: if (m_status == NetConnectionStatus.None) { // Whee! Server full has already been checked bool ok = ValidateHandshakeData(ptr, payloadLength, out hail); if (ok) { if (hail != null) { m_remoteHailMessage = m_peer.CreateIncomingMessage(NetIncomingMessageType.Data, hail); m_remoteHailMessage.LengthBits = (hail.Length * 8); } else { m_remoteHailMessage = null; } if (m_peerConfiguration.IsMessageTypeEnabled(NetIncomingMessageType.ConnectionApproval)) { // ok, let's not add connection just yet NetIncomingMessage appMsg = m_peer.CreateIncomingMessage(NetIncomingMessageType.ConnectionApproval, (m_remoteHailMessage == null ? 0 : m_remoteHailMessage.LengthBytes)); appMsg.m_receiveTime = now; appMsg.m_senderConnection = this; appMsg.m_senderEndpoint = this.m_remoteEndpoint; if (m_remoteHailMessage != null) { appMsg.Write(m_remoteHailMessage.m_data, 0, m_remoteHailMessage.LengthBytes); } m_peer.ReleaseMessage(appMsg); return; } SendConnectResponse((float)now, true); } return; } if (m_status == NetConnectionStatus.RespondedConnect) { // our ConnectResponse must have been lost SendConnectResponse((float)now, true); return; } m_peer.LogDebug("Unhandled Connect: " + tp + ", status is " + m_status + " length: " + payloadLength); break; case NetMessageType.ConnectResponse: switch (m_status) { case NetConnectionStatus.InitiatedConnect: // awesome bool ok = ValidateHandshakeData(ptr, payloadLength, out hail); if (ok) { if (hail != null) { m_remoteHailMessage = m_peer.CreateIncomingMessage(NetIncomingMessageType.Data, hail); m_remoteHailMessage.LengthBits = (hail.Length * 8); } else { m_remoteHailMessage = null; } m_peer.AcceptConnection(this); SendConnectionEstablished(); return; } break; case NetConnectionStatus.RespondedConnect: // hello, wtf? break; case NetConnectionStatus.Disconnecting: case NetConnectionStatus.Disconnected: case NetConnectionStatus.None: // wtf? anyway, bye! break; case NetConnectionStatus.Connected: // my ConnectionEstablished must have been lost, send another one SendConnectionEstablished(); return; } break; case NetMessageType.ConnectionEstablished: switch (m_status) { case NetConnectionStatus.Connected: // ok... break; case NetConnectionStatus.Disconnected: case NetConnectionStatus.Disconnecting: case NetConnectionStatus.None: // too bad, almost made it break; case NetConnectionStatus.InitiatedConnect: // weird, should have been ConnectResponse... break; case NetConnectionStatus.RespondedConnect: // awesome NetIncomingMessage msg = m_peer.SetupReadHelperMessage(ptr, payloadLength); InitializeRemoteTimeOffset(msg.ReadSingle()); m_peer.AcceptConnection(this); InitializePing(); SetStatus(NetConnectionStatus.Connected, "Connected to " + NetUtility.ToHexString(m_remoteUniqueIdentifier)); return; } break; case NetMessageType.Disconnect: // ouch string reason = "Ouch"; try { NetIncomingMessage inc = m_peer.SetupReadHelperMessage(ptr, payloadLength); reason = inc.ReadString(); } catch { } ExecuteDisconnect(reason, false); break; case NetMessageType.Discovery: m_peer.HandleIncomingDiscoveryRequest(now, m_remoteEndpoint, ptr, payloadLength); return; case NetMessageType.DiscoveryResponse: m_peer.HandleIncomingDiscoveryResponse(now, m_remoteEndpoint, ptr, payloadLength); return; case NetMessageType.Ping: // silently ignore return; default: m_peer.LogDebug("Unhandled type during handshake: " + tp + " length: " + payloadLength); break; } }