Skip to content

Commit d88864c

Browse files
authored
Merge pull request #169 from philrhc/set-interface
implements set_interface
2 parents a9ed346 + e782257 commit d88864c

File tree

4 files changed

+84
-46
lines changed

4 files changed

+84
-46
lines changed

pyre/pyre.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ def set_interface(self, value):
117117
"""Set network interface for UDP beacons. If you do not set this, CZMQ will
118118
choose an interface for you. On boxes with several interfaces you should
119119
specify which one you want to use, or strange things can happen."""
120-
logging.debug("set_interface not implemented") #TODO
120+
self.actor.send_unicode("SET INTERFACE", zmq.SNDMORE)
121+
self.actor.send_unicode(value)
121122

122123
# TODO: check args from zyre
123124
def set_endpoint(self, format, *args):

pyre/pyre_node.py

+6
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def __init__(self, ctx, pipe, outbox, *args, **kwargs):
2727
self.outbox = outbox # Outbox back to application
2828
self._terminated = False # API shut us down
2929
self._verbose = False # Log all traffic (logging module?)
30+
self.interface_name = None # Network interface
3031
self.beacon_port = ZRE_DISCOVERY_PORT # Beacon port number
3132
self.interval = 0 # Beacon interval 0=default
3233
self.beacon = None # Beacon actor
@@ -67,6 +68,9 @@ def start(self):
6768
if self._verbose:
6869
self.beacon.send_unicode("VERBOSE")
6970

71+
if self.interface_name:
72+
self.beacon.send_unicode("SET INTERFACE", zmq.SNDMORE)
73+
self.beacon.send_unicode(self.interface_name)
7074

7175
# Our hostname is provided by zbeacon
7276
self.beacon.send_unicode("CONFIGURE", zmq.SNDMORE)
@@ -160,6 +164,8 @@ def recv_api(self):
160164
self.beacon_port = int(request.pop(0))
161165
elif command == "SET INTERVAL":
162166
self.interval = int(request.pop(0))
167+
elif command == "SET INTERFACE":
168+
self.interface_name = request.pop(0).decode()
163169
#elif command == "SET ENDPOINT":
164170
# TODO: gossip start and endpoint setting
165171
# TODO: GOSSIP BIND, GOSSIP CONNECT

pyre/zbeacon.py

+76-44
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# ======================================================================
32
# zbeacon - LAN discovery and presence
43
#
@@ -137,57 +136,85 @@ def prepare_udp(self):
137136
except socket.error:
138137
logger.exception("Initializing of {0} raised an exception".format(self.__class__.__name__))
139138

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):
144140

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)
152145

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
156149

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")
159152

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
163156

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")
166159

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")
169162

170-
interface_string = "{0}/{1}".format(address_str, netmask_str)
163+
interface_string = "{0}/{1}".format(address_str, netmask_str)
171164

172-
interface = ipaddress.ip_interface(u(interface_string))
165+
interface = ipaddress.ip_interface(u(interface_string))
173166

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
177170

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
181174

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
186179

187180
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
189189

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.")
191218

192219
if not self.address:
193220
self.network_address = ipaddress.IPv4Address(u('127.0.0.1'))
@@ -217,6 +244,8 @@ def handle_pipe(self):
217244

218245
if command == "VERBOSE":
219246
self.verbose = True
247+
elif command == "SET INTERFACE":
248+
self.interface_name = request.pop(0).decode()
220249
elif command == "CONFIGURE":
221250
port = struct.unpack('I', request.pop(0))[0]
222251
self.configure(port)
@@ -269,20 +298,21 @@ def send_beacon(self):
269298
try:
270299
self.udpsock.sendto(self.transmit, (str(self.broadcast_address),
271300
self.port_nbr))
272-
301+
273302
except OSError as e:
274-
303+
275304
# network down, just wait, it could come back up again.
276305
# 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
278307
# 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+
281311
# all other cases, we'll terminate
282312
else:
283313
logger.debug("Network seems gone, exiting zbeacon")
284314
self.terminated = True
285-
315+
286316
except socket.error:
287317
logger.debug("Network seems gone, exiting zbeacon")
288318
self.terminated = True
@@ -317,12 +347,14 @@ def run(self):
317347
import zmq
318348
import struct
319349
import time
350+
320351
speaker = ZActor(zmq.Context(), ZBeacon)
321352
speaker.send_unicode("VERBOSE")
322353
speaker.send_unicode("CONFIGURE", zmq.SNDMORE)
323354
speaker.send(struct.pack("I", 9999))
324355
speaker.send_unicode("PUBLISH", zmq.SNDMORE)
325356
import uuid
357+
326358
transmit = struct.pack('cccb16sH', b'Z', b'R', b'E',
327359
1, uuid.uuid4().bytes,
328360
socket.htons(1300))

tests/test_zbeacon.py

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
class ZBeaconTest(unittest.TestCase):
1111
def setUp(self, *args, **kwargs):
12-
ctx = zmq.Context()
1312
ctx = zmq.Context()
1413
# two beacon frames
1514
self.transmit1 = struct.pack('cccb16sH', b'Z', b'R', b'E',

0 commit comments

Comments
 (0)