|
1 | | - |
2 | 1 | # ====================================================================== |
3 | 2 | # zbeacon - LAN discovery and presence |
4 | 3 | # |
@@ -137,57 +136,85 @@ def prepare_udp(self): |
137 | 136 | except socket.error: |
138 | 137 | logger.exception("Initializing of {0} raised an exception".format(self.__class__.__name__)) |
139 | 138 |
|
140 | | - def _prepare_socket(self): |
141 | | - netinf = zhelper.get_ifaddrs() |
142 | | - |
143 | | - logger.debug("Available interfaces: {0}".format(netinf)) |
| 139 | + def _try_interface(self, iface): |
144 | 140 |
|
145 | | - for iface in netinf: |
146 | | - # Loop over the interfaces and their settings to try to find the broadcast address. |
147 | | - # ipv4 only currently and needs a valid broadcast address |
148 | | - for name, data in iface.items(): |
149 | | - logger.debug("Checking out interface {0}.".format(name)) |
150 | | - # For some reason the data we need lives in the "2" section of the interface. |
151 | | - data_2 = data.get(2) |
| 141 | + for name, data in iface.items(): |
| 142 | + logger.debug("Checking out interface {0}.".format(name)) |
| 143 | + # For some reason the data we need lives in the "2" section of the interface. |
| 144 | + data_2 = data.get(2) |
152 | 145 |
|
153 | | - if not data_2: |
154 | | - logger.debug("No data_2 found for interface {0}.".format(name)) |
155 | | - continue |
| 146 | + if not data_2: |
| 147 | + logger.debug("No data_2 found for interface {0}.".format(name)) |
| 148 | + return |
156 | 149 |
|
157 | | - address_str = data_2.get("addr") |
158 | | - netmask_str = data_2.get("netmask") |
| 150 | + address_str = data_2.get("addr") |
| 151 | + netmask_str = data_2.get("netmask") |
159 | 152 |
|
160 | | - if not address_str or not netmask_str: |
161 | | - logger.debug("Address or netmask not found for interface {0}.".format(name)) |
162 | | - continue |
| 153 | + if not address_str or not netmask_str: |
| 154 | + logger.debug("Address or netmask not found for interface {0}.".format(name)) |
| 155 | + return |
163 | 156 |
|
164 | | - if isinstance(address_str, bytes): |
165 | | - address_str = address_str.decode("utf8") |
| 157 | + if isinstance(address_str, bytes): |
| 158 | + address_str = address_str.decode("utf8") |
166 | 159 |
|
167 | | - if isinstance(netmask_str, bytes): |
168 | | - netmask_str = netmask_str.decode("utf8") |
| 160 | + if isinstance(netmask_str, bytes): |
| 161 | + netmask_str = netmask_str.decode("utf8") |
169 | 162 |
|
170 | | - interface_string = "{0}/{1}".format(address_str, netmask_str) |
| 163 | + interface_string = "{0}/{1}".format(address_str, netmask_str) |
171 | 164 |
|
172 | | - interface = ipaddress.ip_interface(u(interface_string)) |
| 165 | + interface = ipaddress.ip_interface(u(interface_string)) |
173 | 166 |
|
174 | | - if interface.is_loopback: |
175 | | - logger.debug("Interface {0} is a loopback device.".format(name)) |
176 | | - continue |
| 167 | + if interface.is_loopback: |
| 168 | + logger.debug("Interface {0} is a loopback device.".format(name)) |
| 169 | + return |
177 | 170 |
|
178 | | - if interface.is_link_local: |
179 | | - logger.debug("Interface {0} is a link-local device.".format(name)) |
180 | | - continue |
| 171 | + if interface.is_link_local: |
| 172 | + logger.debug("Interface {0} is a link-local device.".format(name)) |
| 173 | + return |
181 | 174 |
|
182 | | - self.address = interface.ip |
183 | | - self.network_address = interface.network.network_address |
184 | | - self.broadcast_address = interface.network.broadcast_address |
185 | | - self.interface_name = name |
| 175 | + self.address = interface.ip |
| 176 | + self.network_address = interface.network.network_address |
| 177 | + self.broadcast_address = interface.network.broadcast_address |
| 178 | + self.interface_name = name |
186 | 179 |
|
187 | 180 | if self.address: |
188 | | - break |
| 181 | + return |
| 182 | + |
| 183 | + def _find_selected_interface(self, netinf): |
| 184 | + for iface in netinf: |
| 185 | + for name, data in iface.items(): |
| 186 | + if name == self.interface_name: |
| 187 | + return iface |
| 188 | + return None |
189 | 189 |
|
190 | | - logger.debug("Finished scanning interfaces.") |
| 190 | + def _prepare_socket(self): |
| 191 | + |
| 192 | + netinf = zhelper.get_ifaddrs() |
| 193 | + |
| 194 | + logger.debug("Available interfaces: {0}".format(netinf)) |
| 195 | + |
| 196 | + if self.interface_name: |
| 197 | + logger.debug("Trying the selected interface: {0}".format(self.interface_name)) |
| 198 | + |
| 199 | + if len(self.interface_name) == 1 and self.interface_name.isdigit(): |
| 200 | + logger.debug("Selected interface is a single digit, using as array index".format(self.interface_name)) |
| 201 | + array_index = int(self.interface_name) |
| 202 | + self._try_interface(netinf[array_index]) |
| 203 | + else: |
| 204 | + selected_interface = self._find_selected_interface(netinf) |
| 205 | + if selected_interface is not None: |
| 206 | + logger.debug("Found selected interface.") |
| 207 | + self._try_interface(selected_interface) |
| 208 | + |
| 209 | + if not self.address: |
| 210 | + logger.debug("Looping over interfaces.") |
| 211 | + # Loop over the interfaces and their settings to try to find the broadcast address. |
| 212 | + # ipv4 only currently and needs a valid broadcast address |
| 213 | + for iface in netinf: |
| 214 | + self._try_interface(iface) |
| 215 | + if self.address: |
| 216 | + break |
| 217 | + logger.debug("Finished scanning interfaces.") |
191 | 218 |
|
192 | 219 | if not self.address: |
193 | 220 | self.network_address = ipaddress.IPv4Address(u('127.0.0.1')) |
@@ -217,6 +244,8 @@ def handle_pipe(self): |
217 | 244 |
|
218 | 245 | if command == "VERBOSE": |
219 | 246 | self.verbose = True |
| 247 | + elif command == "SET INTERFACE": |
| 248 | + self.interface_name = request.pop(0).decode() |
220 | 249 | elif command == "CONFIGURE": |
221 | 250 | port = struct.unpack('I', request.pop(0))[0] |
222 | 251 | self.configure(port) |
@@ -269,20 +298,21 @@ def send_beacon(self): |
269 | 298 | try: |
270 | 299 | self.udpsock.sendto(self.transmit, (str(self.broadcast_address), |
271 | 300 | self.port_nbr)) |
272 | | - |
| 301 | + |
273 | 302 | except OSError as e: |
274 | | - |
| 303 | + |
275 | 304 | # network down, just wait, it could come back up again. |
276 | 305 | # socket call errors 50 and 51 relate to the network being |
277 | | - # down or unreachable, the recommended action to take is to |
| 306 | + # down or unreachable, the recommended action to take is to |
278 | 307 | # try again so we don't terminate in these cases. |
279 | | - if e.errno in [ENETDOWN, ENETUNREACH]: pass |
280 | | - |
| 308 | + if e.errno in [ENETDOWN, ENETUNREACH]: |
| 309 | + pass |
| 310 | + |
281 | 311 | # all other cases, we'll terminate |
282 | 312 | else: |
283 | 313 | logger.debug("Network seems gone, exiting zbeacon") |
284 | 314 | self.terminated = True |
285 | | - |
| 315 | + |
286 | 316 | except socket.error: |
287 | 317 | logger.debug("Network seems gone, exiting zbeacon") |
288 | 318 | self.terminated = True |
@@ -317,12 +347,14 @@ def run(self): |
317 | 347 | import zmq |
318 | 348 | import struct |
319 | 349 | import time |
| 350 | + |
320 | 351 | speaker = ZActor(zmq.Context(), ZBeacon) |
321 | 352 | speaker.send_unicode("VERBOSE") |
322 | 353 | speaker.send_unicode("CONFIGURE", zmq.SNDMORE) |
323 | 354 | speaker.send(struct.pack("I", 9999)) |
324 | 355 | speaker.send_unicode("PUBLISH", zmq.SNDMORE) |
325 | 356 | import uuid |
| 357 | + |
326 | 358 | transmit = struct.pack('cccb16sH', b'Z', b'R', b'E', |
327 | 359 | 1, uuid.uuid4().bytes, |
328 | 360 | socket.htons(1300)) |
|
0 commit comments