mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-24 16:10:02 -06:00
186 lines
5.1 KiB
Python
186 lines
5.1 KiB
Python
# This is a forward backport of the Python2.5 uuid module. It isn't available
|
|
# in Python 2.6
|
|
|
|
# The next several classes are used to define FakeSocket, a socket-like
|
|
# interface to an SSL connection.
|
|
|
|
# The primary complexity comes from faking a makefile() method. The
|
|
# standard socket makefile() implementation calls dup() on the socket
|
|
# file descriptor. As a consequence, clients can call close() on the
|
|
# parent socket and its makefile children in any order. The underlying
|
|
# socket isn't closed until they are all closed.
|
|
|
|
# The implementation uses reference counting to keep the socket open
|
|
# until the last client calls close(). SharedSocket keeps track of
|
|
# the reference counting and SharedSocketClient provides an constructor
|
|
# and close() method that call incref() and decref() correctly.
|
|
|
|
import socket
|
|
import errno
|
|
from httplib import UnimplementedFileMode, HTTPException
|
|
|
|
error = HTTPException
|
|
|
|
class SharedSocket:
|
|
def __init__(self, sock):
|
|
self.sock = sock
|
|
self._refcnt = 0
|
|
|
|
def incref(self):
|
|
self._refcnt += 1
|
|
|
|
def decref(self):
|
|
self._refcnt -= 1
|
|
assert self._refcnt >= 0
|
|
if self._refcnt == 0:
|
|
self.sock.close()
|
|
|
|
def __del__(self):
|
|
self.sock.close()
|
|
|
|
class SharedSocketClient:
|
|
|
|
def __init__(self, shared):
|
|
self._closed = 0
|
|
self._shared = shared
|
|
self._shared.incref()
|
|
self._sock = shared.sock
|
|
|
|
def close(self):
|
|
if not self._closed:
|
|
self._shared.decref()
|
|
self._closed = 1
|
|
self._shared = None
|
|
|
|
class SSLFile(SharedSocketClient):
|
|
"""File-like object wrapping an SSL socket."""
|
|
|
|
BUFSIZE = 8192
|
|
|
|
def __init__(self, sock, ssl, bufsize=None):
|
|
SharedSocketClient.__init__(self, sock)
|
|
self._ssl = ssl
|
|
self._buf = ''
|
|
self._bufsize = bufsize or self.__class__.BUFSIZE
|
|
|
|
def _read(self):
|
|
buf = ''
|
|
# put in a loop so that we retry on transient errors
|
|
while True:
|
|
try:
|
|
buf = self._ssl.read(self._bufsize)
|
|
except socket.sslerror, err:
|
|
if (err[0] == socket.SSL_ERROR_WANT_READ
|
|
or err[0] == socket.SSL_ERROR_WANT_WRITE):
|
|
continue
|
|
if (err[0] == socket.SSL_ERROR_ZERO_RETURN
|
|
or err[0] == socket.SSL_ERROR_EOF):
|
|
break
|
|
raise
|
|
except socket.error, err:
|
|
if err[0] == errno.EINTR:
|
|
continue
|
|
if err[0] == errno.EBADF:
|
|
# XXX socket was closed?
|
|
break
|
|
raise
|
|
else:
|
|
break
|
|
return buf
|
|
|
|
def read(self, size=None):
|
|
L = [self._buf]
|
|
avail = len(self._buf)
|
|
while size is None or avail < size:
|
|
s = self._read()
|
|
if s == '':
|
|
break
|
|
L.append(s)
|
|
avail += len(s)
|
|
alldata = "".join(L)
|
|
if size is None:
|
|
self._buf = ''
|
|
return alldata
|
|
else:
|
|
self._buf = alldata[size:]
|
|
return alldata[:size]
|
|
|
|
def readline(self):
|
|
L = [self._buf]
|
|
self._buf = ''
|
|
while 1:
|
|
i = L[-1].find("\n")
|
|
if i >= 0:
|
|
break
|
|
s = self._read()
|
|
if s == '':
|
|
break
|
|
L.append(s)
|
|
if i == -1:
|
|
# loop exited because there is no more data
|
|
return "".join(L)
|
|
else:
|
|
alldata = "".join(L)
|
|
# XXX could do enough bookkeeping not to do a 2nd search
|
|
i = alldata.find("\n") + 1
|
|
line = alldata[:i]
|
|
self._buf = alldata[i:]
|
|
return line
|
|
|
|
def readlines(self, sizehint=0):
|
|
total = 0
|
|
inlist = []
|
|
while True:
|
|
line = self.readline()
|
|
if not line:
|
|
break
|
|
inlist.append(line)
|
|
total += len(line)
|
|
if sizehint and total >= sizehint:
|
|
break
|
|
return inlist
|
|
|
|
def fileno(self):
|
|
return self._sock.fileno()
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def next(self):
|
|
line = self.readline()
|
|
if not line:
|
|
raise StopIteration
|
|
return line
|
|
|
|
class FakeSocket(SharedSocketClient):
|
|
|
|
class _closedsocket:
|
|
def __getattr__(self, name):
|
|
raise error(9, 'Bad file descriptor')
|
|
|
|
def __init__(self, sock, ssl):
|
|
sock = SharedSocket(sock)
|
|
SharedSocketClient.__init__(self, sock)
|
|
self._ssl = ssl
|
|
|
|
def close(self):
|
|
SharedSocketClient.close(self)
|
|
self._sock = self.__class__._closedsocket()
|
|
|
|
def makefile(self, mode, bufsize=None):
|
|
if mode != 'r' and mode != 'rb':
|
|
raise UnimplementedFileMode()
|
|
return SSLFile(self._shared, self._ssl, bufsize)
|
|
|
|
def send(self, stuff, flags = 0):
|
|
return self._ssl.write(stuff)
|
|
|
|
sendall = send
|
|
|
|
def recv(self, len = 1024, flags = 0):
|
|
return self._ssl.read(len)
|
|
|
|
def __getattr__(self, attr):
|
|
return getattr(self._sock, attr)
|
|
|