1 # Higher-level SSL objects used by rpclib
3 # Copyright (c) 2002 Red Hat, Inc.
5 # Author: Mihai Ibanescu <misa@redhat.com>
6 # Modifications by Dan Williams <dcbw@redhat.com>
9 from OpenSSL
import SSL
10 import time
, socket
, select
11 from CommonErrors
import canIgnoreSSLError
16 This whole class exists just to filter out a parameter
17 passed in to the shutdown() method in SimpleXMLRPC.doPOST()
22 def __init__(self
, conn
):
24 Connection is not yet a new-style class,
25 so I'm making a proxy instead of subclassing.
27 self
.__dict
__["conn"] = conn
28 self
.__dict
__["close_refcount"] = 0
29 self
.__dict
__["closed"] = False
30 self
.__dict
__["timeout"] = self
.DEFAULT_TIMEOUT
33 self
.__dict
__["conn"].close()
35 def __getattr__(self
,name
):
36 return getattr(self
.__dict
__["conn"], name
)
38 def __setattr__(self
,name
, value
):
39 setattr(self
.__dict
__["conn"], name
, value
)
41 def settimeout(self
, timeout
):
43 self
.__dict
__["timeout"] = self
.DEFAULT_TIMEOUT
45 self
.__dict
__["timeout"] = timeout
46 self
.__dict
__["conn"].settimeout(timeout
)
48 def shutdown(self
, how
=1):
50 SimpleXMLRpcServer.doPOST calls shutdown(1),
51 and Connection.shutdown() doesn't take
52 an argument. So we just discard the argument.
54 self
.__dict
__["conn"].shutdown()
58 This is the other part of the shutdown() workaround.
59 Since servers create new sockets, we have to infect
60 them with our magic. :)
62 c
, a
= self
.__dict
__["conn"].accept()
63 return (SSLConnection(c
), a
)
65 def makefile(self
, mode
, bufsize
):
67 We need to use socket._fileobject Because SSL.Connection
68 doesn't have a 'dup'. Not exactly sure WHY this is, but
69 this is backed up by comments in socket.py and SSL/connection.c
71 Since httplib.HTTPSResponse/HTTPConnection depend on the
72 socket being duplicated when they close it, we refcount the
73 socket object and don't actually close until its count is 0.
75 self
.__dict
__["close_refcount"] = self
.__dict
__["close_refcount"] + 1
76 return PlgFileObject(self
, mode
, bufsize
)
79 if self
.__dict
__["closed"]:
81 self
.__dict
__["close_refcount"] = self
.__dict
__["close_refcount"] - 1
82 if self
.__dict
__["close_refcount"] == 0:
84 self
.__dict
__["conn"].close()
85 self
.__dict
__["closed"] = True
87 def sendall(self
, data
, flags
=0):
89 - Use select() to simulate a socket timeout without setting the socket
91 - Don't use pyOpenSSL's sendall() either, since it just loops on WantRead
92 or WantWrite, consuming 100% CPU, and never times out.
94 timeout
= self
.__dict
__["timeout"]
95 con
= self
.__dict
__["conn"]
96 (read
, write
, excpt
) = select
.select([], [con
], [], timeout
)
98 raise socket
.timeout((110, "Operation timed out."))
100 if hasattr(data
, 'tobytes'):
101 data
= data
.tobytes()
103 starttime
= time
.time()
107 curtime
= time
.time()
108 if curtime
- starttime
> timeout
:
109 raise socket
.timeout((110, "Operation timed out."))
112 sent
= con
.send(data
, flags
)
113 except SSL
.SysCallError
, e
:
114 if e
[0] == 32: # Broken Pipe
118 raise socket
.error(e
)
119 except (SSL
.WantWriteError
, SSL
.WantReadError
):
124 return origlen
- len(data
)
126 def recv(self
, bufsize
, flags
=0):
128 Use select() to simulate a socket timeout without setting the socket
131 timeout
= self
.__dict
__["timeout"]
132 con
= self
.__dict
__["conn"]
133 (read
, write
, excpt
) = select
.select([con
], [], [], timeout
)
135 raise socket
.timeout((110, "Operation timed out."))
137 starttime
= time
.time()
139 curtime
= time
.time()
140 if curtime
- starttime
> timeout
:
141 raise socket
.timeout((110, "Operation timed out."))
144 return con
.recv(bufsize
, flags
)
145 except SSL
.ZeroReturnError
:
147 except SSL
.WantReadError
:
150 if canIgnoreSSLError(e
):
157 class PlgFileObject(socket
._fileobject
):
160 socket._fileobject doesn't actually _close_ the socket,
161 which we want it to do, so we have to override.