2012-04-20 22:26:00 +08:00
|
|
|
#!/usr/bin/env python
|
2014-04-23 16:31:17 +08:00
|
|
|
# -*- coding: utf-8 -*-
|
2012-04-20 22:26:00 +08:00
|
|
|
#
|
2015-02-03 14:10:36 +08:00
|
|
|
# Copyright 2015 clowwindy
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
|
|
# not use this file except in compliance with the License. You may obtain
|
|
|
|
# a copy of the License at
|
2012-04-20 22:26:00 +08:00
|
|
|
#
|
2015-02-03 14:10:36 +08:00
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
2012-04-20 22:26:00 +08:00
|
|
|
#
|
2015-02-03 14:10:36 +08:00
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
# License for the specific language governing permissions and limitations
|
|
|
|
# under the License.
|
2012-04-20 22:26:00 +08:00
|
|
|
|
2014-10-31 18:28:22 +08:00
|
|
|
from __future__ import absolute_import, division, print_function, \
|
|
|
|
with_statement
|
|
|
|
|
2012-12-30 13:28:51 +08:00
|
|
|
import sys
|
2014-05-17 12:44:12 +08:00
|
|
|
import os
|
2014-06-01 19:09:52 +08:00
|
|
|
import logging
|
2014-09-12 20:47:04 +08:00
|
|
|
import signal
|
2014-10-31 16:29:19 +08:00
|
|
|
|
2014-10-31 18:28:22 +08:00
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../'))
|
2015-02-02 15:46:22 +08:00
|
|
|
from shadowsocks import utils, daemon, eventloop, tcprelay, udprelay, asyncdns
|
2012-05-11 01:14:51 +08:00
|
|
|
|
2012-04-20 22:26:00 +08:00
|
|
|
|
2013-06-22 17:30:31 +08:00
|
|
|
def main():
|
2014-06-01 14:10:18 +08:00
|
|
|
utils.check_python()
|
2013-07-04 23:16:10 +08:00
|
|
|
|
2014-06-01 14:20:40 +08:00
|
|
|
config = utils.get_config(False)
|
2012-12-06 14:39:06 +08:00
|
|
|
|
2014-12-21 12:47:07 +08:00
|
|
|
daemon.daemon_exec(config)
|
|
|
|
|
2014-05-30 18:17:40 +08:00
|
|
|
if config['port_password']:
|
2014-09-20 19:01:52 +08:00
|
|
|
if config['password']:
|
2014-04-23 16:36:27 +08:00
|
|
|
logging.warn('warning: port_password should not be used with '
|
|
|
|
'server_port and password. server_port and password '
|
|
|
|
'will be ignored')
|
2013-11-17 06:17:30 +08:00
|
|
|
else:
|
2014-05-30 18:17:40 +08:00
|
|
|
config['port_password'] = {}
|
2014-06-18 15:50:05 +08:00
|
|
|
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']
|
2014-05-02 12:47:56 +08:00
|
|
|
|
2014-05-17 13:42:26 +08:00
|
|
|
tcp_servers = []
|
|
|
|
udp_servers = []
|
2014-06-08 15:58:59 +08:00
|
|
|
dns_resolver = asyncdns.DNSResolver()
|
2014-06-01 11:01:11 +08:00
|
|
|
for port, password in config['port_password'].items():
|
|
|
|
a_config = config.copy()
|
2014-06-01 17:16:58 +08:00
|
|
|
a_config['server_port'] = int(port)
|
2014-06-01 11:01:11 +08:00
|
|
|
a_config['password'] = password
|
2014-04-23 16:36:27 +08:00
|
|
|
logging.info("starting server at %s:%d" %
|
2014-06-01 17:16:58 +08:00
|
|
|
(a_config['server'], int(port)))
|
2014-06-08 15:58:59 +08:00
|
|
|
tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False))
|
|
|
|
udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False))
|
2014-05-17 13:42:26 +08:00
|
|
|
|
|
|
|
def run_server():
|
2014-09-12 00:51:25 +08:00
|
|
|
def child_handler(signum, _):
|
|
|
|
logging.warn('received SIGQUIT, doing graceful shutting down..')
|
2014-10-31 18:43:15 +08:00
|
|
|
list(map(lambda s: s.close(next_tick=True),
|
|
|
|
tcp_servers + udp_servers))
|
2014-09-20 20:21:09 +08:00
|
|
|
signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM),
|
|
|
|
child_handler)
|
2014-12-22 17:09:37 +08:00
|
|
|
|
|
|
|
def int_handler(signum, _):
|
|
|
|
sys.exit(1)
|
|
|
|
signal.signal(signal.SIGINT, int_handler)
|
|
|
|
|
2014-06-01 17:20:51 +08:00
|
|
|
try:
|
2014-06-01 19:09:52 +08:00
|
|
|
loop = eventloop.EventLoop()
|
2014-06-08 15:58:59 +08:00
|
|
|
dns_resolver.add_to_loop(loop)
|
2014-10-31 18:28:22 +08:00
|
|
|
list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers))
|
2015-02-02 15:38:55 +08:00
|
|
|
|
|
|
|
daemon.set_user(config.get('user', None))
|
2014-06-01 19:09:52 +08:00
|
|
|
loop.run()
|
2015-02-02 16:22:56 +08:00
|
|
|
except Exception as e:
|
2015-02-10 17:16:24 +08:00
|
|
|
utils.print_exception(e)
|
2015-02-02 16:22:56 +08:00
|
|
|
sys.exit(1)
|
2014-04-23 16:36:27 +08:00
|
|
|
|
2014-06-01 11:01:11 +08:00
|
|
|
if int(config['workers']) > 1:
|
2014-05-17 12:44:12 +08:00
|
|
|
if os.name == 'posix':
|
2014-05-17 13:42:26 +08:00
|
|
|
children = []
|
|
|
|
is_child = False
|
2014-10-31 18:28:22 +08:00
|
|
|
for i in range(0, int(config['workers'])):
|
2014-05-17 12:44:12 +08:00
|
|
|
r = os.fork()
|
|
|
|
if r == 0:
|
2014-05-17 13:42:26 +08:00
|
|
|
logging.info('worker started')
|
|
|
|
is_child = True
|
|
|
|
run_server()
|
2014-05-17 12:44:12 +08:00
|
|
|
break
|
2014-05-17 13:42:26 +08:00
|
|
|
else:
|
|
|
|
children.append(r)
|
|
|
|
if not is_child:
|
2014-06-01 17:56:41 +08:00
|
|
|
def handler(signum, _):
|
2014-05-17 14:02:30 +08:00
|
|
|
for pid in children:
|
2014-09-12 00:51:25 +08:00
|
|
|
try:
|
|
|
|
os.kill(pid, signum)
|
2014-12-11 13:00:08 +08:00
|
|
|
os.waitpid(pid, 0)
|
2014-09-12 00:51:25 +08:00
|
|
|
except OSError: # child may already exited
|
|
|
|
pass
|
2014-05-17 14:02:30 +08:00
|
|
|
sys.exit()
|
|
|
|
signal.signal(signal.SIGTERM, handler)
|
2014-09-12 00:51:25 +08:00
|
|
|
signal.signal(signal.SIGQUIT, handler)
|
2014-12-22 17:29:58 +08:00
|
|
|
signal.signal(signal.SIGINT, handler)
|
2014-05-24 19:16:21 +08:00
|
|
|
|
2014-05-17 13:42:26 +08:00
|
|
|
# master
|
2014-06-01 19:09:52 +08:00
|
|
|
for a_tcp_server in tcp_servers:
|
|
|
|
a_tcp_server.close()
|
|
|
|
for a_udp_server in udp_servers:
|
|
|
|
a_udp_server.close()
|
2014-06-08 15:58:59 +08:00
|
|
|
dns_resolver.close()
|
2014-05-24 19:16:21 +08:00
|
|
|
|
2014-05-17 13:42:26 +08:00
|
|
|
for child in children:
|
|
|
|
os.waitpid(child, 0)
|
2014-05-17 12:44:12 +08:00
|
|
|
else:
|
|
|
|
logging.warn('worker is only available on Unix/Linux')
|
2014-05-17 13:54:28 +08:00
|
|
|
run_server()
|
2014-05-17 13:42:26 +08:00
|
|
|
else:
|
|
|
|
run_server()
|
2014-05-17 12:44:12 +08:00
|
|
|
|
2013-06-22 17:30:31 +08:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2014-06-01 19:09:52 +08:00
|
|
|
main()
|