#!/usr/bin/env python
import socket
import threading
from sys import exit, argv, stderr, stdout, stdin
from signal import alarm, signal, SIGALRM
argv0 = 'nanobnc.py'
sok = None
def usage():
print(f'usage: {argv0} passphrase [timeout]')
exit(1)
def handle_args():
global argv0, argv
if len(argv) > 0:
argv0 = argv[0]
argv = argv[1:]
if len(argv) not in (1, 2):
usage()
passphrase = argv[0]
if len(argv) == 1:
timeout = 1800
else:
timeout = int(argv[1])
return passphrase, timeout
def handle_req(passphrase):
req = input().split(maxsplit=2)
if len(req) != 3:
print('bad # of connection args')
exit(3)
host, port, pw = req
if pw != passphrase:
print('bad passphrase')
print(f'bad passphrase trying to connect to {host}:{port}', file=stderr)
exit(4)
try:
port = int(port)
except:
print('bad port')
exit(3)
return host, port
def shutdown():
if sok is not None:
try:
sok.sendall(b'QUIT\n')
sok.shutdown(socket.SHUT_RDWR)
except:
pass
def onalarm(sig, stk):
try:
print('timeout!')
stdout.flush()
except:
pass
try:
print('timeout!', file=stderr)
stderr.flush()
except:
pass
shutdown()
exit(2)
signal(SIGALRM, onalarm)
passphrase, timeout = handle_args()
alarm(timeout)
host, port = handle_req(passphrase)
try:
sok = socket.create_connection((host, port))
except Exception as e:
print(f'connection failed: {e}')
exit(5)
def toserver():
while (s := stdin.readline()) != '':
if s == 'QUIT\n':
break
sok.sendall(s.encode())
shutdown()
exit(0)
def toclient():
fp = sok.makefile('r', encoding='ascii', errors='ignore')
while (s := fp.readline()) != '':
alarm(timeout)
stdout.write(s)
stdout.flush()
shutdown()
exit(0)
t = threading.Thread(target=toserver)
t.start()
toclient()