def close_multicast_socket(sock, address): """ Cleans up the given multicast socket. Unregisters it of the multicast group. Parameters should be the result of create_multicast_socket :param sock: A multicast socket :param address: The multicast address used by the socket """ if sock is None: return if address: # Prepare the mreq structure to join the group mreq = make_mreq(sock.family, address) # Quit group if sock.family == socket.AF_INET: # IPv4 sock.setsockopt(socket.IPPROTO_IP, socket.IP_DROP_MEMBERSHIP, mreq) elif sock.family == socket.AF_INET6: # IPv6 sock.setsockopt(ipproto_ipv6(), socket.IPV6_LEAVE_GROUP, mreq) # Close the socket sock.close()
def create_multicast_socket(address, port): """ Creates a multicast socket according to the given address and port. Handles both IPv4 and IPv6 addresses. :param address: Multicast address/group :param port: Socket port :return: A tuple (socket, listening address) :raise ValueError: Invalid address or port """ # Get the information about a datagram (UDP) socket, of any family try: addrs_info = socket.getaddrinfo( address, port, socket.AF_UNSPEC, socket.SOCK_DGRAM ) except socket.gaierror: raise ValueError( "Error retrieving address informations ({0}, {1})".format( address, port ) ) if len(addrs_info) > 1: _logger.debug( "More than one address information found. Using the first one." ) # Get the first entry : (family, socktype, proto, canonname, sockaddr) addr_info = addrs_info[0] # Only accept IPv4/v6 addresses if addr_info[0] not in (socket.AF_INET, socket.AF_INET6): # Unhandled address family raise ValueError("Unhandled socket family : %d" % (addr_info[0])) # Prepare the socket sock = socket.socket(addr_info[0], socket.SOCK_DGRAM, socket.IPPROTO_UDP) # Reuse address sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if hasattr(socket, "SO_REUSEPORT"): # Special for MacOS # pylint: disable=E1101 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) # Bind the socket if sock.family == socket.AF_INET: # IPv4 binding sock.bind(("0.0.0.0", port)) else: # IPv6 Binding sock.bind(("::", port)) # Prepare the mreq structure to join the group # addrinfo[4] = (addr,port) mreq = make_mreq(sock.family, addr_info[4][0]) # Join the group if sock.family == socket.AF_INET: # IPv4 sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) # Allow multicast packets to get back on this host sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1) elif sock.family == socket.AF_INET6: # IPv6 sock.setsockopt(ipproto_ipv6(), socket.IPV6_JOIN_GROUP, mreq) # Allow multicast packets to get back on this host sock.setsockopt(ipproto_ipv6(), socket.IPV6_MULTICAST_LOOP, 1) return sock, addr_info[4][0]
def create_multicast_socket(address, port): """ Creates a multicast socket according to the given address and port. Handles both IPv4 and IPv6 addresses. :param address: Multicast address/group :param port: Socket port :return: A tuple (socket, listening address) :raise ValueError: Invalid address or port """ # Get the information about a datagram (UDP) socket, of any family try: addrs_info = socket.getaddrinfo(address, port, socket.AF_UNSPEC, socket.SOCK_DGRAM) except socket.gaierror: raise ValueError( "Error retrieving address informations ({0}, {1})".format( address, port)) if len(addrs_info) > 1: _logger.debug("More than one address information found. " "Using the first one.") # Get the first entry : (family, socktype, proto, canonname, sockaddr) addr_info = addrs_info[0] # Only accept IPv4/v6 addresses if addr_info[0] not in (socket.AF_INET, socket.AF_INET6): # Unhandled address family raise ValueError("Unhandled socket family : %d" % (addr_info[0])) # Prepare the socket sock = socket.socket(addr_info[0], socket.SOCK_DGRAM, socket.IPPROTO_UDP) # Reuse address sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if hasattr(socket, 'SO_REUSEPORT'): # Special for MacOS # pylint: disable=E1101 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) # Bind the socket if sock.family == socket.AF_INET: # IPv4 binding sock.bind(('0.0.0.0', port)) else: # IPv6 Binding sock.bind(('::', port)) # Prepare the mreq structure to join the group # addrinfo[4] = (addr,port) mreq = make_mreq(sock.family, addr_info[4][0]) # Join the group if sock.family == socket.AF_INET: # IPv4 sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) # Allow multicast packets to get back on this host sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1) elif sock.family == socket.AF_INET6: # IPv6 sock.setsockopt(ipproto_ipv6(), socket.IPV6_JOIN_GROUP, mreq) # Allow multicast packets to get back on this host sock.setsockopt(ipproto_ipv6(), socket.IPV6_MULTICAST_LOOP, 1) return sock, addr_info[4][0]