186 lines
6.5 KiB
Python
186 lines
6.5 KiB
Python
from OpenSSL import SSL as orig_SSL
|
|
from OpenSSL.SSL import *
|
|
from eventlet import greenio
|
|
from eventlet.hubs import trampoline
|
|
import socket
|
|
|
|
class GreenConnection(greenio.GreenSocket):
|
|
""" Nonblocking wrapper for SSL.Connection objects.
|
|
"""
|
|
def __init__(self, ctx, sock=None):
|
|
if sock is not None:
|
|
fd = orig_SSL.Connection(ctx, sock)
|
|
else:
|
|
# if we're given a Connection object directly, use it;
|
|
# this is used in the inherited accept() method
|
|
fd = ctx
|
|
super(ConnectionType, self).__init__(fd)
|
|
self.sock = self
|
|
|
|
def close(self):
|
|
super(GreenConnection, self).close()
|
|
|
|
def do_handshake(self):
|
|
""" Perform an SSL handshake (usually called after renegotiate or one of
|
|
set_accept_state or set_accept_state). This can raise the same exceptions as
|
|
send and recv. """
|
|
if self.act_non_blocking:
|
|
return self.fd.do_handshake()
|
|
while True:
|
|
try:
|
|
return self.fd.do_handshake()
|
|
except WantReadError:
|
|
trampoline(self.fd.fileno(),
|
|
read=True,
|
|
timeout=self.timeout,
|
|
timeout_exc=socket.timeout)
|
|
except WantWriteError:
|
|
trampoline(self.fd.fileno(),
|
|
write=True,
|
|
timeout=self.timeout,
|
|
timeout_exc=socket.timeout)
|
|
|
|
def dup(self):
|
|
raise NotImplementedError("Dup not supported on SSL sockets")
|
|
|
|
def get_app_data(self, *args, **kw):
|
|
fn = self.get_app_data = self.fd.get_app_data
|
|
return fn(*args, **kw)
|
|
|
|
def set_app_data(self, *args, **kw):
|
|
fn = self.set_app_data = self.fd.set_app_data
|
|
return fn(*args, **kw)
|
|
|
|
def get_cipher_list(self, *args, **kw):
|
|
fn = self.get_cipher_list = self.fd.get_cipher_list
|
|
return fn(*args, **kw)
|
|
|
|
def get_context(self, *args, **kw):
|
|
fn = self.get_context = self.fd.get_context
|
|
return fn(*args, **kw)
|
|
|
|
def get_peer_certificate(self, *args, **kw):
|
|
fn = self.get_peer_certificate = self.fd.get_peer_certificate
|
|
return fn(*args, **kw)
|
|
|
|
def makefile(self, mode='r', bufsize=-1):
|
|
raise NotImplementedError("Makefile not supported on SSL sockets")
|
|
|
|
def pending(self, *args, **kw):
|
|
fn = self.pending = self.fd.pending
|
|
return fn(*args, **kw)
|
|
|
|
def read(self, size):
|
|
"""Works like a blocking call to SSL_read(), whose behavior is
|
|
described here: http://www.openssl.org/docs/ssl/SSL_read.html"""
|
|
if self.act_non_blocking:
|
|
return self.fd.read(size)
|
|
while True:
|
|
try:
|
|
return self.fd.read(size)
|
|
except WantReadError:
|
|
trampoline(self.fd.fileno(),
|
|
read=True,
|
|
timeout=self.timeout,
|
|
timeout_exc=socket.timeout)
|
|
except WantWriteError:
|
|
trampoline(self.fd.fileno(),
|
|
write=True,
|
|
timeout=self.timeout,
|
|
timeout_exc=socket.timeout)
|
|
except SysCallError, e:
|
|
if e[0] == -1 or e[0] > 0:
|
|
return ''
|
|
|
|
recv = read
|
|
|
|
def renegotiate(self, *args, **kw):
|
|
fn = self.renegotiate = self.fd.renegotiate
|
|
return fn(*args, **kw)
|
|
|
|
def write(self, data):
|
|
"""Works like a blocking call to SSL_write(), whose behavior is
|
|
described here: http://www.openssl.org/docs/ssl/SSL_write.html"""
|
|
if not data:
|
|
return 0 # calling SSL_write() with 0 bytes to be sent is undefined
|
|
if self.act_non_blocking:
|
|
return self.fd.write(data)
|
|
while True:
|
|
try:
|
|
return self.fd.write(data)
|
|
except WantReadError:
|
|
trampoline(self.fd.fileno(),
|
|
read=True,
|
|
timeout=self.timeout,
|
|
timeout_exc=socket.timeout)
|
|
except WantWriteError:
|
|
trampoline(self.fd.fileno(),
|
|
write=True,
|
|
timeout=self.timeout,
|
|
timeout_exc=socket.timeout)
|
|
|
|
send = write
|
|
|
|
def sendall(self, data):
|
|
"""Send "all" data on the connection. This calls send() repeatedly until
|
|
all data is sent. If an error occurs, it's impossible to tell how much data
|
|
has been sent.
|
|
|
|
No return value."""
|
|
tail = self.send(data)
|
|
while tail < len(data):
|
|
tail += self.send(data[tail:])
|
|
|
|
def set_accept_state(self, *args, **kw):
|
|
fn = self.set_accept_state = self.fd.set_accept_state
|
|
return fn(*args, **kw)
|
|
|
|
def set_connect_state(self, *args, **kw):
|
|
fn = self.set_connect_state = self.fd.set_connect_state
|
|
return fn(*args, **kw)
|
|
|
|
def shutdown(self):
|
|
if self.act_non_blocking:
|
|
return self.fd.shutdown()
|
|
while True:
|
|
try:
|
|
return self.fd.shutdown()
|
|
except WantReadError:
|
|
trampoline(self.fd.fileno(),
|
|
read=True,
|
|
timeout=self.timeout,
|
|
timeout_exc=socket.timeout)
|
|
except WantWriteError:
|
|
trampoline(self.fd.fileno(),
|
|
write=True,
|
|
timeout=self.timeout,
|
|
timeout_exc=socket.timeout)
|
|
|
|
|
|
def get_shutdown(self, *args, **kw):
|
|
fn = self.get_shutdown = self.fd.get_shutdown
|
|
return fn(*args, **kw)
|
|
|
|
def set_shutdown(self, *args, **kw):
|
|
fn = self.set_shutdown = self.fd.set_shutdown
|
|
return fn(*args, **kw)
|
|
|
|
def sock_shutdown(self, *args, **kw):
|
|
fn = self.sock_shutdown = self.fd.sock_shutdown
|
|
return fn(*args, **kw)
|
|
|
|
def state_string(self, *args, **kw):
|
|
fn = self.state_string = self.fd.state_string
|
|
return fn(*args, **kw)
|
|
|
|
def want_read(self, *args, **kw):
|
|
fn = self.want_read = self.fd.want_read
|
|
return fn(*args, **kw)
|
|
|
|
def want_write(self, *args, **kw):
|
|
fn = self.want_write = self.fd.want_write
|
|
return fn(*args, **kw)
|
|
|
|
Connection = ConnectionType = GreenConnection
|
|
|
|
del greenio |