Exemplo n.º 1
0
def new_runSS():
    """An effective way to start shadowsocks server with all the outputs of it redirected into a log file
    named `shadowsocks.log` under `~/.sspy-mgr/logs`.
    """
    import logging
    fileHandler = createLoggerFile('shadowsocks')
    logger = logging.getLogger()
    logger.addHandler(fileHandler)
    logger.setLevel(logging.INFO)

    from shadowsocks import shell, daemon, eventloop, manager
    logger.info('Start running shadowsock server')
    shell.check_python()
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s %(levelname)-8s %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S')

    config_path = ssConfigFile()
    logger.info(tr('Loading configuration from {}').format(config_path))
    with open(config_path, 'rb') as f:
        try:
            config = shell.parse_json_in_str(f.read().decode('utf8'))
        except ValueError as e:
            logger.error("found an error in config.json: {}".format(e.message))
            sys.exit(1)
    config['manager_address'] = ssAddr(True)
    config['port_password'] = {}
    config['server_port'] = 0
    config['verbose'] = 2
    config['method'] = 'aes-256-cfb'

    daemon.daemon_exec(config)

    config['port_password'] = {}
    # server_port = config['server_port']
    # if type(server_port) == list:
    #     for a_server_port in server_port:
    #         config['port_password'][a_server_port] = config['password']
    # else:
    #     config['port_password'][str(server_port)] = config['password']

    logger.info('entering manager mode')
    manager.run(config)
Exemplo n.º 2
0
def init_config():
    global tcp_servers, udp_servers, dns_resolver, workers, worker_id
    tcp_servers = []
    udp_servers = []
    dns_resolver = asyncdns.DNSResolver()
    workers = int(config['workers'])
    worker_id = 0

    if config['port_password']:
        if config['password']:
            logging.warn('warning: port_password should not be used with '
                         'server_port and password. server_port and password '
                         'will be ignored')
    else:
        config['port_password'] = {}
        server_port = config['server_port']
        if type(server_port) == list:
            for a_server_port in server_port:
                config['port_password'][a_server_port] = config['password']
        else:
            config['port_password'][str(server_port)] = config['password']

    if config.get('manager_address', 0):
        logging.info('entering manager mode')
        manager.run(config)
        return

    port_password = config['port_password']
    #del config['port_password']
    for port, password in port_password.items():
        a_config = config.copy()
        a_config['server_port'] = int(port)
        a_config['password'] = password
        tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False))
        udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False))

    #load servers config from mysql
    mysql_servers = agent_.load_servers()
    tcp_servers += mysql_servers[0]
    udp_servers += mysql_servers[1]
Exemplo n.º 3
0
def new_runSS():
    import logging
    fileHandler = createLoggerFile('shadowsocks')
    logger = logging.getLogger()
    logger.addHandler(fileHandler)
    logger.setLevel(logging.INFO)

    from shadowsocks import shell, daemon, eventloop, manager
    logger.info('Start running shadowsock server')
    shell.check_python()
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s %(levelname)-8s %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S')

    config_path = ssConfigFile()
    logger.info('loading config from %s' % config_path)
    with open(config_path, 'rb') as f:
        try:
            config = shell.parse_json_in_str(f.read().decode('utf8'))
        except ValueError as e:
            logger.error('found an error in config.json: %s', e.message)
            sys.exit(1)
    config['manager_address'] = ssAddr(True)
    config['port_password'] = {}
    config['server_port'] = 0
    config['verbose'] = 2
    config['method'] = 'aes-256-cfb'

    daemon.daemon_exec(config)

    config['port_password'] = {}
    # server_port = config['server_port']
    # if type(server_port) == list:
    #     for a_server_port in server_port:
    #         config['port_password'][a_server_port] = config['password']
    # else:
    #     config['port_password'][str(server_port)] = config['password']

    logger.info('entering manager mode')
    manager.run(config)
Exemplo n.º 4
0
def main():
    shell.check_python()

    # 读取
    config = shell.get_config(False)

    # TODO 临时打印配置信息
    print(config)

    # 根据配置对守护进程进行操作,不开启 daemon 时此处可忽略
    daemon.daemon_exec(config)

    """
    port_password 为一个字典,每个端口有不同的密码,用于多用户登录
    "port_password": {
        "8381": "foobar1",
        "8382": "foobar2",
        }
    """
    if config['port_password']:
        # 如果既配置了端口密码又配置了全局密码,则全局密码会被忽略
        if config['password']:
            logging.warn('warning: port_password should not be used with '
                         'server_port and password. server_port and password '
                         'will be ignored')
    else:
        config['port_password'] = {}
        server_port = config.get('server_port', None)
        if server_port:
            if type(server_port) == list:
                for a_server_port in server_port:
                    config['port_password'][a_server_port] = config['password']
            else:
                config['port_password'][str(server_port)] = config['password']

    # TODO 如果获取到 manager_address,则启动管理进程,先跳过不看
    if config.get('manager_address', 0):
        logging.info('entering manager mode')
        manager.run(config)
        return

    tcp_servers = []
    udp_servers = []

    # 如果设置了 dns 服务器
    if 'dns_server' in config:  # allow override settings in resolv.conf
        dns_resolver = asyncdns.DNSResolver(config['dns_server'])
    else:
        dns_resolver = asyncdns.DNSResolver()

    # 取出服务端口和其密码,当设置中不开启 port_password 时,也会退化到使用 port_password,此时 port_password 为单元素列表
    port_password = config['port_password']
    # TODO 为什么要删除
    del config['port_password']
    # 循环每一对端口和密码
    for port, password in port_password.items():
        # dict.copy() 创建了一个新的字典对象,内容一样
        a_config = config.copy()
        a_config['server_port'] = int(port)
        a_config['password'] = password
        logging.info("starting server at %s:%d" %
                     (a_config['server'], int(port)))
        tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False))
        udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False))

    def run_server():
        def child_handler(signum, _):
            logging.warn('received SIGQUIT, doing graceful shutting down..')
            list(map(lambda s: s.close(next_tick=True),
                     tcp_servers + udp_servers))
        signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM),
                      child_handler)

        def int_handler(signum, _):
            sys.exit(1)
        signal.signal(signal.SIGINT, int_handler)

        try:
            loop = eventloop.EventLoop()
            dns_resolver.add_to_loop(loop)
            list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers))

            daemon.set_user(config.get('user', None))
            loop.run()
        except Exception as e:
            shell.print_exception(e)
            sys.exit(1)

    # 如果 workers 为 1 则直接启动 server,否则进行 fork()
    if int(config['workers']) > 1:
        if os.name == 'posix':
            children = []
            is_child = False
            for i in range(0, int(config['workers'])):
                r = os.fork()
                if r == 0:
                    logging.info('worker started')
                    is_child = True
                    run_server()
                    break
                else:
                    children.append(r)
            if not is_child:
                def handler(signum, _):
                    for pid in children:
                        try:
                            os.kill(pid, signum)
                            os.waitpid(pid, 0)
                        except OSError:  # child may already exited
                            pass
                    sys.exit()
                signal.signal(signal.SIGTERM, handler)
                signal.signal(signal.SIGQUIT, handler)
                signal.signal(signal.SIGINT, handler)

                # master
                for a_tcp_server in tcp_servers:
                    a_tcp_server.close()
                for a_udp_server in udp_servers:
                    a_udp_server.close()
                dns_resolver.close()

                for child in children:
                    os.waitpid(child, 0)
        else:
            logging.warn('worker is only available on Unix/Linux')
            run_server()
    else:
        run_server()
