//internal class SockInterfacePair //{ // internal UdpSocket sock; // internal IPAddress extInterface; // public bool Initialized; // internal SockInterfacePair(UdpSocket sock, IPAddress extIntf) // { // this.sock = sock; // this.extInterface = extIntf; // Initialized = false; // } //} // Apparently binding to the same ports on UDPSender and UDPListener causes problems in unicast. // Sharing the socket though, allows us to tunnel through firewalls as data is sent and received // on the same endpoint. // This region of code enables sharing sockets between the two classes. //internal static SockInterfacePair GetSharedSocket(IPEndPoint endPoint) //{ // lock (socks) // { // object sockObj = socks[endPoint]; // if (sockObj != null) // { // SockInterfacePair sip = (SockInterfacePair)sockObj; // ++sip.sock.refCount; // return sip; // } // else // { // // Create the socket // UdpSocket sock = new UdpSocket(endPoint.AddressFamily); // // Get the External Interface, save it for future use // IPAddress externalInterface = Utility.GetLocalRoutingInterface(endPoint.Address); // if (externalInterface == null) // { // // Pri3: Do something more helpful here // throw new Exception(Strings.UnableToFindLocalRoutingInterface); // } // if (Utility.IsMulticast(endPoint.Address)) // { // // Allow multiple binds to this socket, as it will still function properly // // (this is only the case if it is a multicast socket. Unicast sockets fail to // // receive all data on all sockets) // sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, -1); // // We don't join the multicast group here, because we may not want to listen // // to our own data (halfing our throughput). jasonv - 10/28/2004 // } // // Add the socket to the hashtable // SockInterfacePair sip = new SockInterfacePair(sock, externalInterface); // socks.Add(endPoint, sip); // // Increase the socket's reference count // ++sock.refCount; // return sip; // } // } //} //internal static void ReleaseSharedSocket(IPEndPoint endPoint, UdpSocket sock) //{ // object sockObj = socks[endPoint]; // if (sockObj == null) // throw new InvalidOperationException(Strings.SockDoesNotExistAsASharedSocket); // lock (socks) // { // if (--sock.refCount <= 0) // { // // Leave the multicast group // if (Utility.IsMulticast(endPoint.Address)) // { // try // { // if (endPoint.AddressFamily == AddressFamily.InterNetworkV6) // { // IPv6MulticastOption mo = new IPv6MulticastOption(endPoint.Address); // sock.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.DropMembership, mo); // } // else // { // MulticastOption mo = new MulticastOption(endPoint.Address); // sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DropMembership, mo); // } // } // catch { } // The user of the socket *may* not have joined the multicast group (?) // } // // Remove ourselves from the shared pool // socks.Remove(endPoint); // // Close the socket // try // { // sock.Close(); // } // catch (ObjectDisposedException) { } // } // } //} internal static void ReleaseSocket(IPEndPoint endPoint, UdpSocket sock) { // Leave the multicast group if (Utility.IsMulticast(endPoint.Address)) { try { if (endPoint.AddressFamily == AddressFamily.InterNetworkV6) { IPv6MulticastOption mo = new IPv6MulticastOption(endPoint.Address); sock.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.DropMembership, mo); } else { MulticastOption mo = new MulticastOption(endPoint.Address); sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DropMembership, mo); } } catch { } // The user of the socket *may* not have joined the multicast group (?) } // Close the socket try { sock.Close(); } catch (ObjectDisposedException) { } }
//returns the port number used... public static int CreateListenSocketsOnUniquePort(IPAddress ipv4Address, IPAddress ipv6Address, int receiveBufferSize, int timeToLive, out UdpSocket ipv4Socket, out UdpSocket ipv6Socket) { // We need both IPv4 and IPv6 on the same port. We can't atomicly bind for IPv4 and IPv6, // so we try 10 times, which even with a 50% failure rate will statistically succeed 99.9% of the time. // // We look in the range of 49152-65534 for Vista default behavior parity. // http://www.iana.org/assignments/port-numbers // // We also grab the 10 random numbers in a row to reduce collisions between multiple people somehow // colliding on the same seed. const int retries = 10; const int lowWatermark = 49152; const int highWatermark = 65535; ipv4Socket = null; ipv6Socket = null; int[] portNumbers = new int[retries]; Random randomNumberGenerator = new Random(AppDomain.CurrentDomain.GetHashCode() | Environment.TickCount); for (int i = 0; i < retries; i++) { portNumbers[i] = randomNumberGenerator.Next(lowWatermark, highWatermark); } int port = -1; for (int i = 0; i < retries; i++) { port = portNumbers[i]; try { ipv4Socket = UdpUtility.CreateUnicastListenSocket(ipv4Address, ref port, receiveBufferSize, timeToLive); ipv6Socket = UdpUtility.CreateUnicastListenSocket(ipv6Address, ref port, receiveBufferSize, timeToLive); break; } catch (AddressAlreadyInUseException) { if (ipv4Socket != null) { ipv4Socket.Close(); ipv4Socket = null; } ipv6Socket = null; } catch (AddressAccessDeniedException) { if (ipv4Socket != null) { ipv4Socket.Close(); ipv4Socket = null; } ipv6Socket = null; } } if (ipv4Socket == null) { throw FxTrace.Exception.AsError(new AddressAlreadyInUseException(SR.UniquePortNotAvailable)); } Fx.Assert(ipv4Socket != null, "An exception should have been thrown if the ipv4Socket socket is null"); Fx.Assert(ipv6Socket != null, "An exception should have been thrown if the ipv6Socket socket is null"); Fx.Assert(port > 0, "The port number should have been greater than 0. Actual value was " + port); return port; }