text: #!/usr/bin/env python
  # -*- coding: utf-8 -*-
  
  # Copyright (c) 2014 clowwindy
  #
  # Permission is hereby granted, free of charge, to any person obtaining a copy
  # of this software and associated documentation files (the "Software"), to deal
  # in the Software without restriction, including without limitation the rights
  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  # copies of the Software, and to permit persons to whom the Software is
  # furnished to do so, subject to the following conditions:
  #
  # The above copyright notice and this permission notice shall be included in
  # all copies or substantial portions of the Software.
  #
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  # SOFTWARE.
  
  from __future__ import absolute_import, division, print_function, \
      with_statement
  
  import sys
  import os
  import logging
  import signal
  
  sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../'))
  from shadowsocks import utils, encrypt, eventloop, tcprelay, udprelay, asyncdns
  
  
  def main():
      utils.check_python()
  
      config = utils.get_config(False)
  
      utils.print_shadowsocks()
  
      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']
  
      encrypt.init_table(config['password'], config['method'])
      tcp_servers = []
      udp_servers = []
      dns_resolver = asyncdns.DNSResolver()
      for port, password in config['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)
          try:
              loop = eventloop.EventLoop()
              dns_resolver.add_to_loop(loop)
              list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers))
              loop.run()
          except (KeyboardInterrupt, IOError, OSError) as e:
              logging.error(e)
              if config['verbose']:
                  import traceback
                  traceback.print_exc()
              os._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)
                          except OSError:  # child may already exited
                              pass
                      sys.exit()
                  signal.signal(signal.SIGTERM, handler)
                  signal.signal(signal.SIGQUIT, 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()
  
  
  if __name__ == '__main__':
      main()
  