예제 #1
0
        public void TryParse_Returns_False_On_Code_Mismatch()
        {
            var msg = new List <byte>();

            msg.AddRange(BitConverter.GetBytes(0)); // overall length, ignored for this test.
            msg.Add((byte)MessageCode.Initialization.PeerInit);

            var r = PierceFirewall.TryFromByteArray(msg.ToArray(), out var result);

            Assert.False(r);
            Assert.Null(result);
        }
예제 #2
0
        public void TryParse_Returns_Expected_Data(int token)
        {
            var msg = new List <byte>();

            msg.AddRange(BitConverter.GetBytes(0)); // overall length, ignored for this test.
            msg.Add((byte)MessageCode.Initialization.PierceFirewall);

            msg.AddRange(BitConverter.GetBytes(token));

            // omit token
            var r = PierceFirewall.TryFromByteArray(msg.ToArray(), out var result);

            Assert.True(r);
            Assert.NotNull(result);

            Assert.Equal(token, result.Token);
        }
예제 #3
0
        /// <summary>
        ///     Handle <see cref="IListener.Accepted"/> events.
        /// </summary>
        /// <param name="sender">The originating <see cref="IListener"/> instance.</param>
        /// <param name="connection">The accepted connection.</param>
        public async void HandleConnection(object sender, IConnection connection)
        {
            Diagnostic.Debug($"Accepted incoming connection from {connection.IPEndPoint.Address}:{SoulseekClient.Listener.Port} (id: {connection.Id})");

            try
            {
                var lengthBytes = await connection.ReadAsync(4).ConfigureAwait(false);

                var length = BitConverter.ToInt32(lengthBytes, 0);

                var bodyBytes = await connection.ReadAsync(length).ConfigureAwait(false);

                byte[] message = lengthBytes.Concat(bodyBytes).ToArray();

                if (PeerInit.TryFromByteArray(message, out var peerInit))
                {
                    // this connection is the result of an unsolicited connection from the remote peer, either to request info or
                    // browse, or to send a file.
                    Diagnostic.Debug($"PeerInit for connection type {peerInit.ConnectionType} received from {peerInit.Username} ({connection.IPEndPoint.Address}:{SoulseekClient.Listener.Port}) (id: {connection.Id})");

                    if (peerInit.ConnectionType == Constants.ConnectionType.Peer)
                    {
                        await SoulseekClient.PeerConnectionManager.AddMessageConnectionAsync(
                            peerInit.Username,
                            connection).ConfigureAwait(false);
                    }
                    else if (peerInit.ConnectionType == Constants.ConnectionType.Transfer)
                    {
                        var(transferConnection, remoteToken) = await SoulseekClient.PeerConnectionManager.AddTransferConnectionAsync(
                            peerInit.Username,
                            peerInit.Token,
                            connection).ConfigureAwait(false);

                        SoulseekClient.Waiter.Complete(new WaitKey(Constants.WaitKey.DirectTransfer, peerInit.Username, remoteToken), transferConnection);
                    }
                    else if (peerInit.ConnectionType == Constants.ConnectionType.Distributed)
                    {
                        await SoulseekClient.DistributedConnectionManager.AddChildConnectionAsync(
                            peerInit.Username,
                            connection).ConfigureAwait(false);
                    }
                }
                else if (PierceFirewall.TryFromByteArray(message, out var pierceFirewall))
                {
                    // this connection is the result of a ConnectToPeer request sent to the user, and the incoming message will
                    // contain the token that was provided in the request. Ensure this token is among those expected, and use it
                    // to determine the username of the remote user.
                    if (SoulseekClient.PeerConnectionManager.PendingSolicitations.TryGetValue(pierceFirewall.Token, out var peerUsername))
                    {
                        Diagnostic.Debug($"Peer PierceFirewall with token {pierceFirewall.Token} received from {peerUsername} ({connection.IPEndPoint.Address}:{SoulseekClient.Listener.Port}) (id: {connection.Id})");
                        SoulseekClient.Waiter.Complete(new WaitKey(Constants.WaitKey.SolicitedPeerConnection, peerUsername, pierceFirewall.Token), connection);
                    }
                    else if (SoulseekClient.DistributedConnectionManager.PendingSolicitations.TryGetValue(pierceFirewall.Token, out var distributedUsername))
                    {
                        Diagnostic.Debug($"Distributed PierceFirewall with token {pierceFirewall.Token} received from {distributedUsername} ({connection.IPEndPoint.Address}:{SoulseekClient.Listener.Port}) (id: {connection.Id})");
                        SoulseekClient.Waiter.Complete(new WaitKey(Constants.WaitKey.SolicitedDistributedConnection, distributedUsername, pierceFirewall.Token), connection);
                    }
                    else
                    {
                        throw new ConnectionException($"Unknown PierceFirewall attempt with token {pierceFirewall.Token} from {connection.IPEndPoint.Address}:{connection.IPEndPoint.Port} (id: {connection.Id})");
                    }
                }
                else
                {
                    throw new ConnectionException($"Unrecognized initialization message: {BitConverter.ToString(message)} ({message.Length} bytes, id: {connection.Id})");
                }
            }
            catch (Exception ex)
            {
                Diagnostic.Debug($"Failed to initialize direct connection from {connection.IPEndPoint.Address}:{connection.IPEndPoint.Port}: {ex.Message}");
                connection.Disconnect(exception: ex);
                connection.Dispose();
            }
        }