2828class DiscoveryClient (MessageReceiver ):
2929 MSG_DISCOVERY_PORT = 5466
3030
31- def __init__ (self , address_list , on_device_discovered ):
31+ def __init__ (self , address_list , ip6 , on_device_discovered ):
3232 super ().__init__ ()
3333
34+ self .ip6 = ip6
3435 self .address_list = address_list
3536 self .on_device_discovered = on_device_discovered
3637
3738 @staticmethod
38- async def create (addr , callback ):
39+ async def create (addr , ip6 , callback ):
3940 loop = asyncio .get_running_loop ()
4041
4142 _ , protocol = await loop .create_datagram_endpoint (
42- lambda : DiscoveryClient (addr , callback ),
43+ lambda : DiscoveryClient (addr , ip6 , callback ),
4344 remote_addr = None ,
44- family = socket .AF_INET ,
45+ family = socket .AF_INET6 if ip6 else socket . AF_INET ,
4546 allow_broadcast = True
4647 )
4748
@@ -58,7 +59,10 @@ def connection_made(self, transport):
5859 message += encode_u64 (self .validator )
5960
6061 for address in self .address_list :
61- self .transport .sendto (message , (address , DiscoveryClient .MSG_DISCOVERY_PORT ))
62+ if not self .ip6 :
63+ self .transport .sendto (message , (address , DiscoveryClient .MSG_DISCOVERY_PORT ))
64+ else :
65+ self .transport .sendto (message , address )
6266
6367 def datagram_received (self , data , addr ):
6468 self .remote_addr = addr
@@ -74,7 +78,7 @@ def connection_lost(self, exc):
7478 pass
7579
7680 def message_received (self , msg_id , msg_payload ):
77- if msg_id != Messages .MSG_ID_DISCOVERY or len (msg_payload ) <= 67 :
81+ if msg_id != Messages .MSG_ID_DISCOVERY or len (msg_payload ) <= 47 :
7882 return
7983
8084 validator = decode_u64 (msg_payload [0 :8 ])
@@ -106,45 +110,50 @@ def message_received(self, msg_id, msg_payload):
106110 elif len (device ["version" ][5 ]) != 0 :
107111 device ["versionstr" ] += "+d"
108112
109- msg_ip , _ = self .remote_addr
110- ip4 = str ( ipaddress . IPv4Address ( msg_payload [ 48 : 44 : - 1 ]))
111- ip6 = str ( ipaddress . IPv6Address ( msg_payload [ 49 : 65 ]))
112- address_list = []
113+ if not self .ip6 :
114+ ip , _ = self . remote_addr
115+ else :
116+ ip , _ = socket . getnameinfo ( self . remote_addr , 0 )
113117
114- if ip4 != msg_ip :
115- return
116-
117- if ip4 != "0.0.0.0" :
118- address_list .append (ip4 )
119-
120- if ip6 != "::" :
121- address_list .append (ip6 )
122-
123- if len (address_list ) == 0 :
124- return
125-
126- device ["address" ] = address_list
127- device ["port" ] = decode_u16 (msg_payload [65 :67 ])
128- device ["name" ] = msg_payload [67 :].decode ("UTF-8" )
118+ device ["address" ] = ip
119+ device ["port" ] = decode_u16 (msg_payload [45 :47 ])
120+ device ["name" ] = msg_payload [47 :].decode ("UTF-8" )
129121
130122 self .on_device_discovered (device )
131123
132124async def discover_devices (timeout ):
133- address_list = []
134125 device_list = []
126+ address4_set = set ()
127+ address6_list = []
135128
136129 # Get broadcast address of every available interface
130+
137131 for iface in netifaces .interfaces ():
138132 for addr_family , addr_list in netifaces .ifaddresses (iface ).items ():
139133 if netifaces .address_families [addr_family ] == "AF_INET" :
140134 for addr in addr_list :
141135 if "broadcast" in addr :
142- address_list .append (addr ["broadcast" ])
136+ address4_set .add (addr ["broadcast" ])
137+ elif addr ["addr" ][:8 ] == "169.254." :
138+ address4_set .add ("169.254.255.255" )
139+
140+ address6_list .append (
141+ socket .getaddrinfo (
142+ "ff12::{0}%{1}" .format (DiscoveryClient .MSG_DISCOVERY_PORT , iface ),
143+ 5466 , socket .AF_INET6 , socket .SOCK_DGRAM
144+ )[0 ][- 1 ]
145+ )
143146
144147 # Broadcast DISCOVERY message on every interface
148+
149+ await DiscoveryClient .create (
150+ address4_set , False ,
151+ lambda dev : device_list .append (dev )
152+ )
153+
145154 await DiscoveryClient .create (
146- address_list ,
147- lambda dev : device_list .append (dev )
155+ address6_list , True ,
156+ lambda dev : device_list .append (dev )
148157 )
149158
150159 await asyncio .sleep (timeout )
0 commit comments