public override async Task OnConnectedAsync(ConnectionContext connection)
        {
            if (_connectionLoops.ContainsKey(connection.RemoteEndPoint))
            {
                _logger.LogWarning($"another inbound connection from a known peer: {connection.RemoteEndPoint.ToEndpointString()}. Ignoring");
                return;
            }

            _logger.LogDebug($"New inbound connection from {connection.RemoteEndPoint.ToEndpointString()}");
            var(descriptor, writeReceiver) = descriptorFactory.GetNewSocket(connection.Transport.Output);
            // TODO: using "BTC" here is not clean.
            var peerMan = PeerManagerProvider.GetPeerManager("BTC");

            peerMan.NewInboundConnection(descriptor);
            Func <Task> cleanup = async() =>
            {
                _connectionLoops.TryRemove(connection.RemoteEndPoint, out _);
                await _repository.RemoveRemoteEndPoint(connection.RemoteEndPoint);
            };
            await _repository.SetRemoteEndPoint(connection.RemoteEndPoint);

            var conn = new ConnectionLoop(connection.Transport, descriptor, peerMan, writeReceiver, EventNotify.Writer, _loggerFactory.CreateLogger <ConnectionLoop>(), cleanup);

            _connectionLoops.TryAdd(connection.RemoteEndPoint, conn);
            conn.Start(connection.ConnectionClosed);
            await conn.ExecutionTask;
        }
예제 #2
0
        private (ConnectionLoop, SocketDescriptor) CreateConnection(IDuplexPipe pipe)
        {
            var(socketDescriptor, writeReceiver) = _socketDescriptorFactory.GetNewSocket(pipe.Output);
            var conn = new ConnectionLoop(pipe, socketDescriptor, PeerManager, writeReceiver, EventNotify.Writer);

            return(conn, socketDescriptor);
        }
        /// <summary>
        /// Returns `false` if the peer is already connected. otherwise return `true`.
        /// </summary>
        /// <param name="remoteEndPoint"></param>
        /// <param name="pubkey"></param>
        /// <param name="ct"></param>
        /// <returns>true if the peer is unknown</returns>
        public async ValueTask <bool> NewOutbound(EndPoint remoteEndPoint, PubKey pubkey, CancellationToken ct = default)
        {
            if (remoteEndPoint == null)
            {
                throw new ArgumentNullException(nameof(remoteEndPoint));
            }
            if (pubkey == null)
            {
                throw new ArgumentNullException(nameof(pubkey));
            }
            if (_connectionLoops.ContainsKey(remoteEndPoint))
            {
                _logger.LogError($"We have already connected to: {remoteEndPoint.ToEndpointString()}.");
                return(false);
            }

            try
            {
                var connectionContext = await _connectionFactory.ConnectAsync(remoteEndPoint, ct);

                var(descriptor, writeReceiver) = descriptorFactory.GetNewSocket(connectionContext.Transport.Output);
                var peerMan     = PeerManagerProvider.GetPeerManager("BTC");
                var initialSend = peerMan.NewOutboundConnection(descriptor, pubkey.ToBytes());
                await connectionContext.Transport.Output.WriteAsync(initialSend, ct);

                var flushResult = connectionContext.Transport.Output.FlushAsync(ct);
                if (!flushResult.IsCompleted)
                {
                    await flushResult.ConfigureAwait(false);
                }

                Func <Task> cleanup = async() =>
                {
                    _connectionLoops.TryRemove(connectionContext.RemoteEndPoint, out _);
                    await _repository.RemoveRemoteEndPoint(connectionContext.RemoteEndPoint, ct);
                };
                await _repository.SetRemoteEndPoint(remoteEndPoint, ct);

                var conn = new ConnectionLoop(connectionContext.Transport, descriptor, peerMan,
                                              writeReceiver, EventNotify.Writer, _loggerFactory.CreateLogger <ConnectionLoop>(), cleanup);
                _connectionLoops.TryAdd(remoteEndPoint, conn);
                Task.Run(() => conn.Start(ct));
            }

            catch (SocketException ex) when(ex.SocketErrorCode == SocketError.ConnectionRefused)
            {
                _logger.LogError($"{ex.Message}:{Environment.NewLine}{ex.StackTrace}");
                return(false);
            }

            return(true);
        }