def process_next_packet(self, timeout=0): """Process the next datagram, waiting for it if necessary. @type timeout: float @param timeout: how long to wait for data @rtype: boolean @return: True if some data has been handled, False otherwise """ result = utils.WaitForFdCondition(self.socket, select.POLLIN, timeout) if result is not None and result & select.POLLIN: self.handle_read() return True else: return False
def SocketOperation(sock, op, arg1, timeout): """Wrapper around socket functions. This function abstracts error handling for socket operations, especially for the complicated interaction with OpenSSL. @type sock: socket @param sock: Socket for the operation @type op: int @param op: Operation to execute (SOCKOP_* constants) @type arg1: any @param arg1: Parameter for function (if needed) @type timeout: None or float @param timeout: Timeout in seconds or None @return: Return value of socket function """ # TODO: event_poll/event_check/override if op in (SOCKOP_SEND, SOCKOP_HANDSHAKE): event_poll = select.POLLOUT elif op == SOCKOP_RECV: event_poll = select.POLLIN elif op == SOCKOP_SHUTDOWN: event_poll = None # The timeout is only used when OpenSSL requests polling for a condition. # It is not advisable to have no timeout for shutdown. assert timeout else: raise AssertionError("Invalid socket operation") # Handshake is only supported by SSL sockets if (op == SOCKOP_HANDSHAKE and not isinstance(sock, OpenSSL.SSL.ConnectionType)): return # No override by default event_override = 0 while True: # Poll only for certain operations and when asked for by an override if event_override or op in (SOCKOP_SEND, SOCKOP_RECV, SOCKOP_HANDSHAKE): if event_override: wait_for_event = event_override else: wait_for_event = event_poll event = utils.WaitForFdCondition(sock, wait_for_event, timeout) if event is None: raise HttpSocketTimeout() if event & (select.POLLNVAL | select.POLLHUP | select.POLLERR): # Let the socket functions handle these break if not event & wait_for_event: continue # Reset override event_override = 0 try: try: if op == SOCKOP_SEND: return sock.send(arg1) elif op == SOCKOP_RECV: return sock.recv(arg1) elif op == SOCKOP_SHUTDOWN: if isinstance(sock, OpenSSL.SSL.ConnectionType): # PyOpenSSL's shutdown() doesn't take arguments return sock.shutdown() else: return sock.shutdown(arg1) elif op == SOCKOP_HANDSHAKE: return sock.do_handshake() except OpenSSL.SSL.WantWriteError: # OpenSSL wants to write, poll for POLLOUT event_override = select.POLLOUT continue except OpenSSL.SSL.WantReadError: # OpenSSL wants to read, poll for POLLIN event_override = select.POLLIN | select.POLLPRI continue except OpenSSL.SSL.WantX509LookupError: continue except OpenSSL.SSL.ZeroReturnError, err: # SSL Connection has been closed. In SSL 3.0 and TLS 1.0, this only # occurs if a closure alert has occurred in the protocol, i.e. the # connection has been closed cleanly. Note that this does not # necessarily mean that the transport layer (e.g. a socket) has been # closed. if op == SOCKOP_SEND: # Can happen during a renegotiation raise HttpConnectionClosed(err.args) elif op == SOCKOP_RECV: return "" # SSL_shutdown shouldn't return SSL_ERROR_ZERO_RETURN raise socket.error(err.args) except OpenSSL.SSL.SysCallError, err: if op == SOCKOP_SEND: # arg1 is the data when writing if err.args and err.args[0] == -1 and arg1 == "": # errors when writing empty strings are expected # and can be ignored return 0 if err.args == (-1, _SSL_UNEXPECTED_EOF): if op == SOCKOP_RECV: return "" elif op == SOCKOP_HANDSHAKE: # Can happen if peer disconnects directly after the connection is # opened. raise HttpSessionHandshakeUnexpectedEOF(err.args) raise socket.error(err.args) except OpenSSL.SSL.Error, err: raise socket.error(err.args)