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