#!/usr/bin/python from __future__ import print_function import datetime import socket import random, string import daemon, getopt, sys import daemon.pidlockfile import traceback import os BUFFER_SIZE = 4096 def myrandom(length): return ''.join(random.choice(string.lowercase) for i in range(length)) def serve(port, bindTo, path_report_store=None): assert path_report_store != None s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) s.bind((bindTo, port)) s.listen(1) print('DebugReport server listening on [{0}]:{1}'.format(bindTo, port)) try: from cStringIO import StringIO # Python 2 except ImportError: from io import StringIO # Python 3 report_buffer = StringIO() while 1: conn, addr = s.accept() conn.settimeout(30.0) report_id = None try: while 1: data = conn.recv(BUFFER_SIZE) if not data: break report_buffer.write(data) # python will convert \n to os.linesep report_id = myrandom(10) except: # try to send a zero-length response back to the peer to indicate a problem try: conn.sendall("\r\n") finally: report_buffer.truncate(0) conn.close() continue # don't want to receive any more data from the client conn.shutdown(socket.SHUT_RD) filename = os.path.join( path_report_store, "%s_%s.log" % (datetime.date.today().strftime('%Y-%m-%d_'), report_id) ) with open(filename, 'w') as f: try: f.write(report_buffer.getvalue()) f.flush() except: try: conn.sendall("\r\n") finally: report_buffer.truncate(0) conn.close() continue # f will be closed automatically by leaving the 'with'-scope report_buffer.truncate(0) # send reply to reportee response = "%s\r\n" % report_id try: conn.sendall(response) finally: conn.close() command = 'echo "'+'new report \\\"{0}\\\" from [{2}]:{3} stored as \\\"{1}\\\""'.format(report_id, filename, addr[0], addr[1]) command = command + ' | /usr/local/bin/ff_log_to_bot' os.system(command) print('new report "{0}" from [{2}]:{3} stored as "{1}"'.format(report_id, filename, addr[0], addr[1])) pass if __name__ == '__main__': try: opts, args = getopt.getopt(sys.argv[1:], "dp:b:s:", ["daemonize", "port=", "bind-to=", "report-store="]) except: print ('Unrecognized option') sys.exit(2) daemonize = False port = 1337 bindTo = None path_report_store = os.path.join(os.path.dirname(sys.argv[0]), "reports") for opt, arg in opts: if opt in ("-d", "--daemonize"): daemonize = True elif opt in ("-p", "--port"): port = int(arg) elif opt in ("-b", "--bind-to"): try: socket.inet_pton(socket.AF_INET6, arg) bindTo = str(arg) except: traceback.print_exc() sys.exit(1) elif opt in ("-s", "--report-store"): path_report_store = arg else: assert False if bindTo == None: print("Listening IP address is unset. Using default ::") bindTo = "::" if not os.path.exists(path_report_store): os.makedirs(path_report_store) if daemonize == True: daemonContext = daemon.DaemonContext(pidfile = daemon.pidlockfile.PIDLockFile("/var/run/ffpb-debugserver.pid")) with daemonContext: serve(port, bindTo, path_report_store=path_report_store) else: serve(port, bindTo, path_report_store=path_report_store)