]> review.fuel-infra Code Review - packages/trusty/python-eventlet.git/blob - eventlet/eventlet/convenience.py
Adjust the package revision; no actual code changes
[packages/trusty/python-eventlet.git] / eventlet / eventlet / convenience.py
1 import sys
2
3 from eventlet import greenio
4 from eventlet import greenpool
5 from eventlet import greenthread
6 from eventlet.green import socket
7 from eventlet.support import greenlets as greenlet
8
9
10 def connect(addr, family=socket.AF_INET, bind=None):
11     """Convenience function for opening client sockets.
12
13     :param addr: Address of the server to connect to.  For TCP sockets, this is a (host, port) tuple.
14     :param family: Socket family, optional.  See :mod:`socket` documentation for available families.
15     :param bind: Local address to bind to, optional.
16     :return: The connected green socket object.
17     """
18     sock = socket.socket(family, socket.SOCK_STREAM)
19     if bind is not None:
20         sock.bind(bind)
21     sock.connect(addr)
22     return sock
23
24
25 def listen(addr, family=socket.AF_INET, backlog=50):
26     """Convenience function for opening server sockets.  This
27     socket can be used in :func:`~eventlet.serve` or a custom ``accept()`` loop.
28
29     Sets SO_REUSEADDR on the socket to save on annoyance.
30
31     :param addr: Address to listen on.  For TCP sockets, this is a (host, port)  tuple.
32     :param family: Socket family, optional.  See :mod:`socket` documentation for available families.
33     :param backlog: The maximum number of queued connections. Should be at least 1; the maximum value is system-dependent.
34     :return: The listening green socket object.
35     """
36     sock = socket.socket(family, socket.SOCK_STREAM)
37     if sys.platform[:3] != "win":
38         sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
39     sock.bind(addr)
40     sock.listen(backlog)
41     return sock
42
43
44 class StopServe(Exception):
45     """Exception class used for quitting :func:`~eventlet.serve` gracefully."""
46     pass
47
48
49 def _stop_checker(t, server_gt, conn):
50     try:
51         try:
52             t.wait()
53         finally:
54             conn.close()
55     except greenlet.GreenletExit:
56         pass
57     except Exception:
58         greenthread.kill(server_gt, *sys.exc_info())
59
60
61 def serve(sock, handle, concurrency=1000):
62     """Runs a server on the supplied socket.  Calls the function *handle* in a
63     separate greenthread for every incoming client connection.  *handle* takes
64     two arguments: the client socket object, and the client address::
65
66         def myhandle(client_sock, client_addr):
67             print("client connected", client_addr)
68
69         eventlet.serve(eventlet.listen(('127.0.0.1', 9999)), myhandle)
70
71     Returning from *handle* closes the client socket.
72
73     :func:`serve` blocks the calling greenthread; it won't return until
74     the server completes.  If you desire an immediate return,
75     spawn a new greenthread for :func:`serve`.
76
77     Any uncaught exceptions raised in *handle* are raised as exceptions
78     from :func:`serve`, terminating the server, so be sure to be aware of the
79     exceptions your application can raise.  The return value of *handle* is
80     ignored.
81
82     Raise a :class:`~eventlet.StopServe` exception to gracefully terminate the
83     server -- that's the only way to get the server() function to return rather
84     than raise.
85
86     The value in *concurrency* controls the maximum number of
87     greenthreads that will be open at any time handling requests.  When
88     the server hits the concurrency limit, it stops accepting new
89     connections until the existing ones complete.
90     """
91     pool = greenpool.GreenPool(concurrency)
92     server_gt = greenthread.getcurrent()
93
94     while True:
95         try:
96             conn, addr = sock.accept()
97             gt = pool.spawn(handle, conn, addr)
98             gt.link(_stop_checker, server_gt, conn)
99             conn, addr, gt = None, None, None
100         except StopServe:
101             return
102
103
104 def wrap_ssl(sock, *a, **kw):
105     """Convenience function for converting a regular socket into an
106     SSL socket.  Has the same interface as :func:`ssl.wrap_socket`,
107     but can also use PyOpenSSL. Though, note that it ignores the
108     `cert_reqs`, `ssl_version`, `ca_certs`, `do_handshake_on_connect`,
109     and `suppress_ragged_eofs` arguments when using PyOpenSSL.
110
111     The preferred idiom is to call wrap_ssl directly on the creation
112     method, e.g., ``wrap_ssl(connect(addr))`` or
113     ``wrap_ssl(listen(addr), server_side=True)``. This way there is
114     no "naked" socket sitting around to accidentally corrupt the SSL
115     session.
116
117     :return Green SSL object.
118     """
119     return wrap_ssl_impl(sock, *a, **kw)
120
121 try:
122     from eventlet.green import ssl
123     wrap_ssl_impl = ssl.wrap_socket
124 except ImportError:
125     # trying PyOpenSSL
126     try:
127         from eventlet.green.OpenSSL import SSL
128     except ImportError:
129         def wrap_ssl_impl(*a, **kw):
130             raise ImportError("To use SSL with Eventlet, you must install PyOpenSSL or use Python 2.6 or later.")
131     else:
132         def wrap_ssl_impl(sock, keyfile=None, certfile=None, server_side=False,
133                           cert_reqs=None, ssl_version=None, ca_certs=None,
134                           do_handshake_on_connect=True,
135                           suppress_ragged_eofs=True, ciphers=None):
136             # theoretically the ssl_version could be respected in this line
137             context = SSL.Context(SSL.SSLv23_METHOD)
138             if certfile is not None:
139                 context.use_certificate_file(certfile)
140             if keyfile is not None:
141                 context.use_privatekey_file(keyfile)
142             context.set_verify(SSL.VERIFY_NONE, lambda *x: True)
143
144             connection = SSL.Connection(context, sock)
145             if server_side:
146                 connection.set_accept_state()
147             else:
148                 connection.set_connect_state()
149             return connection