extras-buildsys/common SSLConnection.py,1.7,1.8
Daniel Williams (dcbw)
fedora-extras-commits at redhat.com
Wed Feb 15 17:13:30 UTC 2006
Author: dcbw
Update of /cvs/fedora/extras-buildsys/common
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv12123/common
Modified Files:
SSLConnection.py
Log Message:
2006-02-15 Dan Williams <dcbw at redhat.com>
* common/SSLConnection.py
- Don't use pyOpenSSL's sendall() call, since it simply
calls SSL_write() in a loop. Instead, we simulate the sendall
ourselves, allowing us to honor socket timeouts and to not
peg the CPU when we get WantReadError/WantWriteError exceptions due
to non-blocking IO
- Clean up the recv/sendall functions somewhat too
- Add some cosmetic inter-function spacing
- Increase WantReadError/WantWriteError sleeps from 0.1s -> 0.2s
- Return valid socket error message on timeout
Index: SSLConnection.py
===================================================================
RCS file: /cvs/fedora/extras-buildsys/common/SSLConnection.py,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- SSLConnection.py 24 Jan 2006 01:19:01 -0000 1.7
+++ SSLConnection.py 15 Feb 2006 17:13:22 -0000 1.8
@@ -29,18 +29,23 @@
self.__dict__["close_refcount"] = 0
self.__dict__["closed"] = False
self.__dict__["timeout"] = self.DEFAULT_TIMEOUT
+
def __del__(self):
self.__dict__["conn"].close()
+
def __getattr__(self,name):
return getattr(self.__dict__["conn"], name)
+
def __setattr__(self,name, value):
setattr(self.__dict__["conn"], name, value)
+
def settimeout(self, timeout):
if timeout == None:
self.__dict__["timeout"] = self.DEFAULT_TIMEOUT
else:
self.__dict__["timeout"] = timeout
self.__dict__["conn"].settimeout(timeout)
+
def shutdown(self, how=1):
"""
SimpleXMLRpcServer.doPOST calls shutdown(1),
@@ -48,6 +53,7 @@
an argument. So we just discard the argument.
"""
self.__dict__["conn"].shutdown()
+
def accept(self):
"""
This is the other part of the shutdown() workaround.
@@ -56,6 +62,7 @@
"""
c, a = self.__dict__["conn"].accept()
return (SSLConnection(c), a)
+
def makefile(self, mode, bufsize):
"""
We need to use socket._fileobject Because SSL.Connection
@@ -68,6 +75,7 @@
"""
self.__dict__["close_refcount"] = self.__dict__["close_refcount"] + 1
return PlgFileObject(self, mode, bufsize)
+
def close(self):
if self.__dict__["closed"]:
return
@@ -76,54 +84,66 @@
self.shutdown()
self.__dict__["conn"].close()
self.__dict__["closed"] = True
+
def sendall(self, data, flags=0):
- while True:
- # Use select() to simulate a socket timeout without setting the socket
- # to non-blocking mode
- (read, write, error) = select.select([], [self.__dict__["conn"]], [], self.__dict__["timeout"])
- if self.__dict__["conn"] in write:
- starttime = time.time()
- while True:
- try:
- return self.__dict__["conn"].sendall(data, flags)
- except SSL.SysCallError, e:
- if e[0] == 32: # Broken Pipe
- self.close()
- else:
- raise socket.error(e)
- except SSL.WantWriteError:
- time.sleep(0.1)
-
- curtime = time.time()
- if curtime - starttime > self.__dict__["timeout"]:
- raise socket.timeout
- else:
- raise socket.timeout
- if self.__dict__["conn"] in error:
- raise socket.error
- return None
+ """
+ - Use select() to simulate a socket timeout without setting the socket
+ to non-blocking mode.
+ - Don't use pyOpenSSL's sendall() either, since it just loops on WantRead
+ or WantWrite, consuming 100% CPU, and never times out.
+ """
+ timeout = self.__dict__["timeout"]
+ con = self.__dict__["conn"]
+ (read, write, excpt) = select.select([], [con], [], timeout)
+ if not con in write:
+ raise socket.timeout((110, "Operation timed out."))
+
+ starttime = time.time()
+ origlen = len(data)
+ sent = -1
+ while len(data):
+ curtime = time.time()
+ if curtime - starttime > timeout:
+ raise socket.timeout((110, "Operation timed out."))
+
+ try:
+ sent = con.send(data, flags)
+ except SSL.SysCallError, e:
+ if e[0] == 32: # Broken Pipe
+ self.close()
+ sent = 0
+ else:
+ raise socket.error(e)
+ except (SSL.WantWriteError, SSL.WantReadError):
+ time.sleep(0.2)
+ continue
+
+ data = data[sent:]
+ return origlen - len(data)
+
def recv(self, bufsize, flags=0):
+ """
+ Use select() to simulate a socket timeout without setting the socket
+ to non-blocking mode
+ """
+ timeout = self.__dict__["timeout"]
+ con = self.__dict__["conn"]
+ (read, write, excpt) = select.select([con], [], [], timeout)
+ if not con in read:
+ raise socket.timeout((110, "Operation timed out."))
+
+ starttime = time.time()
while True:
- # Use select() to simulate a socket timeout without setting the socket
- # to non-blocking mode
- (read, write, error) = select.select([self.__dict__["conn"]], [], [], self.__dict__["timeout"])
- if self.__dict__["conn"] in read:
- starttime = time.time()
- while True:
- try:
- return self.__dict__["conn"].recv(bufsize, flags)
- except SSL.ZeroReturnError:
- return None
- except SSL.WantReadError:
- time.sleep(0.1)
-
- curtime = time.time()
- if curtime - starttime > self.__dict__["timeout"]:
- raise socket.timeout
- else:
- raise socket.timeout
- if self.__dict__["conn"] in error:
- raise socket.error
+ curtime = time.time()
+ if curtime - starttime > timeout:
+ raise socket.timeout((110, "Operation timed out."))
+
+ try:
+ return con.recv(bufsize, flags)
+ except SSL.ZeroReturnError:
+ return None
+ except SSL.WantReadError:
+ time.sleep(0.2)
return None
class PlgFileObject(socket._fileobject):
More information about the scm-commits
mailing list