Beispiel #1
0
        /// <summary>
        /// the only procedure which creates/adds streams
        /// manager thread
        /// this will initiate hello-level packets to remote peer
        /// </summary>
        /// <param name="streamId">
        /// if null, it generates random ID, using optional notAllowedStreamIds
        /// </param>
        /// <returns>
        /// null is stream with this StreamId already exists
        /// </returns>
        internal ConnectedPeerStream TryAddStream(SocketWithReceiver socket, IPEndPoint remoteEP, StreamId streamId = null, IEnumerable <StreamId> notAllowedStreamIds = null)
        {
            if (streamId == null)
            {
_retry:
                streamId = _localPeer.Manager.CreateNewUniqueStreamId();
                if (Streams.ContainsKey(streamId))
                {
                    goto _retry;
                }
                if (notAllowedStreamIds != null)
                {
                    if (notAllowedStreamIds.Any(x => x.Equals(streamId)))
                    {
                        goto _retry;
                    }
                }
            }
            else
            {
                if (_localPeer.Manager.IsItUniqueStreamId(streamId) == false)
                {
                    return(null);
                }
            }

            var r = new ConnectedPeerStream(_localPeer, this, streamId, remoteEP, socket);

            lock (Streams)
                Streams.Add(streamId, r);
            socket.OnCreatedDestroyedStream(r, true);
            return(r);
        }
Beispiel #2
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);
        }
Beispiel #3
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));
 }
Beispiel #4
0
        internal void ProcessReceivedNat1TestRequest(SocketWithReceiver socket, byte[] udpData, IPEndPoint remoteEndpoint) // receiver thread
        {
            // todo put some limits here per endpoint? or we don't care?
            var request  = NatTest1RequestPacket.Decode(udpData);
            var response = new NatTest1ResponsePacket {
                RequesterEndpoint = remoteEndpoint, Token32 = request.Token32
            };
            var responseData = response.Encode();

            socket.UdpSocket.Send(responseData, responseData.Length, remoteEndpoint);
        }
Beispiel #5
0
 /// <summary>
 /// receiver thread
 /// changes state of connected peer
 /// </summary>
 internal void ProcessReceivedHello(byte[] data, IPEndPoint remoteEndpoint, SocketWithReceiver socket)
 {
     // enqueue into manager thread // reduce load of the receiver thread
     _actionsQueue.Enqueue(() =>
     {
         var helloPacket = new PeerHelloPacket(data);
         if (helloPacket.ToPeerId == null)
         {
             if (helloPacket.Status.IsSetupOrPing())
             {
                 if (_localPeer.Configuration.RoleAsCoordinator)
                 {
                     ProcessReceivedHello_SetupRequestFromNewPeer(helloPacket, remoteEndpoint, socket, _localPeer.LocalPeerId);
                 }
                 else
                 {
                     _localPeer.Firewall.OnUnauthenticatedReceivedPacket(remoteEndpoint);
                     PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.rejected_dontTryLater, null, socket, remoteEndpoint);
                 }
             }
             else
             {
                 _localPeer.Firewall.OnUnauthenticatedReceivedPacket(remoteEndpoint);
             }
         }
         else if (helloPacket.ToPeerId.Equals(_localPeer.LocalPeerId) == false)
         { // bad ToPeerId  // can happen if this peer restarts
             _localPeer.Firewall.OnUnauthenticatedReceivedPacket(remoteEndpoint);
             if (helloPacket.Status.IsSetupOrPing())
             {
                 PeerHelloPacket.Respond(helloPacket, PeerHelloRequestStatus.rejected_tryCleanSetup, null, socket, remoteEndpoint);
             }
         }
         else if (_pendingPeers.ContainsKey(remoteEndpoint))
         {// correct ToPeerId and remote endpoint is in _initiallyNotRespondedServers
             ProcessReceivedHello_FromPendingPeer(helloPacket, remoteEndpoint);
         }
         else
         {     // correct ToPeerId
             if (_connectedPeers.TryGetValue(helloPacket.FromPeerId, out var connectedPeer))
             { // packet from already connected peer
                 ProcessReceivedHello_FromExistingPeer(helloPacket, remoteEndpoint, socket, connectedPeer);
             }
             else if (helloPacket.Status.IsSetupOrPing())
             { // FromPeerId is unknown, ToPeerId is this one // request to set up connection from new peer
                 ProcessReceivedHello_SetupRequestFromNewPeer(helloPacket, remoteEndpoint, socket, null);
             }
         }
     });
 }
Beispiel #6
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;
            }
        }
Beispiel #7
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);
            }
        }
Beispiel #8
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);
            }
        }