示例#1
0
        /// <summary>
        /// Queries the STUN server with the specified IP address for the public IP
        /// address of the requesting host.
        /// </summary>
        /// <param name="address">The IP address of the STUN server to query.</param>
        /// <param name="port">The port on which the STUN service is running at
        /// the specified host.</param>
        /// <param name="timeout">The maximum number of milliseconds to wait for
        /// a server response before returning to the caller.</param>
        /// <returns>The public IP address of the requesting host.</returns>
        /// <exception cref="ArgumentNullException">The address parameter is
        /// null.</exception>
        /// <exception cref="ArgumentOutOfRangeException">The port is not between
        /// 0 and 65535.</exception>
        /// <exception cref="ProtocolViolationException">The specified STUN
        /// server returned an erroneous response.</exception>
        /// <exception cref="SocketException">The specified hostname could not be
        /// resolved, or an error occurred while sending the request or while
        /// retrieving the response, or the specified STUN server could not be
        /// reached.</exception>
        /// <exception cref="TimeoutException">The specified timeout has
        /// expired.</exception>
        public static IPAddress Query(IPAddress address, int port = 3478,
                                      int timeout = Int32.MaxValue)
        {
            address.ThrowIfNull("address");
            port.ThrowIfOutOfRange("port", 0, 65535);
            IPEndPoint IpEp    = new IPEndPoint(address, port);
            var        request = new BindingRequest().Serialize();
            int        rto     = initialRto;

            using (UdpClient udp = new UdpClient()) {
                // The timeout mechanism is similar to TCP. For details,
                // refer to RFC 5389, Section 7.2.1. Sending over UDP.
                for (int tries = 0; tries < rc; tries++)
                {
                    // Transmit the datagram.
                    udp.Send(request, request.Length, IpEp);
                    // Set the timeout value on the socket.
                    udp.Client.ReceiveTimeout = rto;
                    try {
                        byte[] datagram = udp.Receive(ref IpEp);
                        return(BindingResponse.Deserialize(datagram).Address);
                    } catch (SocketException e) {
                        if (e.ErrorCode != connectionTimeout)
                        {
                            throw;
                        }
                        timeout = timeout - rto;
                        if (timeout <= 0)
                        {
                            throw new TimeoutException("The timeout has expired.");
                        }
                    } catch (SerializationException) {
                        throw new ProtocolViolationException("The STUN " +
                                                             "Binding Response is invalid.");
                    }
                    // Increase the timeout value.
                    if (tries < (rc - 1))
                    {
                        rto = rto * 2;
                    }
                    else
                    {
                        rto = initialRto * rm;
                    }
                    if (timeout < rto)
                    {
                        rto = timeout;
                    }
                }
                // Give up.
                throw new SocketException(connectionTimeout);
            }
        }
示例#2
0
        public static IPAddress Query(IPAddress address, int port = 0xd96, int timeout = 0x7fffffff)
        {
            address.ThrowIfNull <IPAddress>("address");
            port.ThrowIfOutOfRange("port", 0, 0xffff);
            IPEndPoint endPoint = new IPEndPoint(address, port);

            byte[] dgram = new BindingRequest(null).Serialize();
            int    num   = 500;

            using (UdpClient client = new UdpClient())
            {
                for (int i = 0; i < 7; i++)
                {
                    client.Send(dgram, dgram.Length, endPoint);
                    client.Client.ReceiveTimeout = num;
                    try
                    {
                        return(BindingResponse.Deserialize(client.Receive(ref endPoint)).Address);
                    }
                    catch (SocketException exception)
                    {
                        if (exception.ErrorCode != 0x274c)
                        {
                            throw;
                        }
                        timeout -= num;
                        if (timeout <= 0)
                        {
                            throw new TimeoutException("The timeout has expired.");
                        }
                    }
                    catch (SerializationException)
                    {
                        throw new ProtocolViolationException("The STUN Binding Response is invalid.");
                    }
                    if (i < 6)
                    {
                        num *= 2;
                    }
                    else
                    {
                        num = 0x1f40;
                    }
                    if (timeout < num)
                    {
                        num = timeout;
                    }
                }
                throw new SocketException(0x274c);
            }
        }
示例#3
0
		/// <summary>
		/// Queries the STUN server with the specified IP address for the public IP
		/// address of the requesting host.
		/// </summary>
		/// <param name="address">The IP address of the STUN server to query.</param>
		/// <param name="port">The port on which the STUN service is running at
		/// the specified host.</param>
		/// <param name="timeout">The maximum number of milliseconds to wait for
		/// a server response before returning to the caller.</param>
		/// <returns>The public IP address of the requesting host.</returns>
		/// <exception cref="ArgumentNullException">The address parameter is
		/// null.</exception>
		/// <exception cref="ArgumentOutOfRangeException">The port is not between
		/// 0 and 65535.</exception>
		/// <exception cref="ProtocolViolationException">The specified STUN
		/// server returned an erroneous response.</exception>
		/// <exception cref="SocketException">The specified hostname could not be
		/// resolved, or an error occurred while sending the request or while
		/// retrieving the response, or the specified STUN server could not be
		/// reached.</exception>
		/// <exception cref="TimeoutException">The specified timeout has
		/// expired.</exception>
		public static IPAddress Query(IPAddress address, int port = 3478,
			int timeout = Int32.MaxValue) {
			address.ThrowIfNull("address");
			port.ThrowIfOutOfRange("port", 0, 65535);
			IPEndPoint IpEp = new IPEndPoint(address, port);
			var request = new BindingRequest().Serialize();
			int rto = initialRto;
			using (UdpClient udp = new UdpClient()) {
				// The timeout mechanism is similar to TCP. For details,
				// refer to RFC 5389, Section 7.2.1. Sending over UDP.
				for (int tries = 0; tries < rc; tries++) {
					// Transmit the datagram.
					udp.Send(request, request.Length, IpEp);
					// Set the timeout value on the socket.
					udp.Client.ReceiveTimeout = rto;
					try {
						byte[] datagram = udp.Receive(ref IpEp);
						return BindingResponse.Deserialize(datagram).Address;
					} catch (SocketException e) {
						if (e.ErrorCode != connectionTimeout)
							throw;
						timeout = timeout - rto;
						if (timeout <= 0)
							throw new TimeoutException("The timeout has expired.");
					} catch (SerializationException) {
						throw new ProtocolViolationException("The STUN " +
							"Binding Response is invalid.");
					}
					// Increase the timeout value.
					if (tries < (rc - 1))
						rto = rto * 2;
					else
						rto = initialRto * rm;
					if (timeout < rto)
						rto = timeout;
				}
				// Give up.
				throw new SocketException(connectionTimeout);
			}
		}