void ProcessReceivedPeersList(ConnectedPeer connectedPeer, PeersListPacketIpv4 peersListPacket, IPEndPoint remoteEndpoint) { if (!connectedPeer.Streams.TryGetValue(peersListPacket.StreamId, out var localStream)) { _localPeer.Firewall.OnUnauthenticatedReceivedPacket(remoteEndpoint); return; } foreach (var receivedSharedPeer in peersListPacket.SharedPeers) { if (receivedSharedPeer.ToPeerId.Equals(_localPeer.LocalPeerId)) { continue; // dont connect to this peer } if (!_connectedPeers.TryGetValue(receivedSharedPeer.ToPeerId, out var localConnectedPeer)) { _localPeer.WriteToLog_deepDetail(LogModules.PeerSharing, $"received shared peer {receivedSharedPeer}) from {connectedPeer}"); localConnectedPeer = new ConnectedPeer(_localPeer, receivedSharedPeer.ToPeerId, ConnectedPeerType.toPeerShared, receivedSharedPeer.ToEndPoint.Address); lock (_connectedPeers) _connectedPeers.Add(receivedSharedPeer.ToPeerId, localConnectedPeer); } if (!localConnectedPeer.Streams.Values.Any(x => x.RemoteEndPoint.Equals(receivedSharedPeer.ToEndPoint))) { if (connectedPeer.Streams.TryGetValue(receivedSharedPeer.FromSocketAtStreamId, out var fromStreamSocket)) { localConnectedPeer.TryAddStream( fromStreamSocket.Socket, receivedSharedPeer.ToEndPoint, null); } } // else there is already connected stream to this remote peer endpoint } }
void ProcessReceivedAcceptedHello_UpdateHelloLevelFields(ConnectedPeer connectedPeer, ConnectedPeerStream stream, PeerHelloPacket helloResponsePacket, uint responseReceivedTime32) { var rtt = TimeSpan.FromTicks(unchecked (responseReceivedTime32 - helloResponsePacket.RequestTime32)) - TimeSpan.FromMilliseconds(helloResponsePacket.ResponseCpuDelayMs ?? 0); if (rtt < TimeSpan.Zero) { rtt = TimeSpan.Zero; // avoid abnormal measurements } stream.LatestHelloRtt = rtt; stream.LocalPeerPublicIp = helloResponsePacket.RequestedFromIp; stream.LastTimeReceivedAccepted = _localPeer.DateTimeNowUtc; connectedPeer.ProtocolVersion = helloResponsePacket.ProtocolVersion; connectedPeer.LibraryVersion = MiscProcedures.Uint32secondsToDateTime(helloResponsePacket.LibraryVersion); connectedPeer.TotalHelloAcceptedPacketsReceived++; stream.TotalHelloAcceptedPacketsReceived++; stream.RemotePeerRoleIsUser = helloResponsePacket.RoleFlagIsUser; if (helloResponsePacket.IpLocationData != null && connectedPeer.RemoteIpLocationData == null) { _localPeer.WriteToLog_higherLevelDetail(LogModules.Hello, $"got IP location from peer {connectedPeer}: {helloResponsePacket.IpLocationData}"); connectedPeer.RemoteIpLocationData = helloResponsePacket.IpLocationData; } if (helloResponsePacket.ExtensionIds != null && helloResponsePacket.ExtensionIds.Length != 0) { connectedPeer.LatestReceivedRemoteExtensionIds = new HashSet <string>(helloResponsePacket.ExtensionIds.Distinct()); } }
void SendHelloRequestToPeer(DateTime now, ConnectedPeer peer, ConnectedPeerStream stream, bool requestIpLocation) { var data = new PeerHelloPacket(_localPeer, peer, stream, stream.LastTimeReceivedAccepted.HasValue ? PeerHelloRequestStatus.ping : PeerHelloRequestStatus.setup, requestIpLocation).Encode(); stream.LastTimeSentRequest = now; stream.Socket.UdpSocket.Send(data, data.Length, stream.RemoteEndPoint); // send from all local sockets to all remote sockets to open P2P connection in the NAT }
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); }
internal ConnectedPeerStream(LocalPeer localPeer, ConnectedPeer connectedPeer, StreamId streamId, IPEndPoint remoteEP, SocketWithReceiver socket) { _localPeer = localPeer; Created = localPeer.DateTimeNowUtc; StreamId = streamId; RemoteEndPoint = remoteEP; Socket = socket; Extensions = connectedPeer.Extensions.ToDictionary(ext => ext.Key, ext => ext.Value.OnConnectedPeerStream(this)); }
/// <summary> /// for both coordinatorServer and userPeer /// accepts connection, adds peer and/or stream to lists, responds with 'accepted' /// </summary> void ProcessReceivedHello_SetupRequestFromNewPeer(PeerHelloPacket helloPacket, IPEndPoint remoteEndpoint, SocketWithReceiver socket, PeerId localPeerIdForResponse) { if (_localPeer.Configuration.RoleAsCoordinator) { if (_connectedPeers.Count > LocalLogicConfiguration.CoordinatorPeer_MaxConnectedPeersToAccept) { _localPeer.SysAdminFeedbackChannel.OnReachedMaxConnectedPeersAtThisCoordinatorServer(); PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.rejected_tryLater, null, socket, remoteEndpoint); return; } } else if (_localPeer.Configuration.RoleAsSharedPassive) { if (_connectedPeers.Count > LocalLogicConfiguration.SharedPeer_MaxConnectedPeersToAccept) { _localPeer.SysAdminFeedbackChannel.OnReachedMaxConnectedPeersAtThisSharedPeer(); _localPeer.WriteToLog(LogModules.Hello, $"rejecting request from {remoteEndpoint}: _connectedPeers.Count={_connectedPeers.Count} > LocalLogicConfiguration.SharedPeer_MaxConnectedPeersToAccept"); PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.rejected_dontTryLater, null, socket, remoteEndpoint); return; } } else if (_localPeer.Configuration.RoleAsUser) { if (_connectedPeers.Count > LocalLogicConfiguration.UserPeer_MaxConnectedPeersToAccept) { _localPeer.WriteToLog(LogModules.Hello, $"rejecting request from {remoteEndpoint}: _connectedPeers.Count={_connectedPeers.Count} > LocalLogicConfiguration.UserPeer_MaxConnectedPeersToAccept"); PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.rejected_dontTryLater, null, socket, remoteEndpoint); return; } } if (!_connectedPeers.TryGetValue(helloPacket.FromPeerId, out var peer)) { peer = new ConnectedPeer(_localPeer, helloPacket.FromPeerId) { Type = ConnectedPeerType.fromPeerAccepted }; lock (_connectedPeers) _connectedPeers.Add(helloPacket.FromPeerId, peer); } if (peer.Streams.Count > LocalLogicConfiguration.ConnectedPeerMaxStreamsCount) { _localPeer.WriteToLog(LogModules.Hello, $"rejecting request from {remoteEndpoint}: peer.Streams.Count={peer.Streams.Count} > LocalLogicConfiguration.ConnectedPeerMaxStreamsCount"); PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.rejected_dontTryLater, null, socket, remoteEndpoint); } else { var stream = peer.TryAddStream(socket, remoteEndpoint, helloPacket.StreamId); _localPeer.WriteToLog(LogModules.Hello, $"created new stream {stream} from new peer {peer}"); PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.accepted, localPeerIdForResponse, socket, remoteEndpoint, _localPeer.Configuration.RoleAsUser); } }
void ProcessReceivedAcceptedHello_UpdateHelloLevelFields(ConnectedPeer connectedPeer, ConnectedPeerStream stream, PeerHelloPacket helloPacket) { stream.LatestHelloRtt = TimeSpan.FromTicks(unchecked (_localPeer.Time32 - helloPacket.RequestTime32)); stream.LastTimeReceivedAccepted = _localPeer.DateTimeNowUtc; connectedPeer.ProtocolVersion = helloPacket.ProtocolVersion; connectedPeer.LibraryVersion = CompilationInfo.ToDateTime(helloPacket.LibraryVersion); connectedPeer.TotalHelloAcceptedPacketsReceived++; stream.TotalHelloAcceptedPacketsReceived++; stream.RemotePeerRoleIsUser = helloPacket.RoleFlagIsUser; if (helloPacket.ExtensionIds != null && helloPacket.ExtensionIds.Length != 0) { connectedPeer.LatestReceivedRemoteExtensionIds = new HashSet <string>(helloPacket.ExtensionIds.Distinct()); } }
void ShareConnectedPeers(ConnectedPeer connectedPeer1, ConnectedPeer connectedPeer2, DateTime now) { try { var streams1 = SelectWithUniqueRemoteEndPoints(connectedPeer1.Streams.Values.Where(x => x.IsIdle(now, LocalLogicConfiguration.MaxPeerIdleTime_ToShare) == false)).ToArray(); var streams2 = SelectWithUniqueRemoteEndPoints(connectedPeer2.Streams.Values.Where(x => x.IsIdle(now, LocalLogicConfiguration.MaxPeerIdleTime_ToShare) == false)).ToArray(); var l = Math.Min(streams1.Length, streams2.Length); if (l == 0) { return; } var stream1 = streams1[0]; var stream2 = streams2[0]; if (stream1.RemoteEndPoint.Address.Equals(stream2.RemoteEndPoint.Address)) { return; // dont connect peers across lan (from same IP) } var itemsForPacket1 = new PeersListPacket_SharedPeerIpv4[l]; var itemsForPacket2 = new PeersListPacket_SharedPeerIpv4[l]; for (int i = 0; i < l; i++) { itemsForPacket1[i] = new PeersListPacket_SharedPeerIpv4(streams1[i].StreamId, connectedPeer2.RemotePeerId, streams2[i].RemoteEndPoint); itemsForPacket2[i] = new PeersListPacket_SharedPeerIpv4(streams2[i].StreamId, connectedPeer1.RemotePeerId, streams1[i].RemoteEndPoint); } var data1 = new PeersListPacketIpv4(itemsForPacket1, _localPeer.LocalPeerId, stream1.StreamId).Encode(); stream1.Socket.UdpSocket.Send(data1, data1.Length, stream1.RemoteEndPoint); var data2 = new PeersListPacketIpv4(itemsForPacket2, _localPeer.LocalPeerId, stream2.StreamId).Encode(); stream2.Socket.UdpSocket.Send(data2, data2.Length, stream2.RemoteEndPoint); } catch (Exception exc) { _localPeer.HandleException(LogModules.PeerSharing, exc); } }
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; } }
/// <summary> /// for both coordinatorServer and userPeer /// accepts connection, adds peer and/or stream to lists, responds with 'accepted' /// </summary> void ProcessReceivedHello_SetupRequestFromNewPeer(PeerHelloPacket helloPacket, IPEndPoint remoteEndpoint, SocketWithReceiver socket, PeerId localPeerIdForResponse, uint requestReceivedTimestamp32) { if (_localPeer.Configuration.RoleAsCoordinator) { if (_connectedPeers.Count > LocalLogicConfiguration.CoordinatorPeer_MaxConnectedPeersToAccept) { _localPeer.SysAdminFeedbackChannel.OnReachedMaxConnectedPeersAtThisCoordinatorServer(); PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.rejected_tryLater, null, socket, remoteEndpoint); return; } } else if (_localPeer.Configuration.RoleAsSharedPassive) { if (_connectedPeers.Count > LocalLogicConfiguration.SharedPeer_MaxConnectedPeersToAccept) { _localPeer.SysAdminFeedbackChannel.OnReachedMaxConnectedPeersAtThisSharedPeer(); _localPeer.WriteToLog_deepDetail(LogModules.Hello, $"rejecting request from {remoteEndpoint}: _connectedPeers.Count={_connectedPeers.Count} > LocalLogicConfiguration.SharedPeer_MaxConnectedPeersToAccept"); PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.rejected_dontTryLater, null, socket, remoteEndpoint); return; } } else if (_localPeer.Configuration.RoleAsUser) { if (_connectedPeers.Count > LocalLogicConfiguration.UserPeer_MaxConnectedPeersToAccept) { _localPeer.WriteToLog_deepDetail(LogModules.Hello, $"rejecting request from {remoteEndpoint}: _connectedPeers.Count={_connectedPeers.Count} > LocalLogicConfiguration.UserPeer_MaxConnectedPeersToAccept"); PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.rejected_dontTryLater, null, socket, remoteEndpoint); return; } if (!RemoteVersionIsAcceptableForNewConnection(helloPacket)) { _localPeer.WriteToLog_deepDetail(LogModules.Hello, $"rejecting request from {remoteEndpoint}: old version"); PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.rejected_dontTryLater, null, socket, remoteEndpoint); return; } } if (!_connectedPeers.TryGetValue(helloPacket.FromPeerId, out var peer)) { peer = new ConnectedPeer(_localPeer, helloPacket.FromPeerId, ConnectedPeerType.fromPeerAccepted, remoteEndpoint.Address); _localPeer.WriteToLog_deepDetail(LogModules.Hello, $"accepted initial hello from peer {peer}"); lock (_connectedPeers) _connectedPeers.Add(helloPacket.FromPeerId, peer); } if (peer.Streams.Count > LocalLogicConfiguration.ConnectedPeerMaxStreamsCount) { _localPeer.WriteToLog_deepDetail(LogModules.Hello, $"rejecting request from {remoteEndpoint}: peer.Streams.Count={peer.Streams.Count} > LocalLogicConfiguration.ConnectedPeerMaxStreamsCount"); PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.rejected_dontTryLater, null, socket, remoteEndpoint); } else { var stream = peer.TryAddStream(socket, remoteEndpoint, helloPacket.StreamId); // _localPeer.WriteToLog(LogModules.Hello, $"created new stream {stream} from new peer {peer}"); var responseCpuDelayMs = (ushort)Math.Round(TimeSpan.FromTicks(unchecked (_localPeer.Time32 - requestReceivedTimestamp32)).TotalMilliseconds); PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.accepted, localPeerIdForResponse, socket, remoteEndpoint, responseCpuDelayMs, _localPeer.Configuration.RoleAsUser); } }