Exemplo n.º 5
0
def main():
    shell.check_python()

    config = shell.get_config(False)

    shell.log_shadowsocks_version()

    daemon.daemon_exec(config)

    try:
        import resource
        logging.info('current process RLIMIT_NOFILE resource: soft %d hard %d'  % resource.getrlimit(resource.RLIMIT_NOFILE))
    except ImportError:
        pass

    if config['port_password']:
        pass
    else:
        config['port_password'] = {}
        server_port = config['server_port']
        if type(server_port) == list:
            for a_server_port in server_port:
                config['port_password'][a_server_port] = config['password']
        else:
            config['port_password'][str(server_port)] = config['password']

    if not config.get('dns_ipv6', False):
        asyncdns.IPV6_CONNECTION_SUPPORT = False

    if config.get('manager_address', 0):
        logging.info('entering manager mode')
        manager.run(config)
        return

    tcp_servers = []
    udp_servers = []
    dns_resolver = asyncdns.DNSResolver()
    if int(config['workers']) > 1:
        stat_counter_dict = None
    else:
        stat_counter_dict = {}
    port_password = config['port_password']
    config_password = config.get('password', 'm')
    del config['port_password']
    for port, password_obfs in port_password.items():
        method = config["method"]
        protocol = config.get("protocol", 'origin')
        protocol_param = config.get("protocol_param", '')
        obfs = config.get("obfs", 'plain')
        obfs_param = config.get("obfs_param", '')
        bind = config.get("out_bind", '')
        bindv6 = config.get("out_bindv6", '')
        if type(password_obfs) == list:
            password = password_obfs[0]
            obfs = password_obfs[1]
            if len(password_obfs) > 2:
                protocol = password_obfs[2]
        elif type(password_obfs) == dict:
            password = password_obfs.get('password', config_password)
            method = password_obfs.get('method', method)
            protocol = password_obfs.get('protocol', protocol)
            protocol_param = password_obfs.get('protocol_param', protocol_param)
            obfs = password_obfs.get('obfs', obfs)
            obfs_param = password_obfs.get('obfs_param', obfs_param)
            bind = password_obfs.get('bind', bind)
            bindv6 = password_obfs.get('bindv6', bindv6)
        else:
            password = password_obfs
        a_config = config.copy()
        ipv6_ok = False
        logging.info("server start with protocol[%s] password [%s] method [%s] obfs [%s] obfs_param [%s]" %
                (protocol, password, a_config['method'], obfs, obfs_param))
        if 'server_ipv6' in a_config:
            try:
                if len(a_config['server_ipv6']) > 2 and a_config['server_ipv6'][0] == "[" and a_config['server_ipv6'][-1] == "]":
                    a_config['server_ipv6'] = a_config['server_ipv6'][1:-1]
                a_config['server_port'] = int(port)
                a_config['password'] = password
                a_config['method'] = method
                a_config['protocol'] = protocol
                a_config['protocol_param'] = protocol_param
                a_config['obfs'] = obfs
                a_config['obfs_param'] = obfs_param
                a_config['out_bind'] = bind
                a_config['out_bindv6'] = bindv6
                a_config['server'] = a_config['server_ipv6']
                logging.info("starting server at [%s]:%d" %
                             (a_config['server'], int(port)))
                tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False, stat_counter=stat_counter_dict))
                udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False, stat_counter=stat_counter_dict))
                if a_config['server_ipv6'] == b"::":
                    ipv6_ok = True
            except Exception as e:
                shell.print_exception(e)

        try:
            a_config = config.copy()
            a_config['server_port'] = int(port)
            a_config['password'] = password
            a_config['method'] = method
            a_config['protocol'] = protocol
            a_config['protocol_param'] = protocol_param
            a_config['obfs'] = obfs
            a_config['obfs_param'] = obfs_param
            a_config['out_bind'] = bind
            a_config['out_bindv6'] = bindv6
            logging.info("starting server at %s:%d" %
                         (a_config['server'], int(port)))
            tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False, stat_counter=stat_counter_dict))
            udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False, stat_counter=stat_counter_dict))
        except Exception as e:
            if not ipv6_ok:
                shell.print_exception(e)

    def run_server():
        def child_handler(signum, _):
            logging.warn('received SIGQUIT, doing graceful shutting down..')
            list(map(lambda s: s.close(next_tick=True),
                     tcp_servers + udp_servers))
        signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM),
                      child_handler)

        def int_handler(signum, _):
            sys.exit(1)
        signal.signal(signal.SIGINT, int_handler)

        try:
            loop = eventloop.EventLoop()
            dns_resolver.add_to_loop(loop)
            list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers))

            daemon.set_user(config.get('user', None))
            loop.run()
        except Exception as e:
            shell.print_exception(e)
            sys.exit(1)

    if int(config['workers']) > 1:
        if os.name == 'posix':
            children = []
            is_child = False
            for i in range(0, int(config['workers'])):
                r = os.fork()
                if r == 0:
                    logging.info('worker started')
                    is_child = True
                    run_server()
                    break
                else:
                    children.append(r)
            if not is_child:
                def handler(signum, _):
                    for pid in children:
                        try:
                            os.kill(pid, signum)
                            os.waitpid(pid, 0)
                        except OSError:  # child may already exited
                            pass
                    sys.exit()
                signal.signal(signal.SIGTERM, handler)
                signal.signal(signal.SIGQUIT, handler)
                signal.signal(signal.SIGINT, handler)

                # master
                for a_tcp_server in tcp_servers:
                    a_tcp_server.close()
                for a_udp_server in udp_servers:
                    a_udp_server.close()
                dns_resolver.close()

                for child in children:
                    os.waitpid(child, 0)
        else:
            logging.warn('worker is only available on Unix/Linux')
            run_server()
    else:
        run_server()
