|
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