def getOutgoingInterface(self):
i = self.socket.getsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF)
return socket.inet_ntoa(struct.pack("@i", i))
python类IP_MULTICAST_IF的实例源码
def _setInterface(self, addr):
i = socket.inet_aton(addr)
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, i)
return 1
def create_multicast_sock(own_ip, remote_addr, bind_to_multicast_addr):
"""Create UDP multicast socket."""
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setblocking(False)
sock.setsockopt(
socket.SOL_IP,
socket.IP_MULTICAST_IF,
socket.inet_aton(own_ip))
sock.setsockopt(
socket.SOL_IP,
socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(remote_addr[0]) +
socket.inet_aton(own_ip))
sock.setsockopt(
socket.IPPROTO_IP,
socket.IP_MULTICAST_TTL, 2)
sock.setsockopt(
socket.IPPROTO_IP,
socket.IP_MULTICAST_IF,
socket.inet_aton(own_ip))
# I have no idea why we have to use different bind calls here
# - bind() with multicast addr does not work with gateway search requests
# on some machines. It only works if called with own ip.
# - bind() with own_ip does not work with ROUTING_INDICATIONS on Gira
# knx router - for an unknown reason.
if bind_to_multicast_addr:
sock.bind((remote_addr[0], remote_addr[1]))
else:
sock.bind((own_ip, 0))
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 0)
return sock
def subscribe_multicast(interface):
"""subscribe to the mcast addr"""
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(interface.ipv4_address))
mreq = socket.inet_aton(interface.mcastaddr) + socket.inet_aton(interface.ipv4_address)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
sock.bind(('', 52122))
return sock
def getOutgoingInterface(self):
i = self.socket.getsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF)
return socket.inet_ntoa(struct.pack("@i", i))
def _setInterface(self, addr):
i = socket.inet_aton(addr)
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, i)
return 1
def getOutgoingInterface(self):
i = self.socket.getsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF)
return socket.inet_ntoa(struct.pack("@i", i))
def _setInterface(self, addr):
i = socket.inet_aton(addr)
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, i)
return 1
def getOutgoingInterface(self):
i = self.socket.getsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF)
return socket.inet_ntoa(struct.pack("@i", i))
def _setInterface(self, addr):
i = socket.inet_aton(addr)
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, i)
return 1
def set_ipv4_multicast_source_address(sock, source_address):
"""Sets the given socket up to send multicast from the specified source.
Ensures the multicast TTL is set to 1, so that packets are not forwarded
beyond the local link.
:param sock: An opened IP socket.
:param source_address: A string representing an IPv4 source address.
"""
sock.setsockopt(
socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 1)
sock.setsockopt(
socket.IPPROTO_IP, socket.IP_MULTICAST_IF,
socket.inet_aton(source_address))
def get_multicast_socket(sock=None):
if not sock:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(0.001)
# set multicast interface to any local interface
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton('0.0.0.0'))
# Enable multicast, TTL should be <32 (local network)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 5)
# Allow reuse of addresses
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Allow receiving multicast broadcasts (subscribe to multicast group)
try:
mreq = struct.pack('4sL', socket.inet_aton(multicast_ip), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
# Do not loop back own messages
sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 0)
except OSError as e:
logger.error('Unable to obtain socket with multicast enabled.')
raise e
port = None
for i in range(30100, 30105):
try:
# Binding to 0.0.0.0 results in multiple messages if there is multiple interfaces available
# Kept as-is to avoid losing messages
sock.bind(('0.0.0.0', i))
port = i
break
except OSError as e:
# Socket already in use without SO_REUSEADDR enabled
continue
if not port:
raise RuntimeError('No IMC multicast ports free on local interface.')
return sock
def __init__(self, bindaddress=None):
"""Creates an instance of the Zeroconf class, establishing
multicast communications, listening and reaping threads."""
globals()['_GLOBAL_DONE'] = 0
self.intf = bindaddress
self.group = ('', _MDNS_PORT)
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
except Exception:
# SO_REUSEADDR should be equivalent to SO_REUSEPORT for
# multicast UDP sockets (p 731, "TCP/IP Illustrated,
# Volume 2"), but some BSD-derived systems require
# SO_REUSEPORT to be specified explicity. Also, not all
# versions of Python have SO_REUSEPORT available. So
# if you're on a BSD-based system, and haven't upgraded
# to Python 2.3 yet, you may find this library doesn't
# work as expected.
#
pass
self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 255)
self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
try:
self.socket.bind(self.group)
except Exception:
# Some versions of linux raise an exception even though
# the SO_REUSE* options have been set, so ignore it
#
pass
if self.intf is not None:
self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(self.intf) + socket.inet_aton('0.0.0.0'))
self.socket.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0'))
self.listeners = []
self.browsers = []
self.services = {}
self.cache = DNSCache()
self.condition = threading.Condition()
self.engine = Engine(self)
self.listener = Listener(self)
self.reaper = Reaper(self)
def __init__(self, port, callback_obj, ttl=1, enable_loopback=False, bind_addr=''):
asyncore.dispatcher.__init__(self)
# self.lock = threading.RLock()
self.MAX_MTU = 1500
self.callback_obj = None
self.port = port
self.multicastSet = Set([])
self.lock = threading.RLock()
self.ttl = ttl
self.enable_loopback = enable_loopback
if callback_obj is not None and isinstance(callback_obj, IUdpCallback):
self.callback_obj = callback_obj
else:
raise Exception('callback_obj is None or not an instance of IUdpCallback class')
try:
self.create_socket(socket.AF_INET, socket.SOCK_DGRAM)
self.set_reuse_addr()
try:
socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
except AttributeError:
pass # Some systems don't support SO_REUSEPORT
# for both SENDER and RECEIVER to restrict the region
self.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, self.ttl)
# for SENDER to choose whether to use loop back
if self.enable_loopback:
self.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
else:
self.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 0)
self.bind_addr = bind_addr
if self.bind_addr is None or self.bind_addr == '':
self.bind_addr = socket.gethostbyname(socket.gethostname())
# for both SENDER and RECEIVER to bind to specific network adapter
self.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(self.bind_addr))
# for RECEIVE to receive from multiple multicast groups
self.bind(('', port))
except Exception as e:
print e
traceback.print_exc()
self.sendQueue = Queue.Queue() # thread-safe queue
AsyncController.instance().add(self)
if self.callback_obj is not None:
self.callback_obj.on_started(self)
# Even though UDP is connectionless this is called when it binds to a port
def __init__(
self,
interfaces=InterfaceChoice.All,
):
"""Creates an instance of the Zeroconf class, establishing
multicast communications, listening and reaping threads.
:type interfaces: :class:`InterfaceChoice` or sequence of ip addresses
"""
# hook for threads
self._GLOBAL_DONE = False
self._listen_socket = new_socket()
interfaces = normalize_interface_choice(interfaces, socket.AF_INET)
self._respond_sockets = []
for i in interfaces:
log.debug('Adding %r to multicast group', i)
try:
self._listen_socket.setsockopt(
socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(_MDNS_ADDR) + socket.inet_aton(i))
except socket.error as e:
if get_errno(e) == errno.EADDRINUSE:
log.info(
'Address in use when adding %s to multicast group, '
'it is expected to happen on some systems', i,
)
elif get_errno(e) == errno.EADDRNOTAVAIL:
log.info(
'Address not available when adding %s to multicast '
'group, it is expected to happen on some systems', i,
)
continue
else:
raise
respond_socket = new_socket()
respond_socket.setsockopt(
socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(i))
self._respond_sockets.append(respond_socket)
self.listeners = []
self.browsers = {}
self.services = {}
self.servicetypes = {}
self.cache = DNSCache()
self.condition = threading.Condition()
self.engine = Engine(self)
self.listener = Listener(self)
self.engine.add_reader(self.listener, self._listen_socket)
self.reaper = Reaper(self)
self.debug = None
def run(self):
"""Run the server."""
# Listen for UDP port 1900 packets sent to SSDP multicast address
ssdp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ssdp_socket.setblocking(False)
# Required for receiving multicast
ssdp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
ssdp_socket.setsockopt(
socket.SOL_IP,
socket.IP_MULTICAST_IF,
socket.inet_aton(self.host_ip_addr))
ssdp_socket.setsockopt(
socket.SOL_IP,
socket.IP_ADD_MEMBERSHIP,
socket.inet_aton("239.255.255.250") +
socket.inet_aton(self.host_ip_addr))
ssdp_socket.bind(("239.255.255.250", 1900))
while True:
if self._interrupted:
clean_socket_close(ssdp_socket)
return
try:
read, _, _ = select.select(
[self._interrupted_read_pipe, ssdp_socket], [],
[ssdp_socket])
if self._interrupted_read_pipe in read:
# Implies self._interrupted is True
clean_socket_close(ssdp_socket)
return
elif ssdp_socket in read:
data, addr = ssdp_socket.recvfrom(1024)
else:
continue
except socket.error as ex:
if self._interrupted:
clean_socket_close(ssdp_socket)
return
_LOGGER.error("UPNP Responder socket exception occured: %s",
ex.__str__)
if "M-SEARCH" in data.decode('utf-8'):
# SSDP M-SEARCH method received, respond to it with our info
resp_socket = socket.socket(
socket.AF_INET, socket.SOCK_DGRAM)
resp_socket.sendto(self.upnp_response, addr)
resp_socket.close()