Skip to content

Commit

Permalink
Resetup hostapd control interface watcher if directory is recreated
Browse files Browse the repository at this point in the history
A network restart on OpenWRT seems to recreate the directory, so this is
needed to handle network restarts gracefully.
  • Loading branch information
oxan committed May 13, 2020
1 parent bd28eea commit d5fbafc
Showing 1 changed file with 32 additions and 30 deletions.
62 changes: 32 additions & 30 deletions hapt/files/hapt.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class FFI:

inotify_init = libc.func("i", "inotify_init", "")
inotify_add_watch = libc.func("i", "inotify_add_watch", "isI")
inotify_rm_watch = libc.func("i", "inotify_rm_watch", "ii")

def subprocess(command):
with os.popen(command, 'r') as stream:
Expand Down Expand Up @@ -80,15 +81,10 @@ def disconnect_hostapd_socket(socket):
raise ValueError('Received invalid response on DETACH from hostapd: %s' % response)
socket.close()

def create_directory_watch(directory):
fd = FFI.inotify_init()
wd = FFI.inotify_add_watch(fd, directory, FFI.IN_CREATE | FFI.IN_DELETE)
return fd

def decode_inotify_event(event):
wd, mask, cookie, length = ustruct.unpack("iIII", event)
name = event[ustruct.calcsize("iIII"):].split(b'\0', 1)[0].decode('utf-8')
return mask, name
return wd, mask, name

def get_lease_details(leasefile, mac):
try:
Expand All @@ -109,11 +105,12 @@ def listdir(path):

class InterfaceWatcher:
def __init__(self, handler, include_interfaces=None):
self.fds = {}
self.poll = uselect.poll()
self.handler = handler
self.include_interfaces = include_interfaces

self.fds = {}
self.poll = uselect.poll()

def add_interface(self, interface):
if self.include_interfaces and interface not in self.include_interfaces:
return
Expand All @@ -137,23 +134,35 @@ def remove_interface_fd(self, fd):
self.poll.unregister(fd)
del self.fds[fd]


def handle_inotify(self, msg):
wd, mask, name = decode_inotify_event(msg)
if wd == self.inotify_wd_parent and name == 'hostapd':
if mask & FFI.IN_CREATE:
self.inotify_wd_control = FFI.inotify_add_watch(self.inotify_fd, '/var/run/hostapd', FFI.IN_CREATE | FFI.IN_DELETE)
if mask & FFI.IN_DELETE:
FFI.inotify_rm_watch(self.inotify_fd, self.inotify_wd_control)
elif wd == self.inotify_wd_control:
if mask & FFI.IN_CREATE:
self.add_interface(name)
if mask & FFI.IN_DELETE:
self.remove_interface(name)

def setup(self):
try:
uos.stat('/var/run/hostapd')
except OSError as e:
uos.mkdir('/var/run/hostapd')
self.inotify_fd = FFI.inotify_init()
self.inotify_wd_parent = FFI.inotify_add_watch(self.inotify_fd, '/var/run', FFI.IN_CREATE | FFI.IN_DELETE)
self.inotify_wd_control = FFI.inotify_add_watch(self.inotify_fd, '/var/run/hostapd', FFI.IN_CREATE | FFI.IN_DELETE)

inotify_fd = create_directory_watch('/var/run/hostapd')
self.fds[inotify_fd] = ('inotify', None, None)
self.poll.register(inotify_fd, uselect.POLLIN)
self.fds[self.inotify_fd] = ('inotify', None, None)
self.poll.register(self.inotify_fd, uselect.POLLIN)

for interface in listdir('/var/run/hostapd'):
self.add_interface(interface)

def run(self):
print("Monitoring for hostapd events...")
while True:
try:
print("Monitoring for events...")
try:
while True:
for fd, event in self.poll.poll():
if fd not in self.fds:
continue
Expand All @@ -164,19 +173,12 @@ def run(self):
self.remove_interface_fd(fd)

if fd_type == 'hostapd':
msg = fd_obj.recv(1024)
self.handler(fd_name, msg.decode('utf-8'))
self.handler(fd_name, fd_obj.recv(1024).decode('utf-8'))
elif fd_type == 'inotify':
msg = os.read(fd, 256)
event, interface = decode_inotify_event(msg)
if event == FFI.IN_CREATE:
self.add_interface(interface)
elif event == FFI.IN_DELETE:
self.remove_interface(interface)
except Exception as e:
print("Poll event loop encountered following exception, quitting")
sys.print_exception(e)
break
self.handle_inotify(os.read(fd, 256))
except Exception as e:
print("Poll event loop encountered following exception, quitting")
sys.print_exception(e)

def teardown(self):
for fd, desc in self.fds.items():
Expand Down

0 comments on commit d5fbafc

Please sign in to comment.