diff --git a/ethermess-backend.c b/ethermess-backend.c index a37825d..708a103 100644 --- a/ethermess-backend.c +++ b/ethermess-backend.c @@ -1049,7 +1049,8 @@ void eventloop(void) { // Read a command read_command(); } else if (pollfds[0].revents & POLLHUP) { - // Quit + // Quit on frontend exiting + warnx("Frontend exited unexpectedly"); running = false; } else { errx(1, "Got poll event %hd on stdin\n", pollfds[0].revents); @@ -1063,6 +1064,9 @@ void eventloop(void) { if (pollfds[1].revents & POLLIN) { // Process a frame process_frame(); + } else if (pollfds[1].revents & POLLERR) { + // Lost connection + errx(1, "Network went down"); } else { errx(1, "Got poll event %hd on packet socket\n", pollfds[1].revents); } @@ -1121,13 +1125,8 @@ int main(int argc, char **argv) { memcpy(own_mac, ifr.ifr_hwaddr.sa_data, sizeof(own_mac)); // Print it out - char own_mac_str[18]; - format_mac(own_mac, own_mac_str); - if (printf("%s\n", own_mac_str) == -1) { - err(1, "printf"); - } - if (fflush(stdout) == EOF) { - err(1, "fflush"); + if (write(1, own_mac, 6) != 6) { + err(1, "write"); } // Initialize the message id cache diff --git a/ethermess.py b/ethermess.py index bde32e6..98ebe05 100644 --- a/ethermess.py +++ b/ethermess.py @@ -73,6 +73,15 @@ def writeall(f, b): while written < len(b): written += f.write(b[written:]) +def readall(f, length): + read = bytearray() + while len(read) < length: + data = f.read(length - len(read)) + if data is None: + raise ConnectionError('Could not satisfy read of %i bytes' % length) + read.extend(data) + return bytes(read) + def parse_mac(text): parts = text.split(':') if len(parts) != 6: @@ -85,19 +94,34 @@ def parse_mac(text): return parsed +def format_mac(mac): + return ':'.join(mac[i:i+1].hex() for i in range(len(mac))) + class PollBasedThread(threading.Thread): def run(self): - poll = select.poll() - for f in self.pollin: - poll.register(f, select.POLLIN) + while True: + restart = False + self.initialize() - self.initialize() + poll = select.poll() + for f in self.pollin: + poll.register(f, select.POLLIN) - running = True - while running: - for fd, event in poll.poll(): - if self.poll_loop(fd, event) != None: - running = False + running = True + while running and not restart: + for fd, event in poll.poll(): + command = self.poll_loop(fd, event) + if command == None: + pass + elif command == 'quit': + running = False + elif command == 'restart': + restart = True + else: + raise ValueError("poll_loop() needs to return either None, 'quit', or 'restart'") + + if not restart: + break self.finalize() @@ -111,15 +135,26 @@ class PollBasedThread(threading.Thread): ... class Backend(PollBasedThread): - def __init__(self, interface, writes_channel, control_channel): + def __init__(self, interface, nick, writes_channel, control_channel): self.interface = interface + self.nick = nick self.writes_channel = writes_channel self.control_channel = control_channel - self.pollin = [self.writes_channel, self.control_channel] super().__init__() def initialize(self): - self.proc = subprocess.Popen(['sudo', libexec_dir + '/ethermess-backend', self.interface], stdin = subprocess.PIPE, stdout = sys.stdout, stderr = sys.stderr, bufsize = 0) + self.proc = subprocess.Popen(['sudo', libexec_dir + '/ethermess-backend', self.interface], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = sys.stderr, bufsize = 0) + self.pollin = [self.writes_channel, self.control_channel, self.proc.stdout] + + # Tell the backend the status and nick + status = 0 + nick = self.nick.encode('utf-8') + writeall(self.proc.stdin, bytes([status, len(nick)]) + nick) + + # Read our MAC + self.mac = readall(self.proc.stdout, 6) + + print('Own mac: %s' % format_mac(self.mac)) def poll_loop(self, fd, event): if fd == self.writes_channel.fileno() and event & select.POLLIN: @@ -134,6 +169,15 @@ class Backend(PollBasedThread): else: raise Exception('Unreachable') + elif fd == self.proc.stdout.fileno() and event & select.POLLIN: + data = self.proc.stdout.read(1024) + sys.stdout.buffer.write(data) + sys.stdout.flush() + + elif fd == self.proc.stdout.fileno() and event & select.POLLHUP: + print('Backend exited') + return 'quit' + else: raise Exception('Unreachable') @@ -183,8 +227,5 @@ control_channel = Channel() _, interface, nick = sys.argv -nick = nick.encode('utf-8') -writes_channel.send((bytes([0, len(nick)]) + nick)) - -Backend(interface, writes_channel, control_channel).start() +Backend(interface, nick, writes_channel, control_channel).start() Input(writes_channel, control_channel).start()