Exemplo n.º 6
0
def main():
    shell.check_python()

    config = shell.get_config(False)

    daemon.daemon_exec(config)

    if config['port_password']:
        if config['password']:
            logging.warn('warning: port_password should not be used with '
                         'server_port and password. server_port and password '
                         'will be ignored')
    else:
        config['port_password'] = {}
        server_port = config.get('server_port', None)
        if server_port:
            if type(server_port) == list:
                for a_server_port in server_port:
                    config['port_password'][a_server_port] = config['password']
            else:
                config['port_password'][str(server_port)] = config['password']

    if config.get('manager_address', 0):
        logging.info('entering manager mode')
        manager.run(config)
        return

    tcp_servers = []
    udp_servers = []

    if 'dns_server' in config:  # allow override settings in resolv.conf
        dns_resolver = asyncdns.DNSResolver(config['dns_server'])
    else:
        dns_resolver = asyncdns.DNSResolver()

    port_password = config['port_password']
    del config['port_password']
    for port, password in port_password.items():
        a_config = config.copy()
        a_config['server_port'] = int(port)
        a_config['password'] = password
        logging.info("starting server at %s:%d" %
                     (a_config['server'], int(port)))
        tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False))
        udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False))

    def run_server():
        def child_handler(signum, _):
            logging.warn('received SIGQUIT, doing graceful shutting down..')
            list(map(lambda s: s.close(next_tick=True),
                     tcp_servers + udp_servers))
        signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM),
                      child_handler)

        def int_handler(signum, _):
            sys.exit(1)
        signal.signal(signal.SIGINT, int_handler)

        try:
            loop = eventloop.EventLoop()
            dns_resolver.add_to_loop(loop)
            list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers))

            daemon.set_user(config.get('user', None))
            loop.run()
        except Exception as e:
            shell.print_exception(e)
            sys.exit(1)

    if int(config['workers']) > 1:
        if os.name == 'posix':
            children = []
            is_child = False
            for i in range(0, int(config['workers'])):
                r = os.fork()
                if r == 0:
                    logging.info('worker started')
                    is_child = True
                    run_server()
                    break
                else:
                    children.append(r)
            if not is_child:
                def handler(signum, _):
                    for pid in children:
                        try:
                            os.kill(pid, signum)
                            os.waitpid(pid, 0)
                        except OSError:  # child may already exited
                            pass
                    sys.exit()
                signal.signal(signal.SIGTERM, handler)
                signal.signal(signal.SIGQUIT, handler)
                signal.signal(signal.SIGINT, handler)

                # master
                for a_tcp_server in tcp_servers:
                    a_tcp_server.close()
                for a_udp_server in udp_servers:
                    a_udp_server.close()
                dns_resolver.close()

                for child in children:
                    os.waitpid(child, 0)
        else:
            logging.warn('worker is only available on Unix/Linux')
            run_server()
    else:
        run_server()
