Files
shadowsocks/shadowsocks/server.py

130 lines
4.3 KiB
Python
Raw Normal View History

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
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__), '../'))
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')
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)
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:
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()