/// <summary> /// Resolves local IP to public IP using STUN. /// </summary> /// <param name="stunServer">STUN server.</param> /// <param name="port">STUN server port. Default port is 3478.</param> /// <param name="localIP">Local IP address.</param> /// <returns>Returns public IP address.</returns> /// <exception cref="ArgumentNullException">Is raised when <b>stunServer</b> or <b>localIP</b> is null reference.</exception> /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception> /// <exception cref="IOException">Is raised when no connection to STUN server.</exception> public static IPAddress GetPublicIP(string stunServer, int port, IPAddress localIP) { if (stunServer == null) { throw new ArgumentNullException("stunServer"); } if (stunServer == "") { throw new ArgumentException("Argument 'stunServer' value must be specified."); } if (port < 1) { throw new ArgumentException("Invalid argument 'port' value."); } if (localIP == null) { throw new ArgumentNullException("localIP"); } if (!Net_Utils.IsPrivateIP(localIP)) { return(localIP); } STUN_Result result = Query(stunServer, port, Net_Utils.CreateSocket(new IPEndPoint(localIP, 0), ProtocolType.Udp)); if (result.PublicEndPoint != null) { return(result.PublicEndPoint.Address); } else { throw new IOException("Failed to STUN public IP address. STUN server name is invalid or firewall blocks STUN."); } }
/// <summary> /// Starts UDP server. /// </summary> public void Start() { if (m_IsRunning) { return; } m_IsRunning = true; m_StartTime = DateTime.Now; m_pDataReceivers = new List <UDP_DataReceiver>(); // Run only if we have some listening point. if (m_pBindings != null) { // We must replace IPAddress.Any to all available IPs, otherwise it's impossible to send // reply back to UDP packet sender on same local EP where packet received. This is very // important when clients are behind NAT. List <IPEndPoint> listeningEPs = new List <IPEndPoint>(); foreach (IPEndPoint ep in m_pBindings) { if (ep.Address.Equals(IPAddress.Any)) { // Add localhost. IPEndPoint epLocalhost = new IPEndPoint(IPAddress.Loopback, ep.Port); if (!listeningEPs.Contains(epLocalhost)) { listeningEPs.Add(epLocalhost); } // Add all host IPs. foreach (IPAddress ip in System.Net.Dns.GetHostAddresses("")) { IPEndPoint epNew = new IPEndPoint(ip, ep.Port); if (!listeningEPs.Contains(epNew)) { listeningEPs.Add(epNew); } } } else { if (!listeningEPs.Contains(ep)) { listeningEPs.Add(ep); } } } uint IOC_IN = 0x80000000; uint IOC_VENDOR = 0x18000000; uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; // Create sockets. m_pSockets = new List <Socket>(); foreach (IPEndPoint ep in listeningEPs) { try{ Socket socket = Net_Utils.CreateSocket(ep, ProtocolType.Udp); // To avoid : "An existing connection was forcibly closed by the remote host" socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null); m_pSockets.Add(socket); // Create UDP data receivers. for (int i = 0; i < m_ReceiversPerSocket; i++) { UDP_DataReceiver receiver = new UDP_DataReceiver(socket); receiver.PacketReceived += delegate(object s, UDP_e_PacketReceived e){ try{ ProcessUdpPacket(e); } catch (Exception x) { OnError(x); } }; receiver.Error += delegate(object s, ExceptionEventArgs e){ OnError(e.Exception); }; m_pDataReceivers.Add(receiver); receiver.Start(); } } catch (Exception x) { OnError(x); } } // Create round-robin send sockets. NOTE: We must skip localhost, it can't be used // for sending out of server. m_pSendSocketsIPv4 = new CircleCollection <Socket>(); m_pSendSocketsIPv6 = new CircleCollection <Socket>(); foreach (Socket socket in m_pSockets) { if (((IPEndPoint)socket.LocalEndPoint).AddressFamily == AddressFamily.InterNetwork) { if (!((IPEndPoint)socket.LocalEndPoint).Address.Equals(IPAddress.Loopback)) { m_pSendSocketsIPv4.Add(socket); } } else if (((IPEndPoint)socket.LocalEndPoint).AddressFamily == AddressFamily.InterNetworkV6) { m_pSendSocketsIPv6.Add(socket); } } } }
/// <summary> /// Starts UDP server. /// </summary> public void Start() { if (m_IsRunning) { return; } m_IsRunning = true; m_StartTime = DateTime.Now; m_pQueuedPackets = new Queue <UdpPacket>(); // Run only if we have some listening point. if (m_pBindings != null) { // We must replace IPAddress.Any to all available IPs, otherwise it's impossible to send // reply back to UDP packet sender on same local EP where packet received. This is very // important when clients are behind NAT. List <IPEndPoint> listeningEPs = new List <IPEndPoint>(); foreach (IPEndPoint ep in m_pBindings) { if (ep.Address.Equals(IPAddress.Any)) { // Add localhost. IPEndPoint epLocalhost = new IPEndPoint(IPAddress.Loopback, ep.Port); if (!listeningEPs.Contains(epLocalhost)) { listeningEPs.Add(epLocalhost); } // Add all host IPs. foreach (IPAddress ip in System.Net.Dns.GetHostAddresses("")) { IPEndPoint epNew = new IPEndPoint(ip, ep.Port); if (!listeningEPs.Contains(epNew)) { listeningEPs.Add(epNew); } } } else { if (!listeningEPs.Contains(ep)) { listeningEPs.Add(ep); } } } // Create sockets. m_pSockets = new List <Socket>(); foreach (IPEndPoint ep in listeningEPs) { try{ m_pSockets.Add(Net_Utils.CreateSocket(ep, ProtocolType.Udp)); } catch (Exception x) { OnError(x); } } // Create round-robin send sockets. NOTE: We must skip localhost, it can't be used // for sending out of server. m_pSendSocketsIPv4 = new CircleCollection <Socket>(); m_pSendSocketsIPv6 = new CircleCollection <Socket>(); foreach (Socket socket in m_pSockets) { if (((IPEndPoint)socket.LocalEndPoint).AddressFamily == AddressFamily.InterNetwork) { if (!((IPEndPoint)socket.LocalEndPoint).Address.Equals(IPAddress.Loopback)) { m_pSendSocketsIPv4.Add(socket); } } else if (((IPEndPoint)socket.LocalEndPoint).AddressFamily == AddressFamily.InterNetworkV6) { m_pSendSocketsIPv6.Add(socket); } } Thread tr = new Thread(new ThreadStart(this.ProcessIncomingUdp)); tr.Start(); Thread tr2 = new Thread(new ThreadStart(this.ProcessQueuedPackets)); tr2.Start(); } }