Exemplo n.º 7
0
def main():
    shell.check_python3()

    config = shell.get_config(False)

    shell.log_shadowsocks_version()

    daemon.daemon_exec(config)

    try:
        import resource
        logging.info(
            'current process RLIMIT_NOFILE resource: soft %d hard %d' %
            resource.getrlimit(resource.RLIMIT_NOFILE))
    except ImportError:
        pass

    if config['port_password']:
        pass
    else:
        config['port_password'] = {}
        server_port = config['server_port']
        if type(server_port) == list:
            for a_server_port in server_port:
                config['port_password'][a_server_port] = config['password']
        else:
            config['port_password'][str(server_port)] = config['password']

    if not config.get('dns_ipv6', False):
        asyncdns.IPV6_CONNECTION_SUPPORT = False

    if config.get('manager_address', 0):
        logging.info('entering manager mode')
        manager.run(config)
        return

    tcp_servers = []
    udp_servers = []
    dns_resolver = asyncdns.DNSResolver()
    if int(config['workers']) > 1:
        stat_counter_dict = None
    else:
        stat_counter_dict = {}
    port_password = config['port_password']
    config_password = config.get('password', 'm')
    del config['port_password']
    for port, password_obfs in port_password.items():
        method = config["method"]
        protocol = config.get("protocol", 'origin')
        protocol_param = config.get("protocol_param", '')
        obfs = config.get("obfs", 'plain')
        obfs_param = config.get("obfs_param", '')
        bind = config.get("out_bind", '')
        bindv6 = config.get("out_bindv6", '')
        if type(password_obfs) == list:
            password = password_obfs[0]
            obfs = common.to_str(password_obfs[1])
            if len(password_obfs) > 2:
                protocol = common.to_str(password_obfs[2])
        elif type(password_obfs) == dict:
            password = password_obfs.get('password', config_password)
            method = common.to_str(password_obfs.get('method', method))
            protocol = common.to_str(password_obfs.get('protocol', protocol))
            protocol_param = common.to_str(
                password_obfs.get('protocol_param', protocol_param))
            obfs = common.to_str(password_obfs.get('obfs', obfs))
            obfs_param = common.to_str(
                password_obfs.get('obfs_param', obfs_param))
            bind = password_obfs.get('out_bind', bind)
            bindv6 = password_obfs.get('out_bindv6', bindv6)
        else:
            password = password_obfs
        a_config = config.copy()
        ipv6_ok = False
        logging.info(
            "server start with protocol[%s] password [%s] method [%s] obfs [%s] obfs_param [%s]"
            % (protocol, password, method, obfs, obfs_param))
        if 'server_ipv6' in a_config:
            try:
                if len(a_config['server_ipv6']
                       ) > 2 and a_config['server_ipv6'][
                           0] == "[" and a_config['server_ipv6'][-1] == "]":
                    a_config['server_ipv6'] = a_config['server_ipv6'][1:-1]
                a_config['server_port'] = int(port)
                a_config['password'] = password
                a_config['method'] = method
                a_config['protocol'] = protocol
                a_config['protocol_param'] = protocol_param
                a_config['obfs'] = obfs
                a_config['obfs_param'] = obfs_param
                a_config['out_bind'] = bind
                a_config['out_bindv6'] = bindv6
                a_config['server'] = a_config['server_ipv6']
                logging.info("starting server at [%s]:%d" %
                             (a_config['server'], int(port)))
                tcp_servers.append(
                    tcprelay.TCPRelay(a_config,
                                      dns_resolver,
                                      False,
                                      stat_counter=stat_counter_dict))
                udp_servers.append(
                    udprelay.UDPRelay(a_config,
                                      dns_resolver,
                                      False,
                                      stat_counter=stat_counter_dict))
                if a_config['server_ipv6'] == b"::":
                    ipv6_ok = True
            except Exception as e:
                shell.print_exception(e)

        try:
            a_config = config.copy()
            a_config['server_port'] = int(port)
            a_config['password'] = password
            a_config['method'] = method
            a_config['protocol'] = protocol
            a_config['protocol_param'] = protocol_param
            a_config['obfs'] = obfs
            a_config['obfs_param'] = obfs_param
            a_config['out_bind'] = bind
            a_config['out_bindv6'] = bindv6
            logging.info("starting server at %s:%d" %
                         (a_config['server'], int(port)))
            tcp_servers.append(
                tcprelay.TCPRelay(a_config,
                                  dns_resolver,
                                  False,
                                  stat_counter=stat_counter_dict))
            udp_servers.append(
                udprelay.UDPRelay(a_config,
                                  dns_resolver,
                                  False,
                                  stat_counter=stat_counter_dict))
        except Exception as e:
            if not ipv6_ok:
                shell.print_exception(e)

    def run_server():
        def child_handler(signum, _):
            logging.warn('received SIGQUIT, doing graceful shutting down..')
            list(
                map(lambda s: s.close(next_tick=True),
                    tcp_servers + udp_servers))

        signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM),
                      child_handler)

        def int_handler(signum, _):
            sys.exit(1)

        signal.signal(signal.SIGINT, int_handler)

        try:
            loop = eventloop.EventLoop()
            dns_resolver.add_to_loop(loop)
            list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers))

            daemon.set_user(config.get('user', None))
            loop.run()
        except Exception as e:
            shell.print_exception(e)
            sys.exit(1)

    if int(config['workers']) > 1:
        if os.name == 'posix':
            children = []
            is_child = False
            for i in range(0, int(config['workers'])):
                r = os.fork()
                if r == 0:
                    logging.info('worker started')
                    is_child = True
                    run_server()
                    break
                else:
                    children.append(r)
            if not is_child:

                def handler(signum, _):
                    for pid in children:
                        try:
                            os.kill(pid, signum)
                            os.waitpid(pid, 0)
                        except OSError:  # child may already exited
                            pass
                    sys.exit()

                signal.signal(signal.SIGTERM, handler)
                signal.signal(signal.SIGQUIT, handler)
                signal.signal(signal.SIGINT, handler)

                # master
                for a_tcp_server in tcp_servers:
                    a_tcp_server.close()
                for a_udp_server in udp_servers:
                    a_udp_server.close()
                dns_resolver.close()

                for child in children:
                    os.waitpid(child, 0)
        else:
            logging.warn('worker is only available on Unix/Linux')
            run_server()
    else:
        run_server()
