diff --git a/src/twisted/plugins/magic_wormhole_transit_relay.py b/src/twisted/plugins/magic_wormhole_transit_relay.py new file mode 100644 index 0000000..96c1993 --- /dev/null +++ b/src/twisted/plugins/magic_wormhole_transit_relay.py @@ -0,0 +1,8 @@ +from twisted.application.service import ServiceMaker + +TransitRelay = ServiceMaker( + "Magic-Wormhole Transit Relay", # name + "wormhole_transit_relay.server_tap", # module + "Provide the Transit Relay server for Magic-Wormhole clients.", # desc + "transitrelay", # tapname + ) diff --git a/src/wormhole_transit_relay/server_tap.py b/src/wormhole_transit_relay/server_tap.py new file mode 100644 index 0000000..b0a8b27 --- /dev/null +++ b/src/wormhole_transit_relay/server_tap.py @@ -0,0 +1,68 @@ +from . import transit_server +from twisted.internet import reactor +from twisted.python import usage +from twisted.application.internet import StreamServerEndpointService +from twisted.application.service import MultiService +from twisted.internet import endpoints + +LONGDESC = """\ +This plugin sets up a 'Transit Relay' server for magic-wormhole. This service +listens for TCP connections, finds pairs which present the same handshake, and +glues the two TCP sockets together. + +If --usage-logfile= is provided, a line will be written to the given file after +each connection is done. This line will be a complete JSON object (starting +with "{" and ending with "}\n"). The keys will be: + +* 'started': number, seconds since epoch +* 'total_time': number, seconds from open to last close +* 'waiting_time': number, seconds from start to 2nd side appearing, or null +* 'total_bytes': number, total bytes relayed (sum of both directions) +* 'mood': string, one of: happy, lonely, errory + +A mood of "happy" means both sides gave a correct handshake. "lonely" means a +second matching side never appeared (and thus 'waiting_time' will be null). +"errory" means the first side gave an invalid handshake. + +If --blur-usage= is provided, then 'started' will be rounded to the given time +interval, and 'total_bytes' will be rounded as well. + +If --stats-json is provided, the server will periodically write a simple JSON +dictionary to that file (atomically), with usage since last reboot. This +information is *not* blurred (the assumption is that it will be overwritten on +a regular basis, and is aggregated anyways). The keys are: + +* active.connected: number of paired connections +* active.waiting: number of not-yet-paired connections +* since_reboot.bytes: sum of 'total_bytes' +* since_reboot.total: number of completed connections +* since_reboot.moods: dict mapping mood string to number of connections + +The server will write twistd.pid and twistd.log files as usual, if daemonized +by twistd. +""" + +class Options(usage.Options): + #synopsis = "[--port=] [--usage-logfile=] [--blur-usage=] [--stats-json=]" + longdesc = LONGDESC + + optParameters = [ + ("port", "p", "tcp:4001", "endpoint to listen on"), + ("usage-logfile", None, None, "record usage data (JSON lines)"), + ("blur-usage", None, None, "blur logged timestamps and data sizes"), + ("stats-json", None, None, "record usage since-reboot"), + ] + + def opt_blur_usage(self, arg): + self["blur_usage"] = int(arg) + + +def makeService(config, reactor=reactor): + s = MultiService() + t = transit_server.Transit(blur_usage=config["blur-usage"], + usage_logfile=config["usage-logfile"], + stats_json_path=config["stats-json"]) + s.setServiceParent(t) # for the timer + ep = endpoints.serverFromString(reactor, config["port"]) # to listen + s.setServiceParent(StreamServerEndpointService(ep, t)) + return s