dictserver.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. """ DICT server """
  5. from __future__ import (absolute_import, division, print_function,
  6. unicode_literals)
  7. import argparse
  8. import os
  9. import sys
  10. import logging
  11. try: # Python 2
  12. import SocketServer as socketserver
  13. except ImportError: # Python 3
  14. import socketserver
  15. log = logging.getLogger(__name__)
  16. HOST = "localhost"
  17. # The strings that indicate the test framework is checking our aliveness
  18. VERIFIED_REQ = b"verifiedserver"
  19. VERIFIED_RSP = "WE ROOLZ: {pid}"
  20. def dictserver(options):
  21. """
  22. Starts up a TCP server with a DICT handler and serves DICT requests
  23. forever.
  24. """
  25. if options.pidfile:
  26. pid = os.getpid()
  27. with open(options.pidfile, "w") as f:
  28. f.write("{0}".format(pid))
  29. local_bind = (options.host, options.port)
  30. log.info("[DICT] Listening on %s", local_bind)
  31. # Need to set the allow_reuse on the class, not on the instance.
  32. socketserver.TCPServer.allow_reuse_address = True
  33. server = socketserver.TCPServer(local_bind, DictHandler)
  34. server.serve_forever()
  35. return ScriptRC.SUCCESS
  36. class DictHandler(socketserver.BaseRequestHandler):
  37. """Handler class for DICT connections.
  38. """
  39. def handle(self):
  40. """
  41. Simple function which responds to all queries with a 552.
  42. """
  43. try:
  44. # First, send a response to allow the server to continue.
  45. rsp = "220 dictserver <xnooptions> <msgid@msgid>\n"
  46. self.request.sendall(rsp.encode("utf-8"))
  47. # Receive the request.
  48. data = self.request.recv(1024).strip()
  49. log.debug("[DICT] Incoming data: %r", data)
  50. if VERIFIED_REQ in data:
  51. log.debug("[DICT] Received verification request from test "
  52. "framework")
  53. response_data = VERIFIED_RSP.format(pid=os.getpid())
  54. else:
  55. log.debug("[DICT] Received normal request")
  56. response_data = "No matches"
  57. # Send back a failure to find.
  58. response = "552 {0}\n".format(response_data)
  59. log.debug("[DICT] Responding with %r", response)
  60. self.request.sendall(response.encode("utf-8"))
  61. except IOError:
  62. log.exception("[DICT] IOError hit during request")
  63. def get_options():
  64. parser = argparse.ArgumentParser()
  65. parser.add_argument("--port", action="store", default=9016,
  66. type=int, help="port to listen on")
  67. parser.add_argument("--host", action="store", default=HOST,
  68. help="host to listen on")
  69. parser.add_argument("--verbose", action="store", type=int, default=0,
  70. help="verbose output")
  71. parser.add_argument("--pidfile", action="store",
  72. help="file name for the PID")
  73. parser.add_argument("--logfile", action="store",
  74. help="file name for the log")
  75. parser.add_argument("--srcdir", action="store", help="test directory")
  76. parser.add_argument("--id", action="store", help="server ID")
  77. parser.add_argument("--ipv4", action="store_true", default=0,
  78. help="IPv4 flag")
  79. return parser.parse_args()
  80. def setup_logging(options):
  81. """
  82. Set up logging from the command line options
  83. """
  84. root_logger = logging.getLogger()
  85. add_stdout = False
  86. formatter = logging.Formatter("%(asctime)s %(levelname)-5.5s %(message)s")
  87. # Write out to a logfile
  88. if options.logfile:
  89. handler = logging.FileHandler(options.logfile, mode="w")
  90. handler.setFormatter(formatter)
  91. handler.setLevel(logging.DEBUG)
  92. root_logger.addHandler(handler)
  93. else:
  94. # The logfile wasn't specified. Add a stdout logger.
  95. add_stdout = True
  96. if options.verbose:
  97. # Add a stdout logger as well in verbose mode
  98. root_logger.setLevel(logging.DEBUG)
  99. add_stdout = True
  100. else:
  101. root_logger.setLevel(logging.INFO)
  102. if add_stdout:
  103. stdout_handler = logging.StreamHandler(sys.stdout)
  104. stdout_handler.setFormatter(formatter)
  105. stdout_handler.setLevel(logging.DEBUG)
  106. root_logger.addHandler(stdout_handler)
  107. class ScriptRC(object):
  108. """Enum for script return codes"""
  109. SUCCESS = 0
  110. FAILURE = 1
  111. EXCEPTION = 2
  112. class ScriptException(Exception):
  113. pass
  114. if __name__ == '__main__':
  115. # Get the options from the user.
  116. options = get_options()
  117. # Setup logging using the user options
  118. setup_logging(options)
  119. # Run main script.
  120. try:
  121. rc = dictserver(options)
  122. except Exception as e:
  123. log.exception(e)
  124. rc = ScriptRC.EXCEPTION
  125. log.info("[DICT] Returning %d", rc)
  126. sys.exit(rc)