void AddToPendingPeers(ConnectedPeerType type, IPEndPoint remoteEndpoint, SocketWithReceiver socket) { var cp = new ConnectedPeer(_localPeer, null, type, remoteEndpoint.Address); cp.TryAddStream(socket, remoteEndpoint, null, _pendingPeers.Values.Select(x => x.Streams.Values.Single().StreamId)); // all "pending" streams will have unique local stream ID _pendingPeers.Add(remoteEndpoint, cp); }
void ProcessReceivedHello_FromExistingPeer(PeerHelloPacket helloPacket, IPEndPoint remoteEndpoint, SocketWithReceiver socket, ConnectedPeer connectedPeer, uint packetReceivedTimestamp32) { // current situation: // received hello packet; this peer wants to accept connection // in hello packet FromPeerId matches to existing connected peer // there is already at least 1 stream in the existing peer; it could be request via this stream or via another stream // it could be request (ping) or response // it could be packet to new stream, or to existing stream // it could be packet from changed remote endpoint to same stream ID // it could be packet from wrong remote endpoint to new (non-existing locally) stream ID ??????????????????????? if (!connectedPeer.Streams.TryGetValue(helloPacket.StreamId, out var stream)) { // received packet in new streamId if (helloPacket.Status.IsSetupOrPing()) { if (connectedPeer.Streams.Count > LocalLogicConfiguration.ConnectedPeerMaxStreamsCount) { _localPeer.WriteToLog_deepDetail(LogModules.Hello, $"rejecting request from {remoteEndpoint}: connectedPeer.Streams.Count={connectedPeer.Streams.Count} > LocalLogicConfiguration.ConnectedPeerMaxStreamsCount"); PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.rejected_dontTryLater, null, socket, remoteEndpoint); return; } stream = connectedPeer.TryAddStream(socket, remoteEndpoint, helloPacket.StreamId); // _localPeer.WriteToLog(LogModules.Hello, $"peer {connectedPeer} received hello from new stream {stream}"); if (stream == null) { throw new InvalidOperationException(); } } else { _localPeer.Firewall.OnUnauthenticatedReceivedPacket(remoteEndpoint); return; } } else {// received packet in existing streamId // check source endpoint if (!remoteEndpoint.Equals(stream.RemoteEndPoint)) { // dont allow change of source ip/port within same stream _localPeer.Firewall.OnUnauthenticatedReceivedPacket(remoteEndpoint); if (helloPacket.Status.IsSetupOrPing()) { PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.rejected_tryCleanSetup, null, socket, remoteEndpoint); } return; } } // current situation: we got connectedPeer, stream. we handle request or response if (!RemoteVersionIsAcceptableForNewConnection(helloPacket)) { _localPeer.WriteToLog_deepDetail(LogModules.Hello, $"peer {connectedPeer} got response with too old version"); connectedPeer.RemoveStream(stream); _connectedPeers.Remove(connectedPeer.RemotePeerId); return; } switch (helloPacket.Status) { case PeerHelloRequestStatus.setup: case PeerHelloRequestStatus.ping: var responseCpuDelayMs = (ushort)Math.Round(TimeSpan.FromTicks(unchecked (_localPeer.Time32 - packetReceivedTimestamp32)).TotalMilliseconds); PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.accepted, null, socket, remoteEndpoint, responseCpuDelayMs, _localPeer.Configuration.RoleAsUser, _localPeer.IpLocationScraper?.IpLocationData); break; case PeerHelloRequestStatus.accepted: ProcessReceivedAcceptedHello_UpdateHelloLevelFields(connectedPeer, stream, helloPacket, packetReceivedTimestamp32); break; case PeerHelloRequestStatus.rejected_tryCleanSetup: _localPeer.WriteToLog_deepDetail(LogModules.Hello, $"peer {connectedPeer} received {helloPacket.Status} from stream {stream}"); connectedPeer.RemoveStream(stream); AddToPendingPeers(connectedPeer.Type, remoteEndpoint, socket); break; case PeerHelloRequestStatus.rejected_dontTryLater: _localPeer.WriteToLog_deepDetail(LogModules.Hello, $"peer {connectedPeer} received {helloPacket.Status} from stream {stream}"); connectedPeer.RemoveStream(stream); break; case PeerHelloRequestStatus.rejected_tryLater: _localPeer.WriteToLog_deepDetail(LogModules.Hello, $"peer {connectedPeer} received {helloPacket.Status} from stream {stream}"); // it will try anyway on timer break; } }