internal void SendConnect(TimeSpan now) { Peer.AssertIsOnLibraryThread(); int preAllocate = 13 + _peerConfiguration.AppIdentifier.Length; preAllocate += LocalHailMessage == null ? 0 : LocalHailMessage.ByteLength; NetOutgoingMessage om = Peer.CreateMessage(preAllocate); om._messageType = NetMessageType.Connect; om.Write(_peerConfiguration.AppIdentifier); om.Write(Peer.UniqueIdentifier); om.Write(now); WriteLocalHail(om); Peer.SendLibraryMessage(om, RemoteEndPoint); _connectRequested = false; _lastHandshakeSendTime = now; _handshakeAttempts++; if (_handshakeAttempts > 1) { Peer.LogDebug(new NetLogMessage(NetLogCode.ResendingConnect)); } SetStatus(NetConnectionStatus.InitiatedConnect); }
internal void SendDisconnect(NetOutgoingMessage?message, bool onLibraryThread) { if (onLibraryThread) { Peer.AssertIsOnLibraryThread(); } if (message == null) { message = Peer.CreateMessage(); message._messageType = NetMessageType.Disconnect; } if (onLibraryThread) { Peer.SendLibraryMessage(message, RemoteEndPoint); } else { Peer.UnsentUnconnectedMessages.Enqueue((RemoteEndPoint, message)); } }
internal void ExecuteDisconnect(NetOutgoingMessage?reason, bool sendByeMessage) { Peer.AssertIsOnLibraryThread(); // clear send queues for (int i = 0; i < _sendChannels.Length; i++) { NetSenderChannel?channel = _sendChannels[i]; if (channel != null) { channel.Reset(); } } if (sendByeMessage) { SendDisconnect(reason, true); } if (Status == NetConnectionStatus.ReceivedInitiation) { // nothing much has happened yet; no need to send disconnected status message Status = NetConnectionStatus.Disconnected; } else { SetStatus(NetConnectionStatus.Disconnected, reason); } // in case we're still in handshake Peer.Handshakes.TryRemove(RemoteEndPoint, out _); _disconnectRequested = false; _connectRequested = false; _handshakeAttempts = 0; }
internal void SendConnectResponse(TimeSpan now, bool onLibraryThread) { if (onLibraryThread) { Peer.AssertIsOnLibraryThread(); } NetOutgoingMessage om = Peer.CreateMessage( _peerConfiguration.AppIdentifier.Length + 13 + (LocalHailMessage == null ? 0 : LocalHailMessage.ByteLength)); om._messageType = NetMessageType.ConnectResponse; om.Write(_peerConfiguration.AppIdentifier); om.Write(Peer.UniqueIdentifier); om.Write(now); WriteLocalHail(om); if (onLibraryThread) { Peer.SendLibraryMessage(om, RemoteEndPoint); } else { Peer.UnsentUnconnectedMessages.Enqueue((RemoteEndPoint, om)); } _lastHandshakeSendTime = now; _handshakeAttempts++; if (_handshakeAttempts > 1) { Peer.LogDebug(new NetLogMessage(NetLogCode.ResendingRespondedConnect)); } SetStatus(NetConnectionStatus.RespondedConnect); }
internal void ReceivedHandshake(TimeSpan now, NetMessageType type, int offset, int payloadLength) { Peer.AssertIsOnLibraryThread(); switch (type) { case NetMessageType.Connect: if (Status == NetConnectionStatus.ReceivedInitiation) { // Whee! Server full has already been checked var(success, hail, hailLength) = ValidateHandshakeData(offset, payloadLength); if (success) { if (hail != null) { RemoteHailMessage = Peer.CreateIncomingMessage(NetIncomingMessageType.Data); RemoteHailMessage.SetBuffer(hail, true); RemoteHailMessage.ByteLength = hailLength; } else { RemoteHailMessage = null; } if (_peerConfiguration.IsMessageTypeEnabled(NetIncomingMessageType.ConnectionApproval)) { // ok, let's not add connection just yet var appMsg = Peer.CreateIncomingMessage(NetIncomingMessageType.ConnectionApproval); appMsg.ReceiveTime = now; appMsg.SenderConnection = this; appMsg.SenderEndPoint = RemoteEndPoint; if (RemoteHailMessage != null) { appMsg.Write(RemoteHailMessage.GetBuffer().AsSpan(0, RemoteHailMessage.ByteLength)); } SetStatus(NetConnectionStatus.RespondedAwaitingApproval); Peer.ReleaseMessage(appMsg); return; } SendConnectResponse(now, true); } return; } if (Status == NetConnectionStatus.RespondedAwaitingApproval) { Peer.LogWarning(new NetLogMessage(NetLogCode.IgnoringMultipleConnects, endPoint: this)); return; } if (Status == NetConnectionStatus.RespondedConnect) { // our ConnectResponse must have been lost SendConnectResponse(now, true); return; } Peer.LogDebug(NetLogMessage.FromValues(NetLogCode.UnhandledConnect, endPoint: this, value: (int)Status)); break; case NetMessageType.ConnectResponse: HandleConnectResponse(offset, payloadLength); break; case NetMessageType.ConnectionEstablished: switch (Status) { case NetConnectionStatus.Connected: // ok... break; case NetConnectionStatus.Disconnected: case NetConnectionStatus.Disconnecting: case NetConnectionStatus.None: // too bad, almost made it break; case NetConnectionStatus.ReceivedInitiation: // uh, a little premature... ignore break; case NetConnectionStatus.InitiatedConnect: // weird, should have been RespondedConnect... break; case NetConnectionStatus.RespondedConnect: // awesome NetIncomingMessage msg = Peer.SetupReadHelperMessage(offset, payloadLength); InitializeRemoteTimeOffset(msg.ReadTimeSpan()); Peer.AcceptConnection(this); InitializePing(); SetStatus(NetConnectionStatus.Connected); return; } break; case NetMessageType.InvalidHandshake: case NetMessageType.WrongAppIdentifier: case NetMessageType.ConnectTimedOut: case NetMessageType.TimedOut: case NetMessageType.Disconnect: NetOutgoingMessage?reason = null; try { reason = Peer.CreateReadHelperOutMessage(offset, payloadLength); } catch { } ExecuteDisconnect(reason, false); break; case NetMessageType.Discovery: Peer.HandleIncomingDiscoveryRequest(now, RemoteEndPoint, offset, payloadLength); return; case NetMessageType.DiscoveryResponse: Peer.HandleIncomingDiscoveryResponse(now, RemoteEndPoint, offset, payloadLength); return; case NetMessageType.Ping: // silently ignore return; default: Peer.LogDebug(NetLogMessage.FromValues(NetLogCode.UnhandledHandshakeMessage, value: (int)Status)); break; } }
// heartbeat called when connection still is in m_handshakes of NetPeer internal void UnconnectedHeartbeat(TimeSpan now) { Peer.AssertIsOnLibraryThread(); if (_disconnectRequested) { ExecuteDisconnect(_disconnectMessage, true); } if (_connectRequested) { switch (Status) { case NetConnectionStatus.Connected: case NetConnectionStatus.RespondedConnect: // reconnect ExecuteDisconnect(NetMessageType.ConnectTimedOut); break; case NetConnectionStatus.InitiatedConnect: // send another connect attempt SendConnect(now); break; case NetConnectionStatus.Disconnected: Peer.LogError(NetLogMessage.FromValues(NetLogCode.DisconnectedPeer)); break; case NetConnectionStatus.Disconnecting: // let disconnect finish first break; case NetConnectionStatus.None: default: SendConnect(now); break; } return; } if (now - _lastHandshakeSendTime > _peerConfiguration._resendHandshakeInterval) { if (_handshakeAttempts >= _peerConfiguration._maximumHandshakeAttempts) { // failed to connect ExecuteDisconnect(NetMessageType.ConnectTimedOut); return; } // resend handshake switch (Status) { case NetConnectionStatus.InitiatedConnect: SendConnect(now); break; case NetConnectionStatus.RespondedConnect: SendConnectResponse(now, true); break; case NetConnectionStatus.RespondedAwaitingApproval: // awaiting approval _lastHandshakeSendTime = now; // postpone handshake resend break; case NetConnectionStatus.None: case NetConnectionStatus.ReceivedInitiation: default: Peer.LogWarning(NetLogMessage.FromValues(NetLogCode.UnexpectedHandshakeStatus, value: (int)Status)); break; } } }