Example #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);
            }
        }
Example #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);
            }
        }