/// <summary> /// Dispose per the IDisposable pattern /// </summary> public void Dispose() { GC.SuppressFinalize(this); if (!disposed) { disposed = true; if (sock != null) { // if we are using a reflector, send a tear-down message if (!multicastEP.Equals(nextHopEP)) { try { if (joiner != null) { joiner.Terminate(); } // send a LEAVE message; this might get lost, but that doesn't matter // because the reflector wil time out. UdpSender sender = new UdpSender(nextHopEP, 64); UdpReflectorMessage message = new UdpReflectorMessage(UdpReflectorMessageType.LEAVE, multicastEP); sender.Send(message.ToBufferChunk()); sender.Dispose(); } catch (Exception) { } } LstSocks.Socket.ReleaseSharedSocket(nextHopEP, sock); sock = null; } } }
/// <summary> /// Constructor that binds this object instance to an IPEndPoint. If you need to change settings dynamically, Dispose and recreate a new object. /// </summary> /// <param name="endPoint">IPEndPoint where to send the multicast packets -- should be in range 224.0.0.0 to 239.255.255.255</param> /// <param name="timeToLive">ushort Time To Live of the packets -- how many routers will we cross -- set to 2 for local or testing</param> public UdpSender(System.Net.IPEndPoint endPoint, ushort timeToLive) { this.endPoint = endPoint; LstSocks.Socket.SockInterfacePair sip = LstSocks.Socket.GetSharedSocket(endPoint); this.sock = sip.sock; this.externalInterface = sip.extInterface; if (Utility.IsMulticast(endPoint.Address)) { SocketOptionLevel sOL = SocketOptionLevel.IP; if (endPoint.AddressFamily == AddressFamily.InterNetworkV6) { sOL = SocketOptionLevel.IPv6; } // Set the TTL sock.SetSocketOption(sOL, SocketOptionName.MulticastTimeToLive, timeToLive); // Enable Multicast Loopback sock.SetSocketOption(sOL, SocketOptionName.MulticastLoopback, 1); } else { // Enable Unicast Loopback echoEndPoint = new IPEndPoint(externalInterface, endPoint.Port); } }
/// <summary> /// Constructor that binds this object instance to an IPEndPoint. If you need to change settings dynamically, Dispose and recreate a new object. /// </summary> /// <param name="endPoint">IPEndPoint where to send the multicast packets -- should be in range 224.0.0.0 to 239.255.255.255</param> /// <param name="timeToLive">ushort Time To Live of the packets -- how many routers will we cross -- set to 2 for local or testing</param> public UdpSender(System.Net.IPEndPoint destEndPoint, ushort timeToLive) { this.endPoint = destEndPoint; LstSocks.Socket.SockInterfacePair sip = LstSocks.Socket.GetSharedSocket(destEndPoint); this.sock = sip.sock; this.localRoutingInterface = sip.extInterface; if (Utility.IsMulticast(destEndPoint.Address)) { SocketOptionLevel sOL = SocketOptionLevel.IP; if (destEndPoint.AddressFamily == AddressFamily.InterNetworkV6) { sOL = SocketOptionLevel.IPv6; } // Set the TTL sock.SetSocketOption(sOL, SocketOptionName.MulticastTimeToLive, timeToLive); // Enable Multicast Loopback sock.SetSocketOption(sOL, SocketOptionName.MulticastLoopback, 1); } else { // Enable Unicast Loopback /// Note: If we didn't also instantiate a UdpListener, the socket won't have been bound /// to a local interface. Specifically this comes up when we use the UdpSender to transmit /// reports to a diagnostic server. In this case the loopback is not needed anyway. IPEndPoint localEndpoint = (IPEndPoint)sock.LocalEndPoint; if (localEndpoint != null) { echoEndPoint = new IPEndPoint(localRoutingInterface, localEndpoint.Port); } } }
internal asyncReceiveState(MSR.LST.Net.Sockets.Socket sock, BufferChunk bufferChunk, Queue queue, ReceivedFromCallback receivedFromCallback) { this.sock = sock; this.bufferChunk = bufferChunk; this.queue = queue; this.receivedFromCallback = receivedFromCallback; }
/// <summary> /// Constructor that binds this object instance to an IPEndPoint. If you need to change IPEndPoint dynamically, Dispose and recreate a new object. /// </summary> /// <param name="endPoint">IPEndPoint where we should be listening for IP Multicast packets.</param> /// <param name="TimeoutMilliseconds">Milliseconds before lack of a packet == a Network Timeout</param> /// <example> /// ... /// MulticastUdpListener mcListener = new MulticastUdpListener(endPoint1); /// mcListener.Receive(packetBuffer); /// mcListener.Displose(); /// /// MulticastUdpListener mcListener = new MulticastUdpListener(endPoint2); /// mcListener.Receive(packetBuffer); /// mcListener.Displose(); /// /// mcListener = null; /// ... /// </example> public UdpListener(System.Net.IPEndPoint endPoint, int timeoutMilliseconds) { LstSocks.Socket.SockInterfacePair sip = LstSocks.Socket.GetSharedSocket(endPoint); this.sock = sip.sock; this.externalInterface = sip.extInterface; this.ep = endPoint; lock (sip) { if (!sip.Initialized) { try { // Set the timeout on the socket if (timeoutMilliseconds > 0) { sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, timeoutMilliseconds); } // Set the socket to send & receive from this endpoint sock.Bind(new IPEndPoint(externalInterface, endPoint.Port)); // Make room for 80 packets plus some overhead sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, 1500 * 80); if (Utility.IsMulticast(endPoint.Address)) { if (endPoint.AddressFamily == AddressFamily.InterNetworkV6) { // Join the IPv6 Multicast group sock.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption(endPoint.Address)); } else { // Join the IPv4 Multicast group sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(endPoint.Address)); } } sip.Initialized = true; } catch { this.Dispose(); throw; } } } }
/// <summary> /// Dispose per the IDisposable pattern /// </summary> public void Dispose() { GC.SuppressFinalize(this); if (!disposed) { disposed = true; if (sock != null) { LstSocks.Socket.ReleaseSharedSocket(ep, sock); sock = null; } } }
// 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 LstSocks.Socket sock = new LstSocks.Socket(endPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); // 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("Unable to find a local routing interface, is no network present?"); } 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(); sip.sock = sock; sip.extInterface = externalInterface; socks.Add(endPoint, sip); // Increase the socket's reference count ++sock.refCount; return sip; } } }
// 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 LstSocks.Socket sock = new LstSocks.Socket(endPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); // 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(); sip.sock = sock; sip.extInterface = externalInterface; socks.Add(endPoint, sip); // Increase the socket's reference count ++sock.refCount; return(sip); } } }
/// <summary> /// This constructor is for use with a unicast reflector. This constructor sends JOIN messages /// to the given reflector endpoint. /// /// </summary> /// <param name="reflectorEP"></param> /// <param name="multicastEP"></param> /// <param name="timeout"></param> public UdpListener(IPEndPoint multicastEP, IPEndPoint reflectorEP, int timeout) { LstSocks.Socket.SockInterfacePair sip = LstSocks.Socket.GetSharedSocket(reflectorEP); this.sock = sip.sock; this.externalInterface = sip.extInterface; this.nextHopEP = reflectorEP; this.multicastEP = multicastEP; // check whether we must "force" the local port to equal the remote port -- this is done // for clients behind picky firewalls. If not, use port number 0 to indicate a "don't care" int port = 0; try { string forcePort = ConfigurationManager.AppSettings["MSR.LST.Net.ForceLocalUnicastPorts"]; bool force = Boolean.Parse(forcePort); if (force) { port = reflectorEP.Port; } } catch (Exception) { } lock (sip) { if (!sip.Initialized) { try { InitializeSocket(port, timeout); // notify the reflector of our presence... joiner = new UdpReflectorJoiner(nextHopEP, multicastEP); joiner.Start(); sip.Initialized = true; } catch { this.Dispose(); throw; } } } }
internal static void ReleaseSharedSocket(IPEndPoint endPoint, LstSocks.Socket 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) {} } } }
/// <summary> /// This constructor is used for non-reflector sessions; /// if necessary, it joins the appropriate multicast group. /// </summary> /// <param name="multicastEP"></param> /// <param name="timeoutMilliseconds"></param> public UdpListener(System.Net.IPEndPoint nextHopEP, int timeoutMilliseconds) { LstSocks.Socket.SockInterfacePair sip = LstSocks.Socket.GetSharedSocket(nextHopEP); this.sock = sip.sock; this.externalInterface = sip.extInterface; this.nextHopEP = nextHopEP; this.multicastEP = nextHopEP; lock (sip) { if (!sip.Initialized) { try { InitializeSocket(nextHopEP.Port, timeoutMilliseconds); if (Utility.IsMulticast(nextHopEP.Address)) { if (nextHopEP.AddressFamily == AddressFamily.InterNetworkV6) { // Join the IPv6 Multicast group sock.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption(nextHopEP.Address)); } else { // Join the IPv4 Multicast group sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(nextHopEP.Address)); } } sip.Initialized = true; } catch { this.Dispose(); throw; } } } }
/// <summary> /// Constructor that binds this object instance to an IPEndPoint. If you need to change settings dynamically, Dispose and recreate a new object. /// </summary> /// <param name="endPoint">IPEndPoint where to send the multicast packets -- should be in range 224.0.0.0 to 239.255.255.255</param> /// <param name="timeToLive">ushort Time To Live of the packets -- how many routers will we cross -- set to 2 for local or testing</param> public UdpSender(System.Net.IPEndPoint endPoint, ushort timeToLive) { this.endPoint = endPoint; LstSocks.Socket.SockInterfacePair sip = LstSocks.Socket.GetSharedSocket(endPoint); this.sock = sip.sock; this.externalInterface = sip.extInterface; if ( Utility.IsMulticast( endPoint.Address ) ) { SocketOptionLevel sOL = SocketOptionLevel.IP; if (endPoint.AddressFamily == AddressFamily.InterNetworkV6) { sOL = SocketOptionLevel.IPv6; } // Set the TTL sock.SetSocketOption(sOL, SocketOptionName.MulticastTimeToLive, timeToLive); // Enable Multicast Loopback sock.SetSocketOption(sOL, SocketOptionName.MulticastLoopback, 1); } else { // Enable Unicast Loopback echoEndPoint = new IPEndPoint(externalInterface, endPoint.Port); } }
/// <summary> /// Dispose per the IDisposable pattern /// </summary> public void Dispose() { GC.SuppressFinalize(this); if(!disposed) { disposed = true; if (sock != null) { LstSocks.Socket.ReleaseSharedSocket(endPoint, sock); sock = null; } } }
/// <summary> /// Dispose per the IDisposable pattern /// </summary> public void Dispose() { GC.SuppressFinalize(this); if(!disposed) { disposed = true; if (sock != null) { // if we are using a reflector, send a tear-down message if (!multicastEP.Equals(nextHopEP)) { try { if (joiner != null) joiner.Terminate(); // send a LEAVE message; this might get lost, but that doesn't matter // because the reflector wil time out. UdpSender sender = new UdpSender(nextHopEP, 64); UdpReflectorMessage message = new UdpReflectorMessage(UdpReflectorMessageType.LEAVE, multicastEP); sender.Send(message.ToBufferChunk()); sender.Dispose(); } catch (Exception) { } } LstSocks.Socket.ReleaseSharedSocket(nextHopEP, sock); sock = null; } } }
/// <summary> /// This constructor is for use with a unicast reflector. This constructor sends JOIN messages /// to the given reflector endpoint. /// /// </summary> /// <param name="reflectorEP"></param> /// <param name="multicastEP"></param> /// <param name="timeout"></param> public UdpListener(IPEndPoint multicastEP, IPEndPoint reflectorEP, int timeout) { LstSocks.Socket.SockInterfacePair sip = LstSocks.Socket.GetSharedSocket(reflectorEP); this.sock = sip.sock; this.externalInterface = sip.extInterface; this.nextHopEP = reflectorEP; this.multicastEP = multicastEP; // check whether we must "force" the local port to equal the remote port -- this is done // for clients behind picky firewalls. If not, use port number 0 to indicate a "don't care" int port = 0; try { string forcePort = ConfigurationManager.AppSettings["MSR.LST.Net.ForceLocalUnicastPorts"]; bool force = Boolean.Parse(forcePort); if (force) port = reflectorEP.Port; } catch (Exception) { } lock (sip) { if (!sip.Initialized) { try { InitializeSocket(port, timeout); // notify the reflector of our presence... joiner = new UdpReflectorJoiner(nextHopEP, multicastEP); joiner.Start(); sip.Initialized = true; } catch { this.Dispose(); throw; } } } }
/// <summary> /// This constructor is used for non-reflector sessions; /// if necessary, it joins the appropriate multicast group. /// </summary> /// <param name="multicastEP"></param> /// <param name="timeoutMilliseconds"></param> public UdpListener(System.Net.IPEndPoint nextHopEP, int timeoutMilliseconds) { LstSocks.Socket.SockInterfacePair sip = LstSocks.Socket.GetSharedSocket(nextHopEP); this.sock = sip.sock; this.externalInterface = sip.extInterface; this.nextHopEP = nextHopEP; this.multicastEP = nextHopEP; lock(sip) { if(!sip.Initialized) { try { InitializeSocket(nextHopEP.Port, timeoutMilliseconds); if(Utility.IsMulticast(nextHopEP.Address)) { if(nextHopEP.AddressFamily == AddressFamily.InterNetworkV6) { // Join the IPv6 Multicast group sock.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption(nextHopEP.Address)); } else { // Join the IPv4 Multicast group sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(nextHopEP.Address)); } } sip.Initialized = true; } catch { this.Dispose(); throw; } } } }
/// <summary> /// Constructor that binds this object instance to an IPEndPoint. If you need to change IPEndPoint dynamically, Dispose and recreate a new object. /// </summary> /// <param name="endPoint">IPEndPoint where we should be listening for IP Multicast packets.</param> /// <param name="TimeoutMilliseconds">Milliseconds before lack of a packet == a Network Timeout</param> /// <example> /// ... /// MulticastUdpListener mcListener = new MulticastUdpListener(endPoint1); /// mcListener.Receive(packetBuffer); /// mcListener.Displose(); /// /// MulticastUdpListener mcListener = new MulticastUdpListener(endPoint2); /// mcListener.Receive(packetBuffer); /// mcListener.Displose(); /// /// mcListener = null; /// ... /// </example> public UdpListener(System.Net.IPEndPoint endPoint, int timeoutMilliseconds) { LstSocks.Socket.SockInterfacePair sip = LstSocks.Socket.GetSharedSocket(endPoint); this.sock = sip.sock; this.externalInterface = sip.extInterface; this.ep = endPoint; lock(sip) { if(!sip.Initialized) { try { // Set the timeout on the socket if( timeoutMilliseconds > 0 ) sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, timeoutMilliseconds); // Set the socket to send & receive from this endpoint sock.Bind(new IPEndPoint(externalInterface,endPoint.Port)); // Make room for 80 packets plus some overhead sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, 1500 * 80); if(Utility.IsMulticast(endPoint.Address)) { if(endPoint.AddressFamily == AddressFamily.InterNetworkV6) { // Join the IPv6 Multicast group sock.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption(endPoint.Address)); } else { // Join the IPv4 Multicast group sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(endPoint.Address)); } } sip.Initialized = true; } catch { this.Dispose(); throw; } } } }
/// <summary> /// Constructor that binds this object instance to an IPEndPoint. If you need to change settings dynamically, Dispose and recreate a new object. /// </summary> /// <param name="endPoint">IPEndPoint where to send the multicast packets -- should be in range 224.0.0.0 to 239.255.255.255</param> /// <param name="timeToLive">ushort Time To Live of the packets -- how many routers will we cross -- set to 2 for local or testing</param> public UdpSender(System.Net.IPEndPoint destEndPoint, ushort timeToLive) { this.endPoint = destEndPoint; LstSocks.Socket.SockInterfacePair sip = LstSocks.Socket.GetSharedSocket(destEndPoint); this.sock = sip.sock; this.localRoutingInterface = sip.extInterface; if ( Utility.IsMulticast( destEndPoint.Address ) ) { SocketOptionLevel sOL = SocketOptionLevel.IP; if (destEndPoint.AddressFamily == AddressFamily.InterNetworkV6) { sOL = SocketOptionLevel.IPv6; } // Set the TTL sock.SetSocketOption(sOL, SocketOptionName.MulticastTimeToLive, timeToLive); // Enable Multicast Loopback sock.SetSocketOption(sOL, SocketOptionName.MulticastLoopback, 1); } else { // Enable Unicast Loopback /// Note: If we didn't also instantiate a UdpListener, the socket won't have been bound /// to a local interface. Specifically this comes up when we use the UdpSender to transmit /// reports to a diagnostic server. In this case the loopback is not needed anyway. IPEndPoint localEndpoint = (IPEndPoint)sock.LocalEndPoint; if (localEndpoint != null) { echoEndPoint = new IPEndPoint(localRoutingInterface, localEndpoint.Port); } } }