Exemplo n.º 8
0
def main():
    shell.check_python()  #检查python版本

    config = shell.get_config(False)  #从配置文件,命令行等获取参数

    daemon.daemon_exec(config)  #根据'daemon'参数来start,stop或restart ssserver

    if config['port_password']:
        if config['password']:
            logging.warn('warning: port_password should not be used with '
                         'server_port and password. server_port and password '
                         'will be ignored')
    else:
        config['port_password'] = {}
        server_port = config['server_port']
        if type(server_port) == list:
            for a_server_port in server_port:
                config['port_password'][a_server_port] = config['password']
        else:
            config['port_password'][str(server_port)] = config['password']

    if config.get('manager_address', 0):
        logging.info('entering manager mode')
        manager.run(config)
        return

    tcp_servers = []
    udp_servers = []
    # 类DNSResolver初始化时会从/etc/hosts和/etc/resolv.conf中获取hostname和dns
    dns_resolver = asyncdns.DNSResolver()
    port_password = config['port_password']
    del config['port_password']
    for port, password in port_password.items():
        a_config = config.copy()
        a_config['server_port'] = int(port)
        a_config['password'] = password
        logging.info("starting server at %s:%d" %
                     (a_config['server'], int(port)))
        tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False))
        udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False))

    def run_server():
        def child_handler(signum, _):
            logging.warn('received SIGQUIT, doing graceful shutting down..')
            # map(function, sequence[, sequence, ...]) -> list 将function函数作用到
            # sequence中的每一个元素,也就是关掉上面打开的所有的socket
            list(
                map(lambda s: s.close(next_tick=True),
                    tcp_servers + udp_servers))

        # 注册SIGQUIT或SIGTERM的信号处理函数,Windows不支持SIGQUIT而Linux支持,所以为了
        # 跨平台兼容,此处使用了getattr函数
        # 在调用exec前,子进程会继承父进程注册的信号处理action,这里在子进程中重新注册
        # 了SIGTERM信号的处理action,不出意外,signal函数会返回上一次注册的action
        signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM),
                      child_handler)

        # 为SIGINT注册信号处理函数
        def int_handler(signum, _):
            sys.exit(1)

        signal.signal(signal.SIGINT, int_handler)

        try:
            loop = eventloop.EventLoop()
            # 将dns以及之前tcp, udp的socket都注册到epoll事件表中
            dns_resolver.add_to_loop(loop)
            list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers))

            daemon.set_user(config.get('user', None))
            loop.run()
        except Exception as e:
            shell.print_exception(e)
            sys.exit(1)

    if int(config['workers']) > 1:
        if os.name == 'posix':
            children = []
            is_child = False
            for i in range(0, int(config['workers'])):
                r = os.fork()
                if r == 0:
                    logging.info('worker started')
                    is_child = True
                    run_server()
                    break
                else:
                    children.append(r)
            if not is_child:

                def handler(signum, _):
                    for pid in children:
                        try:
                            os.kill(pid, signum)
                            os.waitpid(pid, 0)
                        except OSError:  # child may already exited
                            pass
                    sys.exit()

                signal.signal(signal.SIGTERM, handler)
                signal.signal(signal.SIGQUIT, handler)
                signal.signal(signal.SIGINT, handler)

                # master
                for a_tcp_server in tcp_servers:
                    a_tcp_server.close()
                for a_udp_server in udp_servers:
                    a_udp_server.close()
                dns_resolver.close()

                for child in children:
                    os.waitpid(child, 0)
        else:
            logging.warn('worker is only available on Unix/Linux')
            run_server()
    else:
        run_server()
Exemplo n.º 9
0
def main():
    # 检查python版本
    shell.check_python()
   
    config = shell.get_config(False)    # 获取配置文件,其中参数False 是标识符is_local的假值,表示要获取非local配置

    daemon.daemon_exec(config)          # 检查配置是否要开启进程守护,仅在UNIX, Linux 上有效
    # 多用户分配设置处理
    if config['port_password']:
        if config['password']:
            logging.warning('warning: port_password should not be used with '
                         'server_port and password. server_port and password '
                         'will be ignored')
    else:
        config['port_password'] = {}
        server_port = config['server_port']
        if type(server_port) == list:
            for a_server_port in server_port:
                config['port_password'][a_server_port] = config['password']
        else:
            config['port_password'][str(server_port)] = config['password']

    if config.get('manager_address', 0):
        logging.info('entering manager mode')
        manager.run(config)
        return

    tcp_servers = []
    udp_servers = []
    dns_resolver = asyncdns.DNSResolver()   # 创建DNS查询对象
    port_password = config['port_password'] # 获取
    del config['port_password']             # 删除config 字典中的"port_password"键
    # 将多用户配置转换为单用户配置
    for port, password in port_password.items():
        a_config = config.copy()
        a_config['server_port'] = int(port) # 创建"server_port"键
        a_config['password'] = password # 创建"password"键
        logging.info("starting server at %s:%d" % (a_config['server'], int(port)))  # 记录服务开启
        tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False))    # 添加TCP查询对象,TCP代理实现
        udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False))    # 添加UDP查询对象

    # 开启服务
    def run_server():
        def child_handler(signum, _):
            logging.warning('received SIGQUIT, doing graceful shutting down..')
            list(map(lambda s: s.close(next_tick=True), tcp_servers + udp_servers))
        signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM), child_handler)

        def int_handler(signum, _):
            sys.exit(1)
        signal.signal(signal.SIGINT, int_handler)

        try:
            loop = eventloop.EventLoop()    # 创建事件循环处理对象
            dns_resolver.add_to_loop(loop)  # 将DNS绑定到事件循环
            list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers))

            daemon.set_user(config.get('user', None))   # 开启角色进程守护
            
            loop.run()  # 开启事件处理死循环
            
        except Exception as e:
            shell.print_exception(e)    # 异常处理
            sys.exit(1) # 退出

    if int(config['workers']) > 1:
        if os.name == 'posix':
            children = []
            is_child = False
            for i in range(0, int(config['workers'])):
                r = os.fork()
                if r == 0:
                    logging.info('worker started')
                    is_child = True
                    run_server()
                    break
                else:
                    children.append(r)
            if not is_child:
                def handler(signum, _):
                    for pid in children:
                        try:
                            os.kill(pid, signum)
                            os.waitpid(pid, 0)
                        except OSError:  # child may already exited
                            pass
                    sys.exit()
                signal.signal(signal.SIGTERM, handler)
                signal.signal(signal.SIGQUIT, handler)
                signal.signal(signal.SIGINT, handler)

                # master
                for a_tcp_server in tcp_servers:
                    a_tcp_server.close()
                for a_udp_server in udp_servers:
                    a_udp_server.close()
                dns_resolver.close()

                for child in children:
                    os.waitpid(child, 0)
        else:
            logging.warn('worker is only available on Unix/Linux')
            run_server()
    else:
        run_server()
