aboutsummaryrefslogtreecommitdiffstats
path: root/tools/gbhub
diff options
context:
space:
mode:
authoruser <user@clank>2026-07-17 19:47:12 +0200
committeruser <user@clank>2026-07-17 19:47:12 +0200
commit6f8243ef094241d3a4175fd2deed23fe5ee946ce (patch)
treee4d71c21979664e185a56284dde9da6de1e1286b /tools/gbhub
parentnet: unbreak ping against hosts that intermittently drop ICMP (diff)
downloadgbos-6f8243ef094241d3a4175fd2deed23fe5ee946ce.tar.gz
gbos-6f8243ef094241d3a4175fd2deed23fe5ee946ce.tar.xz
gbos-6f8243ef094241d3a4175fd2deed23fe5ee946ce.zip
gbhub: make GB drops attributable, not spooky
Link-drop investigation fallout - every drop looked identical because the hub discarded all the evidence: - gb_reader logs *how* a GB left (clean eof vs the exception) with timestamps on join/leave, for correlating against SSH/terminal events. - Spawn mode keeps each emulator's stderr in /tmp/gbhub_<n>.err instead of devnull - postmortems get the emulator's side of the story. - A second gbhub exits with a clear 'already running?' message instead of an ioctl traceback (and can't damage the live hub's NAT/socket).
Diffstat (limited to '')
-rwxr-xr-xtools/gbhub20
1 files changed, 15 insertions, 5 deletions
diff --git a/tools/gbhub b/tools/gbhub
index 3823463..85a4843 100755
--- a/tools/gbhub
+++ b/tools/gbhub
@@ -93,13 +93,16 @@ def route(gb, fr):
def gb_reader(gb):
buf, inf, esc = bytearray(), False, False
while True:
+ why = "eof"
try: chunk = gb.conn.recv(2048)
- except Exception: chunk = None
+ except Exception as e:
+ chunk = None; why = "%s: %s" % (type(e).__name__, e)
if not chunk:
with lock: # GB left: free its address
conns.pop(gb.ip, None)
if gb.octet not in pool: pool.append(gb.octet); pool.sort()
- sys.stderr.write("[gbhub] GB%d (10.0.0.%d) left\n" % (gb.idx, gb.octet))
+ sys.stderr.write("[gbhub] %s GB%d (10.0.0.%d) left (%s)\n"
+ % (time.strftime("%H:%M:%S"), gb.idx, gb.octet, why))
return
for c in chunk:
if c == END:
@@ -125,7 +128,11 @@ def tun_reader():
def net_setup():
global tun
tun = os.open("/dev/net/tun", os.O_RDWR)
- fcntl.ioctl(tun, 0x400454ca, struct.pack("16sH", IFACE.encode(), 0x0001|0x1000))
+ try:
+ fcntl.ioctl(tun, 0x400454ca, struct.pack("16sH", IFACE.encode(), 0x0001|0x1000))
+ except OSError as e:
+ sys.exit("gbhub: cannot claim %s (%s) - another gbhub is already running?\n"
+ " (sudo pkill -f tools/gbhub to stop it)" % (IFACE, e.strerror))
wan = subprocess.check_output("ip route show default|awk '{print $5;exit}'", shell=True).decode().strip() or "eth0"
sh("ip addr add 10.0.0.1/24 dev %s" % IFACE); sh("ip link set %s mtu %d up" % (IFACE, MTU))
sh("sysctl -w net.ipv4.ip_forward=1")
@@ -146,7 +153,8 @@ def register(conn):
octet = pool.pop(0)
gb = GB(octet, conn); conns[gb.ip] = gb
threading.Thread(target=gb_reader, args=(gb,), daemon=True).start()
- sys.stderr.write("[gbhub] GB%d joined -> 10.0.0.%d\n" % (gb.idx, octet))
+ sys.stderr.write("[gbhub] %s GB%d joined -> 10.0.0.%d\n"
+ % (time.strftime("%H:%M:%S"), gb.idx, octet))
return gb
def main():
@@ -176,9 +184,11 @@ def main():
for i in range(n):
rom = "/tmp/gbhub_%d.gb" % i # per-GB ROM so saves don't clash
shutil.copyfile(ROM, rom)
+ err = open("/tmp/gbhub_%d.err" % i, "ab", buffering=0) # keep emulator stderr for postmortems
emus.append(subprocess.Popen([EMU, "--headless", "--uncapped", "--serial-sock", SOCK, rom],
- stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
+ stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=err,
start_new_session=True))
+ err.close()
sys.stderr.write("[gbhub] %d Game Boys on 10.0.0.0/24 (10.0.0.2..%d), NAT via %s\n" % (n, 1+n, wan))
srv.settimeout(12)
for i in range(n):