rpyc_classic.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #!/usr/bin/env python
  2. """
  3. classic rpyc server (threaded, forking or std) running a SlaveService
  4. usage:
  5. rpyc_classic.py # default settings
  6. rpyc_classic.py -m forking -p 12345 # custom settings
  7. rpyc_classic.py --vdb file.vdb # tlslite-authenticated server
  8. # ssl-authenticated server (keyfile and certfile are required)
  9. rpyc_classic.py --ssl-keyfile keyfile.pem --ssl-certfile certfile.pem --ssl-cafile cafile.pem
  10. """
  11. import sys
  12. import os
  13. import rpyc
  14. from optparse import OptionParser
  15. from rpyc.utils.server import ThreadedServer, ForkingServer
  16. from rpyc.utils.classic import DEFAULT_SERVER_PORT, DEFAULT_SERVER_SSL_PORT
  17. from rpyc.utils.registry import REGISTRY_PORT
  18. from rpyc.utils.registry import UDPRegistryClient, TCPRegistryClient
  19. from rpyc.utils.authenticators import TlsliteVdbAuthenticator, SSLAuthenticator
  20. from rpyc.lib import setup_logger
  21. from rpyc.core import SlaveService
  22. parser = OptionParser()
  23. parser.add_option("-m", "--mode", action="store", dest="mode", metavar="MODE",
  24. default="threaded", type="string", help="mode can be 'threaded', 'forking', "
  25. "or 'stdio' to operate over the standard IO pipes (for inetd, etc.). "
  26. "Default is 'threaded'")
  27. #
  28. # TCP options
  29. #
  30. parser.add_option("-p", "--port", action="store", dest="port", type="int",
  31. metavar="PORT", default=None,
  32. help="specify a different TCP listener port (default = %s, default for SSL = %s)" %
  33. (DEFAULT_SERVER_PORT, DEFAULT_SERVER_SSL_PORT))
  34. parser.add_option("--host", action="store", dest="host", type="str",
  35. metavar="HOST", default="0.0.0.0", help="specify a different "
  36. "host to bind to. Default is 0.0.0.0")
  37. #
  38. # logging
  39. #
  40. parser.add_option("--logfile", action="store", dest="logfile", type="str",
  41. metavar="FILE", default=None, help="specify the log file to use; the "
  42. "default is stderr")
  43. parser.add_option("-q", "--quiet", action="store_true", dest="quiet",
  44. default=False,
  45. help="quiet mode (no logging). in stdio mode, writes to /dev/null")
  46. #
  47. # TLSlite
  48. #
  49. parser.add_option("--vdb", action="store", dest="vdbfile", metavar="FILENAME",
  50. default=None, help="starts an TLS/SSL authenticated server (using tlslite);"
  51. "the credentials are loaded from the vdb file. if not given, the server"
  52. "is not secure (unauthenticated). use vdbconf.py to manage vdb files"
  53. )
  54. #
  55. # SSL
  56. #
  57. parser.add_option("--ssl-keyfile", action="store", dest="ssl_keyfile", metavar="FILENAME",
  58. default=None, help="the keyfile to use for SSL. required for SSL"
  59. )
  60. parser.add_option("--ssl-certfile", action="store", dest="ssl_certfile", metavar="FILENAME",
  61. default=None, help="the certificate file to use for SSL. required for SSL"
  62. )
  63. parser.add_option("--ssl-cafile", action="store", dest="ssl_cafile", metavar="FILENAME",
  64. default=None, help="the certificate authority chain file to use for SSL. "
  65. "optional, allows client-side authentication"
  66. )
  67. #
  68. # registry
  69. #
  70. parser.add_option("--register", action="store_true", dest="auto_register",
  71. default=False, help="asks the server to attempt registering with a registry server"
  72. "By default, the server will not attempt to register")
  73. parser.add_option("--registry-type", action="store", dest="regtype", type="str",
  74. default="udp", help="can be 'udp' or 'tcp', default is 'udp'")
  75. parser.add_option("--registry-port", action="store", dest="regport", type="int",
  76. default=REGISTRY_PORT, help="the UDP/TCP port. default is %s" % (REGISTRY_PORT,))
  77. parser.add_option("--registry-host", action="store", dest="reghost", type="str",
  78. default=None, help="the registry host machine. for UDP, the default is "
  79. "255.255.255.255; for TCP, a value is required")
  80. def get_options():
  81. options, args = parser.parse_args()
  82. if args:
  83. parser.error("does not take positional arguments: %r" % (args,))
  84. options.mode = options.mode.lower()
  85. if options.regtype.lower() == "udp":
  86. if options.reghost is None:
  87. options.reghost = "255.255.255.255"
  88. options.registrar = UDPRegistryClient(ip = options.reghost, port = options.regport)
  89. elif options.regtype.lower() == "tcp":
  90. if options.reghost is None:
  91. parser.error("must specific --registry-host")
  92. options.registrar = TCPRegistryClient(ip = options.reghost, port = options.regport)
  93. else:
  94. parser.error("invalid registry type %r" % (options.regtype,))
  95. if options.vdbfile:
  96. if not os.path.exists(options.vdbfile):
  97. parser.error("vdb file does not exist")
  98. options.authenticator = TlsliteVdbAuthenticator.from_file(options.vdbfile, mode = "r")
  99. if options.ssl_keyfile or options.ssl_certfile or options.ssl_cafile:
  100. if not options.ssl_keyfile:
  101. parser.error("SSL: keyfile required")
  102. if not options.ssl_certfile:
  103. parser.error("SSL: certfile required")
  104. options.authenticator = SSLAuthenticator(options.ssl_keyfile,
  105. options.ssl_certfile, options.ssl_cafile)
  106. if not options.port:
  107. options.port = DEFAULT_SERVER_SSL_PORT
  108. else:
  109. options.authenticator = None
  110. if not options.port:
  111. options.port = DEFAULT_SERVER_PORT
  112. options.handler = "serve_%s" % (options.mode,)
  113. if options.handler not in globals():
  114. parser.error("invalid mode %r" % (options.mode,))
  115. return options
  116. def serve_threaded(options):
  117. setup_logger(options)
  118. t = ThreadedServer(SlaveService, hostname = options.host,
  119. port = options.port, reuse_addr = True,
  120. authenticator = options.authenticator, registrar = options.registrar,
  121. auto_register = options.auto_register)
  122. t.logger.quiet = options.quiet
  123. if options.logfile:
  124. t.logger.console = open(options.logfile, "w")
  125. t.start()
  126. def serve_forking(options):
  127. setup_logger(options)
  128. t = ForkingServer(SlaveService, hostname = options.host,
  129. port = options.port, reuse_addr = True,
  130. authenticator = options.authenticator, registrar = options.registrar,
  131. auto_register = options.auto_register)
  132. t.logger.quiet = options.quiet
  133. if options.logfile:
  134. t.logger.console = open(options.logfile, "w")
  135. t.start()
  136. def serve_stdio(options):
  137. origstdin = sys.stdin
  138. origstdout = sys.stdout
  139. if options.quiet:
  140. dev = os.devnull
  141. elif sys.platform == "win32":
  142. dev = "con:"
  143. else:
  144. dev = "/dev/tty"
  145. try:
  146. sys.stdin = open(dev, "r")
  147. sys.stdout = open(dev, "w")
  148. except (IOError, OSError):
  149. sys.stdin = open(os.devnull, "r")
  150. sys.stdout = open(os.devnull, "w")
  151. conn = rpyc.classic.connect_pipes(origstdin, origstdout)
  152. try:
  153. try:
  154. conn.serve_all()
  155. except KeyboardInterrupt:
  156. print( "User interrupt!" )
  157. finally:
  158. conn.close()
  159. def main():
  160. options = get_options()
  161. handler = globals()[options.handler]
  162. handler(options)
  163. if __name__ == "__main__":
  164. main()