diff --git a/copyparty/__main__.py b/copyparty/__main__.py index b7431139..3b4d6fbc 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -132,8 +132,8 @@ def main(): ) # fmt: off ap.add_argument("-c", metavar="PATH", type=str, action="append", help="add config file") - ap.add_argument("-i", metavar="IP", type=str, default="0.0.0.0", help="ip to bind") - ap.add_argument("-p", metavar="PORT", type=int, default=3923, help="port to bind") + ap.add_argument("-i", metavar="IP", type=str, default="0.0.0.0", help="ip to bind (comma-sep.)") + ap.add_argument("-p", metavar="PORT", type=str, default="3923", help="ports to bind (comma/range)") ap.add_argument("-nc", metavar="NUM", type=int, default=64, help="max num clients") ap.add_argument("-j", metavar="CORES", type=int, default=1, help="max num cpu cores") ap.add_argument("-a", metavar="ACCT", type=str, action="append", help="add account") @@ -151,6 +151,16 @@ def main(): al = ap.parse_args() # fmt: on + al.i = al.i.split(",") + try: + if "-" in al.p: + lo, hi = [int(x) for x in al.p.split("-")] + al.p = list(range(lo, hi + 1)) + else: + al.p = [int(x) for x in al.p.split(",")] + except: + raise Exception("invalid value for -p") + SvcHub(al).run() diff --git a/copyparty/tcpsrv.py b/copyparty/tcpsrv.py index a31cd07c..c207dbfa 100644 --- a/copyparty/tcpsrv.py +++ b/copyparty/tcpsrv.py @@ -4,6 +4,7 @@ from __future__ import print_function, unicode_literals import re import time import socket +import select from .util import chkcmd, Counter @@ -23,39 +24,50 @@ class TcpSrv(object): ip = "127.0.0.1" eps = {ip: "local only"} - if self.args.i != ip: - eps = self.detect_interfaces(self.args.i) or {self.args.i: "external"} + nonlocals = [x for x in self.args.i if x != ip] + if nonlocals: + eps = self.detect_interfaces(self.args.i) + if not eps: + for x in nonlocals: + eps[x] = "external" for ip, desc in sorted(eps.items(), key=lambda x: x[1]): - self.log( - "tcpsrv", - "available @ http://{}:{}/ (\033[33m{}\033[0m)".format( - ip, self.args.p, desc - ), - ) + for port in sorted(self.args.p): + self.log( + "tcpsrv", + "available @ http://{}:{}/ (\033[33m{}\033[0m)".format( + ip, port, desc + ), + ) - self.srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.srv.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + self.srv = [] + for ip in self.args.i: + for port in self.args.p: + self.srv.append(self._listen(ip, port)) + + def _listen(self, ip, port): + srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + srv.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) try: - self.srv.bind((self.args.i, self.args.p)) + srv.bind((ip, port)) + return srv except (OSError, socket.error) as ex: if ex.errno == 98: raise Exception( - "\033[1;31mport {} is busy on interface {}\033[0m".format( - self.args.p, self.args.i - ) + "\033[1;31mport {} is busy on interface {}\033[0m".format(port, ip) ) if ex.errno == 99: raise Exception( - "\033[1;31minterface {} does not exist\033[0m".format(self.args.i) + "\033[1;31minterface {} does not exist\033[0m".format(ip) ) def run(self): - self.srv.listen(self.args.nc) - - self.log("tcpsrv", "listening @ {0}:{1}".format(self.args.i, self.args.p)) + for srv in self.srv: + srv.listen(self.args.nc) + ip, port = srv.getsockname() + self.log("tcpsrv", "listening @ {0}:{1}".format(ip, port)) while True: self.log("tcpsrv", "\033[1;30m|%sC-ncli\033[0m" % ("-" * 1,)) @@ -64,15 +76,23 @@ class TcpSrv(object): continue self.log("tcpsrv", "\033[1;30m|%sC-acc1\033[0m" % ("-" * 2,)) - sck, addr = self.srv.accept() - self.log("%s %s" % addr, "\033[1;30m|%sC-acc2\033[0m" % ("-" * 3,)) - self.num_clients.add() - self.hub.broker.put(False, "httpconn", sck, addr) + ready, _, _ = select.select(self.srv, [], []) + for srv in ready: + sck, addr = srv.accept() + sip, sport = srv.getsockname() + self.log( + "%s %s" % addr, + "\033[1;30m|{}C-acc2 \033[0;36m{} \033[3{}m{}".format( + "-" * 3, sip, sport % 8, sport + ), + ) + self.num_clients.add() + self.hub.broker.put(False, "httpconn", sck, addr) def shutdown(self): self.log("tcpsrv", "ok bye") - def detect_interfaces(self, listen_ip): + def detect_interfaces(self, listen_ips): eps = {} # get all ips and their interfaces @@ -86,8 +106,9 @@ class TcpSrv(object): for ln in ip_addr.split("\n"): try: ip, dev = r.match(ln.rstrip()).groups() - if listen_ip in ["0.0.0.0", ip]: - eps[ip] = dev + for lip in listen_ips: + if lip in ["0.0.0.0", ip]: + eps[ip] = dev except: pass @@ -114,11 +135,12 @@ class TcpSrv(object): s.close() - if default_route and listen_ip in ["0.0.0.0", default_route]: - desc = "\033[32mexternal" - try: - eps[default_route] += ", " + desc - except: - eps[default_route] = desc + for lip in listen_ips: + if default_route and lip in ["0.0.0.0", default_route]: + desc = "\033[32mexternal" + try: + eps[default_route] += ", " + desc + except: + eps[default_route] = desc return eps