existingconnectionserver.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. """
  2. Socket server for a the special case of a single, already existing, connection.
  3. Pyro - Python Remote Objects. Copyright by Irmen de Jong (irmen@razorvine.net).
  4. """
  5. from __future__ import print_function
  6. import socket
  7. import sys
  8. import logging
  9. import ssl
  10. from Pyro4 import socketutil, errors, util
  11. from Pyro4.configuration import config
  12. log = logging.getLogger("Pyro4.existingconnectionserver")
  13. class SocketServer_ExistingConnection(object):
  14. def __init__(self):
  15. self.sock = self.daemon = self.locationStr = self.conn = None
  16. self.shutting_down = False
  17. def init(self, daemon, connected_socket):
  18. connected_socket.getpeername() # check that it is connected
  19. if config.SSL and not isinstance(connected_socket, ssl.SSLSocket):
  20. raise socket.error("SSL configured for Pyro but existing socket is not a SSL socket")
  21. self.daemon = daemon
  22. self.sock = connected_socket
  23. log.info("starting server on user-supplied connected socket " + str(connected_socket))
  24. sn = connected_socket.getsockname()
  25. if hasattr(socket, "AF_UNIX") and connected_socket.family == socket.AF_UNIX:
  26. self.locationStr = "./u:" + (sn or "<<not-bound>>")
  27. else:
  28. host, port = sn[:2]
  29. if ":" in host: # ipv6
  30. self.locationStr = "[%s]:%d" % (host, port)
  31. else:
  32. self.locationStr = "%s:%d" % (host, port)
  33. self.conn = socketutil.SocketConnection(connected_socket)
  34. def __repr__(self):
  35. return "<%s on %s>" % (self.__class__.__name__, self.locationStr)
  36. def __del__(self):
  37. if self.sock is not None:
  38. self.sock = None
  39. self.conn = None
  40. @property
  41. def selector(self):
  42. raise TypeError("single-connection server doesn't have multiplexing selector")
  43. @property
  44. def sockets(self):
  45. return [self.sock]
  46. def combine_loop(self, server):
  47. raise errors.PyroError("cannot combine servers when using user-supplied connected socket")
  48. def events(self, eventsockets):
  49. raise errors.PyroError("cannot combine events when using user-supplied connected socket")
  50. def shutdown(self):
  51. self.shutting_down = True
  52. self.close()
  53. self.sock = None
  54. self.conn = None
  55. def close(self):
  56. # don't close the socket itself, that's the user's responsibility
  57. self.sock = None
  58. self.conn = None
  59. def handleRequest(self):
  60. """Handles a single connection request event and returns if the connection is still active"""
  61. try:
  62. self.daemon.handleRequest(self.conn)
  63. return True
  64. except (socket.error, errors.ConnectionClosedError, errors.SecurityError) as x:
  65. # client went away or caused a security error.
  66. # close the connection silently.
  67. try:
  68. peername = self.conn.sock.getpeername()
  69. log.debug("disconnected %s", peername)
  70. except socket.error:
  71. log.debug("disconnected a client")
  72. self.shutdown()
  73. return False
  74. except errors.TimeoutError as x:
  75. # for timeout errors we're not really interested in detailed traceback info
  76. log.warning("error during handleRequest: %s" % x)
  77. return False
  78. except:
  79. # other error occurred, close the connection, but also log a warning
  80. ex_t, ex_v, ex_tb = sys.exc_info()
  81. tb = util.formatTraceback(ex_t, ex_v, ex_tb)
  82. msg = "error during handleRequest: %s; %s" % (ex_v, "".join(tb))
  83. log.warning(msg)
  84. return False
  85. def loop(self, loopCondition=lambda: True):
  86. log.debug("entering requestloop")
  87. while loopCondition() and self.sock:
  88. try:
  89. self.handleRequest()
  90. self.daemon._housekeeping()
  91. except socket.timeout:
  92. pass # just continue the loop on a timeout
  93. except KeyboardInterrupt:
  94. log.debug("stopping on break signal")
  95. break