Exemple #1
0
        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
            }
        }
Exemple #2
0
        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());
            }
        }
Exemple #3
0
        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
        }
Exemple #4
0
        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);
        }
Exemple #5
0
 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));
 }
Exemple #6
0
        /// <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);
            }
        }
Exemple #7
0
        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());
            }
        }
Exemple #8
0
        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);
            }
        }
Exemple #9
0
        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;
            }
        }
Exemple #10
0
        /// <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);
            }
        }