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); } }
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(); } }