server.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. # Copyright (c) 2009-2012 Denis Bilenko. See LICENSE for details.
  2. """TCP/SSL server"""
  3. import sys
  4. import _socket
  5. from gevent.baseserver import BaseServer
  6. from gevent.socket import EWOULDBLOCK, socket
  7. from gevent._compat import PYPY, PY3
  8. __all__ = ['StreamServer', 'DatagramServer']
  9. if sys.platform == 'win32':
  10. # SO_REUSEADDR on Windows does not mean the same thing as on *nix (issue #217)
  11. DEFAULT_REUSE_ADDR = None
  12. else:
  13. DEFAULT_REUSE_ADDR = 1
  14. class StreamServer(BaseServer):
  15. """
  16. A generic TCP server.
  17. Accepts connections on a listening socket and spawns user-provided
  18. *handle* function for each connection with 2 arguments: the client
  19. socket and the client address.
  20. Note that although the errors in a successfully spawned handler
  21. will not affect the server or other connections, the errors raised
  22. by :func:`accept` and *spawn* cause the server to stop accepting
  23. for a short amount of time. The exact period depends on the values
  24. of :attr:`min_delay` and :attr:`max_delay` attributes.
  25. The delay starts with :attr:`min_delay` and doubles with each
  26. successive error until it reaches :attr:`max_delay`. A successful
  27. :func:`accept` resets the delay to :attr:`min_delay` again.
  28. See :class:`~gevent.baseserver.BaseServer` for information on defining the *handle*
  29. function and important restrictions on it.
  30. **SSL Support**
  31. The server can optionally work in SSL mode when given the correct
  32. keyword arguments. (That is, the presence of any keyword arguments
  33. will trigger SSL mode.) On Python 2.7.9 and later (any Python
  34. version that supports the :class:`ssl.SSLContext`), this can be
  35. done with a configured ``SSLContext``. On any Python version, it
  36. can be done by passing the appropriate arguments for
  37. :func:`ssl.wrap_socket`.
  38. The incoming socket will be wrapped into an SSL socket before
  39. being passed to the *handle* function.
  40. If the *ssl_context* keyword argument is present, it should
  41. contain an :class:`ssl.SSLContext`. The remaining keyword
  42. arguments are passed to the :meth:`ssl.SSLContext.wrap_socket`
  43. method of that object. Depending on the Python version, supported arguments
  44. may include:
  45. - server_hostname
  46. - suppress_ragged_eofs
  47. - do_handshake_on_connect
  48. .. caution:: When using an SSLContext, it should either be
  49. imported from :mod:`gevent.ssl`, or the process needs to be monkey-patched.
  50. If the process is not monkey-patched and you pass the standard library
  51. SSLContext, the resulting client sockets will not cooperate with gevent.
  52. Otherwise, keyword arguments are assumed to apply to :func:`ssl.wrap_socket`.
  53. These keyword arguments bay include:
  54. - keyfile
  55. - certfile
  56. - cert_reqs
  57. - ssl_version
  58. - ca_certs
  59. - suppress_ragged_eofs
  60. - do_handshake_on_connect
  61. - ciphers
  62. .. versionchanged:: 1.2a2
  63. Add support for the *ssl_context* keyword argument.
  64. """
  65. # the default backlog to use if none was provided in __init__
  66. backlog = 256
  67. reuse_addr = DEFAULT_REUSE_ADDR
  68. def __init__(self, listener, handle=None, backlog=None, spawn='default', **ssl_args):
  69. BaseServer.__init__(self, listener, handle=handle, spawn=spawn)
  70. try:
  71. if ssl_args:
  72. ssl_args.setdefault('server_side', True)
  73. if 'ssl_context' in ssl_args:
  74. ssl_context = ssl_args.pop('ssl_context')
  75. self.wrap_socket = ssl_context.wrap_socket
  76. self.ssl_args = ssl_args
  77. else:
  78. from gevent.ssl import wrap_socket
  79. self.wrap_socket = wrap_socket
  80. self.ssl_args = ssl_args
  81. else:
  82. self.ssl_args = None
  83. if backlog is not None:
  84. if hasattr(self, 'socket'):
  85. raise TypeError('backlog must be None when a socket instance is passed')
  86. self.backlog = backlog
  87. except:
  88. self.close()
  89. raise
  90. @property
  91. def ssl_enabled(self):
  92. return self.ssl_args is not None
  93. def set_listener(self, listener):
  94. BaseServer.set_listener(self, listener)
  95. try:
  96. self.socket = self.socket._sock
  97. except AttributeError:
  98. pass
  99. def init_socket(self):
  100. if not hasattr(self, 'socket'):
  101. # FIXME: clean up the socket lifetime
  102. # pylint:disable=attribute-defined-outside-init
  103. self.socket = self.get_listener(self.address, self.backlog, self.family)
  104. self.address = self.socket.getsockname()
  105. if self.ssl_args:
  106. self._handle = self.wrap_socket_and_handle
  107. else:
  108. self._handle = self.handle
  109. @classmethod
  110. def get_listener(cls, address, backlog=None, family=None):
  111. if backlog is None:
  112. backlog = cls.backlog
  113. return _tcp_listener(address, backlog=backlog, reuse_addr=cls.reuse_addr, family=family)
  114. if PY3:
  115. def do_read(self):
  116. sock = self.socket
  117. try:
  118. fd, address = sock._accept()
  119. except BlockingIOError: # python 2: pylint: disable=undefined-variable
  120. if not sock.timeout:
  121. return
  122. raise
  123. sock = socket(sock.family, sock.type, sock.proto, fileno=fd)
  124. # XXX Python issue #7995?
  125. return sock, address
  126. else:
  127. def do_read(self):
  128. try:
  129. client_socket, address = self.socket.accept()
  130. except _socket.error as err:
  131. if err.args[0] == EWOULDBLOCK:
  132. return
  133. raise
  134. sockobj = socket(_sock=client_socket)
  135. if PYPY:
  136. client_socket._drop()
  137. return sockobj, address
  138. def do_close(self, sock, *args):
  139. # pylint:disable=arguments-differ
  140. sock.close()
  141. def wrap_socket_and_handle(self, client_socket, address):
  142. # used in case of ssl sockets
  143. ssl_socket = self.wrap_socket(client_socket, **self.ssl_args)
  144. return self.handle(ssl_socket, address)
  145. class DatagramServer(BaseServer):
  146. """A UDP server"""
  147. reuse_addr = DEFAULT_REUSE_ADDR
  148. def __init__(self, *args, **kwargs):
  149. # The raw (non-gevent) socket, if possible
  150. self._socket = None
  151. BaseServer.__init__(self, *args, **kwargs)
  152. from gevent.lock import Semaphore
  153. self._writelock = Semaphore()
  154. def init_socket(self):
  155. if not hasattr(self, 'socket'):
  156. # FIXME: clean up the socket lifetime
  157. # pylint:disable=attribute-defined-outside-init
  158. self.socket = self.get_listener(self.address, self.family)
  159. self.address = self.socket.getsockname()
  160. self._socket = self.socket
  161. try:
  162. self._socket = self._socket._sock
  163. except AttributeError:
  164. pass
  165. @classmethod
  166. def get_listener(cls, address, family=None):
  167. return _udp_socket(address, reuse_addr=cls.reuse_addr, family=family)
  168. def do_read(self):
  169. try:
  170. data, address = self._socket.recvfrom(8192)
  171. except _socket.error as err:
  172. if err.args[0] == EWOULDBLOCK:
  173. return
  174. raise
  175. return data, address
  176. def sendto(self, *args):
  177. self._writelock.acquire()
  178. try:
  179. self.socket.sendto(*args)
  180. finally:
  181. self._writelock.release()
  182. def _tcp_listener(address, backlog=50, reuse_addr=None, family=_socket.AF_INET):
  183. """A shortcut to create a TCP socket, bind it and put it into listening state."""
  184. sock = socket(family=family)
  185. if reuse_addr is not None:
  186. sock.setsockopt(_socket.SOL_SOCKET, _socket.SO_REUSEADDR, reuse_addr)
  187. try:
  188. sock.bind(address)
  189. except _socket.error as ex:
  190. strerror = getattr(ex, 'strerror', None)
  191. if strerror is not None:
  192. ex.strerror = strerror + ': ' + repr(address)
  193. raise
  194. sock.listen(backlog)
  195. sock.setblocking(0)
  196. return sock
  197. def _udp_socket(address, backlog=50, reuse_addr=None, family=_socket.AF_INET):
  198. # backlog argument for compat with tcp_listener
  199. # pylint:disable=unused-argument
  200. # we want gevent.socket.socket here
  201. sock = socket(family=family, type=_socket.SOCK_DGRAM)
  202. if reuse_addr is not None:
  203. sock.setsockopt(_socket.SOL_SOCKET, _socket.SO_REUSEADDR, reuse_addr)
  204. try:
  205. sock.bind(address)
  206. except _socket.error as ex:
  207. strerror = getattr(ex, 'strerror', None)
  208. if strerror is not None:
  209. ex.strerror = strerror + ': ' + repr(address)
  210. raise
  211. return sock