class SslHandshakingTransport(BaseSocketTransport): __slots__ = ["connected_dfr"] def __init__(self, reactor, sslsock): BaseSocketTransport.__init__(self, reactor, sslsock) self.connected_dfr = ReactorDeferred(self.reactor) def handshake(self): if not self.connected_dfr.is_set(): self._handshake() return self.connected_dfr def _handshake(self): try: self.sock.do_handshake() except ssl.SSLError as ex: if ex.errno == ssl.SSL_ERROR_WANT_READ: self.reactor.register_read(self) elif ex.errno == ssl.SSL_ERROR_WANT_WRITE: self.reactor.register_write(self) else: self.connected_dfr.throw(ex) else: sock = self.sock self.detach() trns = SslStreamTransport(self.reactor, sock) self.connected_dfr.set(trns) def on_read(self): self.reactor.unregister_read(self) self._handshake() def on_write(self): self.reactor.unregister_write(self) self._handshake()
def recvfrom(self, count = -1): if count < 0 or count > self.MAX_DATAGRAM_SIZE: count = self.MAX_DATAGRAM_SIZE if self._ongoing_read: raise OverlappingRequestError("overlapping recvfrom") self._ongoing_read = True def read_finished(size, exc): self._ongoing_read = False if exc: dfr.throw(exc) else: data = buf[:size] addrinfo = (sockaddr.addr_str, sockaddr.port) dfr.set((data, addrinfo)) dfr = ReactorDeferred(self.reactor) overlapped = self.reactor._get_overlapped(read_finished) try: buf, sockaddr, _ = winsock.WSARecvFromSocket(self.sock, count, overlapped) except Exception as ex: self._ongoing_read = False self.reactor._discard_overlapped(overlapped) dfr.throw(ex) return dfr
def recvfrom(self, count=-1): if count < 0 or count > self.MAX_DATAGRAM_SIZE: count = self.MAX_DATAGRAM_SIZE if self._ongoing_read: raise OverlappingRequestError("overlapping recvfrom") self._ongoing_read = True def read_finished(size, exc): self._ongoing_read = False if exc: dfr.throw(exc) else: data = buf[:size] addrinfo = (sockaddr.addr_str, sockaddr.port) dfr.set((data, addrinfo)) dfr = ReactorDeferred(self.reactor) overlapped = self.reactor._get_overlapped(read_finished) try: buf, sockaddr, _ = winsock.WSARecvFromSocket( self.sock, count, overlapped) except Exception as ex: self._ongoing_read = False self.reactor._discard_overlapped(overlapped) dfr.throw(ex) return dfr
def read(self, count): # XXX: # The ReadFile function may fail with ERROR_INVALID_USER_BUFFER or # ERROR_NOT_ENOUGH_MEMORY whenever there are too many outstanding # asynchronous I/O requests. # # XXX: # http://support.microsoft.com/kb/156932 -- ReadFile may return # immediately, need to check that condition if self._ongoing_read: raise OverlappingRequestError("overlapping reads") self._ongoing_read = True def read_finished(size, exc): if size == 0: data = None # EOF else: data = bytes(buf[:size]) self._ongoing_read = False if exc: dfr.throw(exc) else: dfr.set(data) dfr = ReactorDeferred(self.reactor) count = min(count, self.MAX_READ_SIZE) if count <= 0: self._ongoing_read = False dfr.set("") return dfr overlapped = self._get_read_overlapped(read_finished) try: buf = win32file.AllocateReadBuffer(count) win32file.ReadFile(self.fileno(), buf, overlapped) except Exception as ex: self.reactor._discard_overlapped(overlapped) self._ongoing_read = False if isinstance(ex, pywintypes.error ) and ex.winerror in win32iocp.IGNORED_ERRORS: # why can't windows be just a little consistent?! # why can't a set of APIs share the same semantics for all kinds # of handles? grrrrr dfr.set(None) else: dfr.throw(ex) return dfr
def read(self, count): # XXX: # The ReadFile function may fail with ERROR_INVALID_USER_BUFFER or # ERROR_NOT_ENOUGH_MEMORY whenever there are too many outstanding # asynchronous I/O requests. # # XXX: # http://support.microsoft.com/kb/156932 -- ReadFile may return # immediately, need to check that condition if self._ongoing_read: raise OverlappingRequestError("overlapping reads") self._ongoing_read = True def read_finished(size, exc): if size == 0: data = None # EOF else: data = bytes(buf[:size]) self._ongoing_read = False if exc: dfr.throw(exc) else: dfr.set(data) dfr = ReactorDeferred(self.reactor) count = min(count, self.MAX_READ_SIZE) if count <= 0: self._ongoing_read = False dfr.set("") return dfr overlapped = self._get_read_overlapped(read_finished) try: buf = win32file.AllocateReadBuffer(count) win32file.ReadFile(self.fileno(), buf, overlapped) except Exception as ex: self.reactor._discard_overlapped(overlapped) self._ongoing_read = False if isinstance(ex, pywintypes.error) and ex.winerror in win32iocp.IGNORED_ERRORS: # why can't windows be just a little consistent?! # why can't a set of APIs share the same semantics for all kinds # of handles? grrrrr dfr.set(None) else: dfr.throw(ex) return dfr
class ConnectingSocketTransport(BaseSocketTransport): __slots__ = ["addr", "connected_dfr", "_connecting"] def __init__(self, reactor, sock, addr): BaseSocketTransport.__init__(self, reactor, sock) self.addr = addr self.connected_dfr = ReactorDeferred(self.reactor) self._connecting = False def connect(self, timeout=None): if self._connecting: raise OverlappingRequestError("already connecting") self._connecting = True if timeout is not None: self.reactor.jobs.schedule(timeout, self._cancel) self.reactor.register_write(self) self._attempt_connect() return self.connected_dfr def on_write(self): self._attempt_connect() def _attempt_connect(self): if self.connected_dfr.is_set(): self.detach() return err = self.sock.connect_ex(self.addr) if err in (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK): return if err == errno.EINVAL and sys.platform == "win32": return sock = self.sock self.detach() if err in (0, errno.EISCONN): self.connected_dfr.set(SocketStreamTransport(self.reactor, sock)) else: self.connected_dfr.throw(socket.error(err, errno.errorcode[err])) def _cancel(self): if self.connected_dfr.is_set(): return self.close() self.connected_dfr.throw(socket.timeout("connection timed out"))
class ConnectingSocketTransport(BaseSocketTransport): __slots__ = ["addr", "connected_dfr", "_connecting"] def __init__(self, reactor, sock, addr): BaseSocketTransport.__init__(self, reactor, sock) self.addr = addr self.connected_dfr = ReactorDeferred(self.reactor) self._connecting = False def connect(self, timeout = None): if self._connecting: raise OverlappingRequestError("already connecting") self._connecting = True if timeout is not None: self.reactor.jobs.schedule(timeout, self._cancel) self.reactor.register_write(self) self._attempt_connect() return self.connected_dfr def on_write(self): self._attempt_connect() def _attempt_connect(self): if self.connected_dfr.is_set(): self.detach() return err = self.sock.connect_ex(self.addr) if err in (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK): return if err == errno.EINVAL and sys.platform == "win32": return sock = self.sock self.detach() if err in (0, errno.EISCONN): self.connected_dfr.set(SocketStreamTransport(self.reactor, sock)) else: self.connected_dfr.throw(socket.error(err, errno.errorcode[err])) def _cancel(self): if self.connected_dfr.is_set(): return self.close() self.connected_dfr.throw(socket.timeout("connection timed out"))
def accept(self): def accept_finished(size, exc): if exc: self.reactor.call(trns.close) dfr.throw(exc) else: dfr.set(trns) dfr = ReactorDeferred(self.reactor) overlapped = self.reactor._get_overlapped(accept_finished) try: sock = socket.socket(self.sock.family, self.sock.type) # this is needed here to register the new socket with its IOCP trns = self.factory(self.reactor, sock) fd = sock.fileno() buffer = win32file.AllocateReadBuffer(win32file.CalculateSocketEndPointSize(fd)) win32file.AcceptEx(self.fileno(), fd, buffer, overlapped) except Exception as ex: self.reactor._discard_overlapped(overlapped) dfr.throw(ex) return dfr
def accept(self): def accept_finished(size, exc): if exc: self.reactor.call(trns.close) dfr.throw(exc) else: dfr.set(trns) dfr = ReactorDeferred(self.reactor) overlapped = self.reactor._get_overlapped(accept_finished) try: sock = socket.socket(self.sock.family, self.sock.type) # this is needed here to register the new socket with its IOCP trns = self.factory(self.reactor, sock) fd = sock.fileno() buffer = win32file.AllocateReadBuffer( win32file.CalculateSocketEndPointSize(fd)) win32file.AcceptEx(self.fileno(), fd, buffer, overlapped) except Exception as ex: self.reactor._discard_overlapped(overlapped) dfr.throw(ex) return dfr
def sendto(self, addr, data): if len(data) > self.MAX_DATAGRAM_SIZE: raise TransportError("data too long") if self._ongoing_write: raise OverlappingRequestError("overlapping sendto") self._ongoing_write = True def write_finished(size, exc): self._ongoing_write = False if exc: dfr.throw(exc) else: dfr.set(size) # return actual sent size dfr = ReactorDeferred(self.reactor) overlapped = self.reactor._get_overlapped(write_finished) try: winsock.WSASendToSocket(self.sock, data, addr, overlapped) except Exception as ex: self._ongoing_read = False self.reactor._discard_overlapped(overlapped) dfr.throw(ex) return dfr