rpyc_classic.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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. # ssl-authenticated server (keyfile and certfile are required)
  8. rpyc_classic.py --ssl-keyfile keyfile.pem --ssl-certfile certfile.pem --ssl-cafile cafile.pem
  9. """
  10. import sys
  11. import os
  12. import rpyc
  13. from plumbum import cli
  14. from rpyc.utils.server import ThreadedServer, ForkingServer, OneShotServer
  15. from rpyc.utils.classic import DEFAULT_SERVER_PORT, DEFAULT_SERVER_SSL_PORT
  16. from rpyc.utils.registry import REGISTRY_PORT
  17. from rpyc.utils.registry import UDPRegistryClient, TCPRegistryClient
  18. from rpyc.utils.authenticators import SSLAuthenticator
  19. from rpyc.lib import setup_logger
  20. from rpyc.core import SlaveService
  21. class ClassicServer(cli.Application):
  22. mode = cli.SwitchAttr(["-m", "--mode"], cli.Set("threaded", "forking", "stdio", "oneshot"),
  23. default="threaded", help="The serving mode (threaded, forking, or 'stdio' for "
  24. "inetd, etc.)")
  25. port = cli.SwitchAttr(["-p", "--port"], cli.Range(0, 65535), default=None,
  26. help="The TCP listener port (default = %s, default for SSL = %s)" %
  27. (DEFAULT_SERVER_PORT, DEFAULT_SERVER_SSL_PORT), group="Socket Options")
  28. host = cli.SwitchAttr(["--host"], str, default="", help="The host to bind to. "
  29. "The default is localhost", group="Socket Options")
  30. ipv6 = cli.Flag(["--ipv6"], help="Enable IPv6", group="Socket Options")
  31. logfile = cli.SwitchAttr("--logfile", str, default=None, help="Specify the log file to use; "
  32. "the default is stderr", group="Logging")
  33. quiet = cli.Flag(["-q", "--quiet"], help="Quiet mode (only errors will be logged)",
  34. group="Logging")
  35. ssl_keyfile = cli.SwitchAttr("--ssl-keyfile", cli.ExistingFile,
  36. help="The keyfile to use for SSL. Required for SSL", group="SSL",
  37. requires=["--ssl-certfile"])
  38. ssl_certfile = cli.SwitchAttr("--ssl-certfile", cli.ExistingFile,
  39. help="The certificate file to use for SSL. Required for SSL", group="SSL",
  40. requires=["--ssl-keyfile"])
  41. ssl_cafile = cli.SwitchAttr("--ssl-cafile", cli.ExistingFile,
  42. help="The certificate authority chain file to use for SSL. "
  43. "Optional; enables client-side authentication",
  44. group="SSL", requires=["--ssl-keyfile"])
  45. auto_register = cli.Flag("--register", help="Asks the server to attempt registering with "
  46. "a registry server. By default, the server will not attempt to register",
  47. group="Registry")
  48. registry_type = cli.SwitchAttr("--registry-type", cli.Set("UDP", "TCP"),
  49. default="UDP", help="Specify a UDP or TCP registry", group="Registry")
  50. registry_port = cli.SwitchAttr("--registry-port", cli.Range(0, 65535), default=REGISTRY_PORT,
  51. help="The registry's UDP/TCP port", group="Registry")
  52. registry_host = cli.SwitchAttr("--registry-host", str, default=None,
  53. help="The registry host machine. For UDP, the default is 255.255.255.255; "
  54. "for TCP, a value is required", group="Registry")
  55. def main(self):
  56. if not self.host:
  57. self.host = "::1" if self.ipv6 else "127.0.0.1"
  58. if self.registry_type == "UDP":
  59. if self.registry_host is None:
  60. self.registry_host = "255.255.255.255"
  61. self.registrar = UDPRegistryClient(ip=self.registry_host, port=self.registry_port)
  62. else:
  63. if self.registry_host is None:
  64. raise ValueError("With TCP registry, you must specify --registry-host")
  65. self.registrar = TCPRegistryClient(ip=self.registry_host, port=self.registry_port)
  66. if self.ssl_keyfile:
  67. self.authenticator = SSLAuthenticator(self.ssl_keyfile, self.ssl_certfile,
  68. self.ssl_cafile)
  69. default_port = DEFAULT_SERVER_SSL_PORT
  70. else:
  71. self.authenticator = None
  72. default_port = DEFAULT_SERVER_PORT
  73. if self.port is None:
  74. self.port = default_port
  75. setup_logger(self.quiet, self.logfile)
  76. if self.mode == "threaded":
  77. self._serve_mode(ThreadedServer)
  78. elif self.mode == "forking":
  79. self._serve_mode(ForkingServer)
  80. elif self.mode == "oneshot":
  81. self._serve_oneshot()
  82. elif self.mode == "stdio":
  83. self._serve_stdio()
  84. def _serve_mode(self, factory):
  85. t = factory(SlaveService, hostname=self.host, port=self.port,
  86. reuse_addr=True, ipv6=self.ipv6, authenticator=self.authenticator,
  87. registrar=self.registrar, auto_register=self.auto_register)
  88. t.start()
  89. def _serve_oneshot(self):
  90. t = OneShotServer(SlaveService, hostname=self.host, port=self.port,
  91. reuse_addr=True, ipv6=self.ipv6, authenticator=self.authenticator,
  92. registrar=self.registrar, auto_register=self.auto_register)
  93. t._listen()
  94. sys.stdout.write("rpyc-oneshot\n")
  95. sys.stdout.write("%s\t%s\n" % (t.host, t.port))
  96. sys.stdout.flush()
  97. t.start()
  98. def _serve_stdio(self):
  99. origstdin = sys.stdin
  100. origstdout = sys.stdout
  101. sys.stdin = open(os.devnull, "r")
  102. sys.stdout = open(os.devnull, "w")
  103. sys.stderr = open(os.devnull, "w")
  104. conn = rpyc.classic.connect_pipes(origstdin, origstdout)
  105. try:
  106. try:
  107. conn.serve_all()
  108. except KeyboardInterrupt:
  109. print("User interrupt!")
  110. finally:
  111. conn.close()
  112. if __name__ == "__main__":
  113. ClassicServer.run()
  114. #python rpyc_classic.py --host=0.0.0.0 -m threaded -p 12333 --ssl-keyfile=./server.key --ssl-certfile=./server.cer