예제 #1
0
        public async Task <IPAddress> GetExternalAddressAsync(CancellationToken cancel_token)
        {
            int tries = 1;

retry:
            cancel_token.ThrowIfCancellationRequested();
            using (var client = new UdpClient()) {
                var cancel_source = CancellationTokenSource.CreateLinkedTokenSource(
                    new CancellationTokenSource(250 * tries).Token,
                    cancel_token);
                var cancel = cancel_source.Token;
                cancel.Register(() => client.Close(), false);
                try {
                    var bytes = new byte[] { PMPVersion, PMPOpExternalPort };
                    await client.SendAsync(bytes, bytes.Length, new IPEndPoint(this.DeviceAddress, PMPPort)).ConfigureAwait(false);

                    var msg = await client.ReceiveAsync().ConfigureAwait(false);

                    if (!msg.RemoteEndPoint.Address.Equals(this.DeviceAddress) || msg.Buffer.Length < 12)
                    {
                        if (tries++ < PMPTries)
                        {
                            goto retry;
                        }
                        return(null);
                    }
                    var ver         = BinaryAccessor.GetByte(msg.Buffer, 0);
                    var opcode      = BinaryAccessor.GetByte(msg.Buffer, 1);
                    var err         = BinaryAccessor.GetUInt16BE(msg.Buffer, 2);
                    var time        = BinaryAccessor.GetUInt32BE(msg.Buffer, 4);
                    var external_ip = BinaryAccessor.GetIPv4AddressBE(msg.Buffer, 8);
                    if (ver != PMPVersion || opcode != PMPOpResultExternalPort || err != 0)
                    {
                        if (tries++ < PMPTries)
                        {
                            goto retry;
                        }
                        return(null);
                    }
                    this.LastTimestamp = time;
                    return(external_ip);
                }
                catch (SocketException) { }
                catch (ObjectDisposedException) { }
                if (tries++ < PMPTries)
                {
                    goto retry;
                }
                return(null);
            }
        }
예제 #2
0
        private async Task <MappedPort> MapAsyncInternal(
            MappingProtocol protocol,
            int port,
            int lifetime,
            CancellationToken cancel_token)
        {
            int tries = 1;

retry:
            cancel_token.ThrowIfCancellationRequested();
            using (var client = new UdpClient())
                using (var cancel_source = CancellationTokenSource.CreateLinkedTokenSource(cancel_token))
                    using (cancel_source.Token.Register(() => client.Close(), false)) {
                        cancel_source.CancelAfter(250 * tries);
                        try {
                            var bytes = new byte[12];
                            BinaryAccessor.PutByte(bytes, 0, PMPVersion);
                            switch (protocol)
                            {
                            case MappingProtocol.TCP:
                                BinaryAccessor.PutByte(bytes, 1, PMPOpMapTcp);
                                break;

                            case MappingProtocol.UDP:
                                BinaryAccessor.PutByte(bytes, 1, PMPOpMapUdp);
                                break;
                            }
                            BinaryAccessor.PutUInt16BE(bytes, 2, 0);
                            BinaryAccessor.PutUInt16BE(bytes, 4, port);
                            BinaryAccessor.PutUInt16BE(bytes, 6, port);
                            BinaryAccessor.PutUInt32BE(bytes, 8, lifetime);

                            await client.SendAsync(bytes, bytes.Length, new IPEndPoint(this.DeviceAddress, PMPPort)).ConfigureAwait(false);

                            var msg = await client.ReceiveAsync().ConfigureAwait(false);

                            if (!msg.RemoteEndPoint.Address.Equals(this.DeviceAddress) || msg.Buffer.Length < 16)
                            {
                                if (tries++ < PMPTries)
                                {
                                    goto retry;
                                }
                                throw new PortMappingException();
                            }
                            var ver             = BinaryAccessor.GetByte(msg.Buffer, 0);
                            var opcode          = BinaryAccessor.GetByte(msg.Buffer, 1);
                            var err             = BinaryAccessor.GetUInt16BE(msg.Buffer, 2);
                            var time            = BinaryAccessor.GetUInt32BE(msg.Buffer, 4);
                            var internal_port   = BinaryAccessor.GetUInt16BE(msg.Buffer, 8);
                            var external_port   = BinaryAccessor.GetUInt16BE(msg.Buffer, 10);
                            var mapped_lifetime = BinaryAccessor.GetUInt32BE(msg.Buffer, 12);
                            if (ver != PMPVersion)
                            {
                                if (tries++ < PMPTries)
                                {
                                    goto retry;
                                }
                                throw new PortMappingException();
                            }
                            switch (protocol)
                            {
                            case MappingProtocol.TCP:
                                if (opcode != PMPOpResultMapTcp)
                                {
                                    if (tries++ < PMPTries)
                                    {
                                        goto retry;
                                    }
                                    throw new PortMappingException();
                                }
                                break;

                            case MappingProtocol.UDP:
                                if (opcode != PMPOpResultMapUdp)
                                {
                                    if (tries++ < PMPTries)
                                    {
                                        goto retry;
                                    }
                                    throw new PortMappingException();
                                }
                                break;
                            }
                            if (err != 0)
                            {
                                if (tries++ < PMPTries)
                                {
                                    goto retry;
                                }
                                throw new PortMappingException();
                            }
                            this.LastTimestamp = time;
                            return(new MappedPort(
                                       this,
                                       protocol,
                                       internal_port,
                                       external_port,
                                       DateTime.Now.AddSeconds(mapped_lifetime)));
                        }
                        catch (SocketException) { }
                        catch (ObjectDisposedException) { }
                        if (tries++ < PMPTries)
                        {
                            goto retry;
                        }
                        throw new PortMappingException();
                    }
        }