Exemplo n.º 10
0
def main():
    logging.basicConfig(
        level=logging.DEBUG,
        format=
        '%(levelname)-4s:%(filename)s %(lineno)d %(funcName)s %(message)s')
    logging.info("main exec...")

    # a = "123456"
    # b = []
    # b.append(a)
    #
    # logging.info("a:%s" % a[2:])
    # logging.info("b:%s" % type(b))
    #
    # s = utils.encode(b[0])
    # logging.info(s)
    # b = utils.decode(s)
    # logging.info(b)

    shell.check_python()

    config = shell.get_config(False)

    daemon.daemon_exec(config)

    if config['port_password']:
        if config['password']:
            logging.warn('warning: port_password should not be used with '
                         'server_port and password. server_port and password '
                         'will be ignored')
    else:
        config['port_password'] = {}
        server_port = config['server_port']
        if type(server_port) == list:
            for a_server_port in server_port:
                logging.info('a_server_port:%s' % str(a_server_port))
                config['port_password'][a_server_port] = config['password']
        else:
            logging.info('server_port:%s' % str(server_port))
            config['port_password'][str(server_port)] = config['password']

    if config.get('manager_address', 0):
        logging.info('entering manager mode')
        manager.run(config)
        return

    tcp_servers = []
    udp_servers = []

    if 'dns_server' in config:  # allow override settings in resolv.conf
        logging.info("dns_server in config")
        dns_resolver = asyncdns.DNSResolver(config['dns_server'],
                                            config['prefer_ipv6'])
    else:
        logging.info("dns_server not in config")
        dns_resolver = asyncdns.DNSResolver(prefer_ipv6=config['prefer_ipv6'])

    port_password = config['port_password']
    logging.info("port_password:%s" % str(port_password))

    del config['port_password']
    for port, password in port_password.items():
        a_config = config.copy()
        a_config['server_port'] = int(port)
        a_config['password'] = password
        logging.info("starting server at %s:%d" %
                     (a_config['server'], int(port)))
        tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False))
        udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False))

    logging.info('config type:' + str(type(config)))

    def run_server():
        logging.info("run_server enters")

        def child_handler(signum, _):
            logging.warn('received SIGQUIT, doing graceful shutting down..')
            list(
                map(lambda s: s.close(next_tick=True),
                    tcp_servers + udp_servers))

        signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM),
                      child_handler)

        def int_handler(signum, _):
            sys.exit(1)

        signal.signal(signal.SIGINT, int_handler)

        try:
            loop = eventloop.EventLoop()
            dns_resolver.add_to_loop(loop)
            list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers))

            daemon.set_user(config.get('user', None))
            loop.run()
        except Exception as e:
            shell.print_exception(e)
            sys.exit(1)

    if int(config['workers']) > 1:
        if os.name == 'posix':
            children = []
            is_child = False
            for i in range(0, int(config['workers'])):
                r = os.fork()
                if r == 0:
                    logging.info('worker started')
                    is_child = True
                    logging.info("run_server enters - 3")
                    run_server()
                    break
                else:
                    children.append(r)
            if not is_child:

                def handler(signum, _):
                    for pid in children:
                        try:
                            os.kill(pid, signum)
                            os.waitpid(pid, 0)
                        except OSError:  # child may already exited
                            pass
                    sys.exit()

                signal.signal(signal.SIGTERM, handler)
                signal.signal(signal.SIGQUIT, handler)
                signal.signal(signal.SIGINT, handler)

                # master
                for a_tcp_server in tcp_servers:
                    a_tcp_server.close()
                for a_udp_server in udp_servers:
                    a_udp_server.close()
                dns_resolver.close()

                for child in children:
                    os.waitpid(child, 0)
        else:
            logging.warn('worker is only available on Unix/Linux')
            logging.info("call run_server - 1")
            run_server()
    else:
        logging.info("call run_server enters - 2")
        run_server()
Exemplo n.º 11
0
def main():
    """
    启动服务器主函数 

    :return: None
    """
    shell.check_python()
    config = shell.get_config(False)
    daemon.daemon_exec(config)
    if config['port_password']:
        if config['password']:
            # 提示:端口密码不能用服务器端口号和密码
            logging.warn('warning: port_password should not be used with '
                         'server_port and password. server_port and password '
                         'will be ignored')
    else:
        # 清空端口密码
        config['port_password'] = {}
        # 提取服务器端口
        server_port = config['server_port']
        # 如果是列表形式
        if type(server_port) == list:
            # 给每个port赋password
            for a_server_port in server_port:
                config['port_password'][a_server_port] = config['password']
        else:
            # 只有1个port,单独赋值
            config['port_password'][str(server_port)] = config['password']

    if config.get('manager_address', 0):
        # 管理模式
        logging.info('entering manager mode')
        manager.run(config)
        return

    tcp_servers = []
    udp_servers = []
    dns_resolver = asyncdns.DNSResolver()
    # 得到每个端口的密码
    port_password = config['port_password']
    del config['port_password']
    # 对每个端口及其对应的密码
    for port, password in port_password.items():
        a_config = config.copy()
        # 记录当前端口和密码
        a_config['server_port'] = int(port)
        a_config['password'] = password
        # 开启服务器
        logging.info("starting server at %s:%d" %
                     (a_config['server'], int(port)))
        tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False))
        udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False))

    def run_server():
        """
        服务器运行
        
        :return: None
        """
        def child_handler(signum, _):
            """
            子程序要求关闭 
            
            :param signum: 信号值
            
            :param _: 不明
            
            :return: None 
            """
            logging.warn('received SIGQUIT, doing graceful shutting down..')
            list(
                map(lambda s: s.close(next_tick=True),
                    tcp_servers + udp_servers))

        signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM),
                      child_handler)

        def int_handler(signum, _):
            """
            强制退出程序,意义不明 
            
            :param signum: 信号值
            
            :param _: 不明
            
            :return: None
            """
            sys.exit(1)

        signal.signal(signal.SIGINT, int_handler)

        try:
            loop = eventloop.EventLoop()
            # 用addtoloop把dnsresolver添加到eventloop里,当DNSResolver对应的socket有dns解析结果可以读取的时候,eventloop会自动调用其handle_event方法将就绪的socket递给DNSResolver,DNSResolver就可以从其中读取dns应答数据了。
            dns_resolver.add_to_loop(loop)
            list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers))

            daemon.set_user(config.get('user', None))
            loop.run()
        except Exception as e:
            shell.print_exception(e)
            sys.exit(1)

    # workers<=1时开启服务器,>1时检查
    if int(config['workers']) > 1:
        if os.name == 'posix':
            children = []
            is_child = False
            for i in range(0, int(config['workers'])):
                r = os.fork()
                if r == 0:
                    logging.info('worker started')
                    is_child = True
                    run_server()
                    break
                else:
                    children.append(r)
            if not is_child:
                # 不是子进程
                def handler(signum, _):
                    """
                    关闭所有子进程
                    
                    :param signum: 信号值 
                    
                    :param _: 不明 
                    
                    :return: None
                    
                    :raises OSError: 子进程已经退出
                    """
                    for pid in children:
                        try:
                            os.kill(pid, signum)
                            os.waitpid(pid, 0)
                        except OSError:  # child may already exited
                            pass
                    sys.exit()

                signal.signal(signal.SIGTERM, handler)
                signal.signal(signal.SIGQUIT, handler)
                signal.signal(signal.SIGINT, handler)

                # 关闭所有服务器
                for a_tcp_server in tcp_servers:
                    a_tcp_server.close()
                for a_udp_server in udp_servers:
                    a_udp_server.close()
                dns_resolver.close()

                for child in children:
                    os.waitpid(child, 0)
        else:
            logging.warn('worker is only available on Unix/Linux')
            run_server()
    else:
        run_server()
