Ticket #764: Twistedssl.diff
| File Twistedssl.diff, 9.2 KB (added by jknight, 9 years ago) |
|---|
-
twisted/internet/abstract.py
129 129 return self._postLoseConnection() 130 130 elif self._writeDisconnecting: 131 131 # I was previously asked to to half-close the connection. 132 self._closeWriteConnection()132 result = self._closeWriteConnection() 133 133 self._writeDisconnected = True 134 134 return result 135 135 return result -
twisted/internet/tcp.py
74 74 class _TLSMixin: 75 75 writeBlockedOnRead = 0 76 76 readBlockedOnWrite = 0 77 sslShutdown = 078 77 _userWantRead = _userWantWrite = True 78 79 79 def getPeerCertificate(self): 80 80 return self.socket.get_peer_certificate() 81 81 82 82 def doRead(self): 83 83 if self.writeBlockedOnRead: 84 84 self.writeBlockedOnRead = 0 85 self. startWriting()85 self._resetReadWrite() 86 86 try: 87 87 return Connection.doRead(self) 88 88 except SSL.ZeroReturnError: 89 # close SSL layer, since other side has done so, if we haven't 90 if not self.sslShutdown: 91 try: 92 self.socket.shutdown() 93 self.sslShutdown = 1 94 except SSL.Error: 95 pass 89 #print "ZeroReturnError", self 96 90 return main.CONNECTION_DONE 97 91 except SSL.WantReadError: 98 92 return 99 93 except SSL.WantWriteError: 100 94 self.readBlockedOnWrite = 1 101 self.startWriting() 95 Connection.startWriting(self) 96 Connection.stopReading(self) 102 97 return 98 except SSL.SysCallError, (retval, desc): 99 if ((retval == -1 and desc == 'Unexpected EOF') 100 or retval > 0): 101 return main.CONNECTION_LOST 102 log.err() 103 return main.CONNECTION_LOST 103 104 except SSL.Error: 104 105 log.err() 105 106 return main.CONNECTION_LOST 106 107 107 def loseConnection(self):108 Connection.loseConnection(self)109 if self.connected:110 self.startReading()111 112 def halfCloseConnection(self, read=False, write=False):113 raise RuntimeError, "TLS connections currently do not support half-closing"114 115 108 def doWrite(self): 116 if self.writeBlockedOnRead: 117 self.stopWriting() 118 return 109 #print "doWrite", self 110 # Retry disconnecting 111 if self.disconnecting: 112 return self._postLoseConnection() 113 if self._writeDisconnected: 114 return self._closeWriteConnection() 115 119 116 if self.readBlockedOnWrite: 120 117 self.readBlockedOnWrite = 0 121 # XXX - This is touching internal guts bad bad bad 122 if not self.dataBuffer and not self._tempDataBuffer: 123 self.stopWriting() 124 return self.doRead() 118 self._resetReadWrite() 125 119 return Connection.doWrite(self) 126 120 127 121 def writeSomeData(self, data): … … 131 125 return 0 132 126 except SSL.WantReadError: 133 127 self.writeBlockedOnRead = 1 128 Connection.stopWriting(self) 129 Connection.startReading(self) 134 130 return 0 131 except SSL.ZeroReturnError: 132 return main.CONNECTION_LOST 135 133 except SSL.SysCallError, e: 136 134 if e[0] == -1 and data == "": 137 135 # errors when writing empty strings are expected … … 156 154 def _postLoseConnection(self): 157 155 """Gets called after loseConnection(), after buffered data is sent. 158 156 159 We close the SSL transport layer, and if the other side hasn't 160 closed it yet we start reading, waiting for a ZeroReturnError 161 which will indicate the SSL shutdown has completed. 157 We try to send an SSL shutdown alert, but if it doesn't work, retry 158 when the socket is writable. 162 159 """ 160 #print "_postLoseConnection", self 161 self.socket.set_shutdown(SSL.RECEIVED_SHUTDOWN) 162 return self._sendCloseAlert() 163 164 _first=False 165 def _sendCloseAlert(self): 166 # Okay, *THIS* is a bit complicated. 167 168 # Basically, the issue is, OpenSSL seems to not actually return 169 # errors from SSL_shutdown. Therefore, the only way to 170 # determine if the close notification has been sent is by 171 # SSL_shutdown returning "done". However, it will not claim it's 172 # done until it's both sent *and* received a shutdown notification. 173 174 # I don't actually want to wait for a received shutdown 175 # notification, though, so, I have to set RECEIVED_SHUTDOWN 176 # before calling shutdown. Then, it'll return True once it's 177 # *SENT* the shutdown. 178 179 # However, RECEIVED_SHUTDOWN can't be left set, because then 180 # reads will fail, breaking half close. 181 182 # Also, since shutdown doesn't report errors, an empty write call is 183 # done first, to try to detect if the connection has gone away. 184 # (*NOT* an SSL_write call, because that fails once you've called 185 # shutdown) 186 187 #print "_sendCloseAlert" 188 #import pdb; pdb.set_trace() 163 189 try: 190 os.write(self.socket.fileno(), '') 191 except OSError, se: 192 if se.args[0] in (EINTR, EWOULDBLOCK, ENOBUFS): 193 return 0 194 # Write error, socket gone 195 return main.CONNECTION_LOST 196 197 try: 198 laststate = self.socket.get_shutdown() 199 self.socket.set_shutdown(laststate | SSL.RECEIVED_SHUTDOWN) 164 200 done = self.socket.shutdown() 165 self.sslShutdown = 1 201 if not (laststate & SSL.RECEIVED_SHUTDOWN): 202 self.socket.set_shutdown(SSL.SENT_SHUTDOWN) 203 #print "SSL_SHUTDOWN:", done 166 204 except SSL.Error: 167 205 log.err() 168 206 return main.CONNECTION_LOST 207 169 208 if done: 209 self.stopWriting() 170 210 return main.CONNECTION_DONE 171 211 else: 172 # we wait for other side to close SSL connection -173 # this will be signaled by SSL.ZeroReturnError when reading174 # from the socket175 self.stopWriting()176 self.startReading()212 #print "writeBlockedOnRead:", self.writeBlockedOnRead 213 self.startWriting() 214 #import default 215 #print default.writes 216 return None 177 217 178 # don't close socket just yet 218 def _closeWriteConnection(self): 219 #print "_closeWriteConnection", self 220 result = self._sendCloseAlert() 221 222 if result is main.CONNECTION_DONE: 223 self.socket.sock_shutdown(1) 224 p = interfaces.IHalfCloseableProtocol(self.protocol, None) 225 if p: 226 p.writeConnectionLost() 179 227 return None 228 229 return result 180 230 231 def _closeReadConnection(self): 232 # Keeps further reads from being received. 233 self.socket.set_shutdown(SSL.RECEIVED_SHUTDOWN) 234 self.socket.sock_shutdown(0) 235 p = interfaces.IHalfCloseableProtocol(self.protocol, None) 236 if p: 237 p.readConnectionLost() 238 239 def startReading(self): 240 self._userWantRead = True 241 if not self.readBlockedOnWrite: 242 return Connection.startReading(self) 243 244 def stopReading(self): 245 self._userWantRead = False 246 if not self.writeBlockedOnRead: 247 return Connection.stopReading(self) 248 249 def startWriting(self): 250 self._userWantWrite = True 251 if not self.writeBlockedOnRead: 252 return Connection.startWriting(self) 253 254 def stopWriting(self): 255 self._userWantWrite = False 256 if not self.readBlockedOnWrite: 257 #print "stopWriting" 258 return Connection.stopWriting(self) 259 260 def _resetReadWrite(self): 261 # After changing readBlockedOnWrite or writeBlockedOnRead, 262 # call this to reset the state to what the user requested. 263 if self._userWantWrite: 264 self.startWriting() 265 else: 266 self.stopWriting() 267 268 if self._userWantRead: 269 self.startReading() 270 else: 271 self.stopReading() 272 181 273 class Connection(abstract.FileDescriptor): 182 274 """I am the superclass of all socket-based FileDescriptors. 183 275 … … 248 340 return 249 341 else: 250 342 return main.CONNECTION_LOST 251 except SSL.SysCallError, (retval, desc):252 # Yes, SSL might be None, but self.socket.recv() can *only*253 # raise socket.error, if anything else is raised, it must be an254 # SSL socket, and so SSL can't be None. (That's my story, I'm255 # stickin' to it)256 if retval == -1 and desc == 'Unexpected EOF':257 return main.CONNECTION_DONE258 raise259 343 if not data: 260 344 return main.CONNECTION_DONE 261 345 return self.protocol.dataReceived(data)