Exemplo n.º 12
0
        if config['password']:
            logging.warn('warning: port_password should not be used with '
                         'server_port and password. server_port and password '
                         'will be ignored')
    else:
        config['port_password'] = {}
        server_port = config['server_port']
        if type(server_port) == list:
            for a_server_port in server_port:
                config['port_password'][a_server_port] = config['password']
        else:
            config['port_password'][str(server_port)] = config['password']

    if config.get('manager_address', 0):
        logging.info('entering manager mode')
        manager.run(config)
        return

    tcp_servers = []
    udp_servers = []
    dns_resolver = asyncdns.DNSResolver()
    port_password = config['port_password']
    del config['port_password']
    for port, password in port_password.items():
        a_config = config.copy()
        a_config['server_port'] = int(port)
        a_config['password'] = password
        logging.info("starting server at %s:%d" %
                     (a_config['server'], int(port)))
        tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False))
        udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False))
Exemplo n.º 13
0
def main():
    shell.check_python()

    # 读取配置信息,False 表示这里是服务端运行
    config = shell.get_config(False)

    # TODO 临时打印配置信息
    print(config)
    """
    默认配置信息
    {
        'log-file': '/var/log/shadowsocks.log',
        'verbose': False,
        'local_port': 1080,
        'workers': 1,
        'fast_open': False,
        'forbidden_ip': <shadowsocks.common.IPNetwork object at 0x10f4f8a10>,
        'server': '0.0.0.0',
        'port_password': None,
        'server_port': None,
        'timeout': 300,
        'local_address': '127.0.0.1',
        'pid-file': '/var/run/shadowsocks.pid',
        'password': '', 必填
        'method': 'aes-256-cfb'
    }
    """

    # 根据配置对守护进程进行操作,不开启 daemon 时此处可忽略
    daemon.daemon_exec(config)

    """
    port_password 为一个字典,每个端口有不同的密码,用于多用户登录
    "port_password": {
        "8381": "foobar1",
        "8382": "foobar2",
        }
    """
    if config['port_password']:
        # 如果既配置了端口密码又配置了全局密码,则全局密码会被忽略
        if config['password']:
            logging.warn('warning: port_password should not be used with '
                         'server_port and password. server_port and password '
                         'will be ignored')
    else:
        config['port_password'] = {}
        # TODO 待确认
        # 此处应为 server_port = config.get('server_port', 8388) 以允许默认端口启动
        server_port = config.get('server_port', None)
        if server_port:
            if type(server_port) == list:
                for a_server_port in server_port:
                    config['port_password'][a_server_port] = config['password']
            else:
                config['port_password'][str(server_port)] = config['password']
    print(config)

    # 如果获取到 manager_address,则启动管理进程
    if config.get('manager_address', 0):
        logging.info('entering manager mode')
        manager.run(config)
        return

    tcp_servers = []
    udp_servers = []

    # 如果设置了 dns 服务器
    if 'dns_server' in config:  # allow override settings in resolv.conf
        dns_resolver = asyncdns.DNSResolver(config['dns_server'])
    else:
        dns_resolver = asyncdns.DNSResolver()

    # 取出服务端口和其密码,当设置中不开启 port_password 时,也会退化到使用 port_password,此时 port_password 为单元素列表
    port_password = config['port_password']
    # 后面用 port_password 中每一项分别生成一份配置,所以 config['port_password'] 就用不着了
    del config['port_password']
    # 循环每一对端口和密码
    for port, password in port_password.items():
        # dict.copy() 创建了一个新的字典对象,内容一样
        a_config = config.copy()
        a_config['server_port'] = int(port)
        a_config['password'] = password
        logging.info("starting server at %s:%d" %
                     (a_config['server'], int(port)))
        # 用每一对端口和密码产生一对 TCP 和 UDP 的 Relay 实例
        tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False))
        udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False))

    def run_server():
        def child_handler(signum, _):
            logging.warn('received SIGQUIT, doing graceful shutting down..')
            list(map(lambda s: s.close(next_tick=True),
                     tcp_servers + udp_servers))
        """
        getattr(object, name[, default]) 如果 siganl.SIGQUIT 不存在,即注册 SIGTERM 事件
        SIGTERM 终止进程,但终止前会允许 handler 被执行,SIGKILL 不会
        SIGQUIT 在 SIGTERM 的基础上,还生成了一份 core dump 文件记录了进程信息
        http://programmergamer.blogspot.jp/2013/05/clarification-on-sigint-sigterm-sigkill.html
        """
        signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM),
                      child_handler)

        # 中断处理函数,如果接受到键盘中断信号,则异常退出
        def int_handler(signum, _):
            sys.exit(1)
        signal.signal(signal.SIGINT, int_handler)

        try:
            # 定义新事件循环
            loop = eventloop.EventLoop()
            # 添加 dns 解析器到事件循环中
            dns_resolver.add_to_loop(loop)
            # 批量地将所有 tcp_server 和 udp_server 加入事件循环中
            list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers))
            # 使守护进程以设置中 user 的名义执行
            daemon.set_user(config.get('user', None))
            # 启动事件循环
            loop.run()
        except Exception as e:
            shell.print_exception(e)
            sys.exit(1)

    # 如果 workers 为 1 则直接启动 server,否则进行 fork()
    if int(config['workers']) > 1:
        if os.name == 'posix':
            children = []
            is_child = False
            for i in range(0, int(config['workers'])):
                r = os.fork()
                # 如果执行这段代码的进程为子进程,输出启动信息,然后运行 run_server()
                if r == 0:
                    logging.info('worker started')
                    is_child = True
                    run_server()
                    break
                else:
                    # 如果为父进程,添加到 pid 到子进程列表中
                    children.append(r)
            # 如果是父进程
            if not is_child:
                def handler(signum, _):
                    for pid in children:
                        try:
                            os.kill(pid, signum)
                            os.waitpid(pid, 0)
                        except OSError:  # child may already exited
                            pass
                    sys.exit()
                # 当收到中断或者终止信号时,向每个子进程 pid 发出终止信号
                signal.signal(signal.SIGTERM, handler)
                signal.signal(signal.SIGQUIT, handler)
                signal.signal(signal.SIGINT, handler)

                # master
                # 关闭所有 tcp_server,udp_server 和 dns 解析器
                # close 方法从 eventloop 中移除了每个注册的事件
                for a_tcp_server in tcp_servers:
                    a_tcp_server.close()
                for a_udp_server in udp_servers:
                    a_udp_server.close()
                dns_resolver.close()

                for child in children:
                    # TODO 待测试
                    # 等待子进程结束,当子进程结束时返回
                    os.waitpid(child, 0)
        else:
            logging.warn('worker is only available on Unix/Linux')
            run_server()
    else:
        run_server()
Exemplo n.º 14
0
def main():
    shell.check_python()

    config = shell.get_config(False)

    daemon.daemon_exec(config)

    # 支持多客户端
    if config['port_password']:
        if config['password']:
            logging.warn('warning: port_password should not be used with '
                         'server_port and password. server_port and password '
                         'will be ignored')
    else:
        config['port_password'] = {}
        server_port = config['server_port']
        # 若发现有多用户配置:采用‘端口->密码’的映射方式。
        if type(server_port) == list:
            for a_server_port in server_port:
                config['port_password'][a_server_port] = config['password']
        else:
            config['port_password'][str(server_port)] = config['password']

    if config.get('manager_address', 0):
        logging.info('entering manager mode')
        manager.run(config)
        return

    tcp_servers = []
    udp_servers = []

    # 创建一个dns解析对象
    if 'dns_server' in config:  # allow override settings in resolv.conf
        dns_resolver = asyncdns.DNSResolver(config['dns_server'],
                                            config['prefer_ipv6'])
    else:
        dns_resolver = asyncdns.DNSResolver(prefer_ipv6=config['prefer_ipv6'])

    # 一个服务器端可以打开多个端口
    # 对于每个端口,都要新建一个对应的处理器
    # 同时从配置文件中删除对应的配置
    port_password = config['port_password']
    del config['port_password']
    for port, password in port_password.items():
        a_config = config.copy()
        a_config['server_port'] = int(port)
        a_config['password'] = password
        logging.info("starting server at %s:%d" %
                     (a_config['server'], int(port)))
        # 逐一加到tcp、udp列表
        tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False))
        udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False))

    def run_server():
        def child_handler(signum, _):
            logging.warn('received SIGQUIT, doing graceful shutting down..')
            # 关闭所有的socket,lambda表达式一句话搞定
            # map(function, sequence[, sequence, ...]) -> list
            # Return a list of the results of applying the function to the items of the argument sequence(s).
            list(
                map(lambda s: s.close(next_tick=True),
                    tcp_servers + udp_servers))

        signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM),
                      child_handler)

        def int_handler(signum, _):
            sys.exit(1)

        signal.signal(signal.SIGINT, int_handler)

        try:
            loop = eventloop.EventLoop()
            dns_resolver.add_to_loop(loop)
            # 把所有的监听端口添加到事件循环loop中,lambda表达式一句话搞定
            list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers))

            daemon.set_user(config.get('user', None))
            loop.run()
        except Exception as e:
            shell.print_exception(e)
            sys.exit(1)

    # Shadowsocks supports spawning child processes like nginx.
    # You can use --workers to specify how many workers to use.
    # This argument is only supported on Unix and ssserver.
    # Currently UDP relay does not work well on multiple workers.
    # 支持像nginx多进程,可以在config中指定worker的数量。仅在linux下生效。
    # 目前的bug:worker设为大于1时,udp转发有可能工作不正常
    if int(config['workers']) > 1:
        if os.name == 'posix':
            children = []
            is_child = False
            for i in range(0, int(config['workers'])):
                r = os.fork()
                if r == 0:
                    logging.info('worker started')
                    is_child = True
                    run_server()
                    break
                else:
                    children.append(r)
            if not is_child:

                def handler(signum, _):
                    for pid in children:
                        try:
                            os.kill(pid, signum)
                            os.waitpid(pid, 0)
                        except OSError:  # child may already exited
                            pass
                    sys.exit()

                signal.signal(signal.SIGTERM, handler)
                signal.signal(signal.SIGQUIT, handler)
                signal.signal(signal.SIGINT, handler)

                # master
                for a_tcp_server in tcp_servers:
                    a_tcp_server.close()
                for a_udp_server in udp_servers:
                    a_udp_server.close()
                dns_resolver.close()

                for child in children:
                    os.waitpid(child, 0)
        else:
            logging.warn('worker is only available on Unix/Linux')
            run_server()
    else:
        run_server()