Ejemplo n.º 1
0
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()
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
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()
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
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"))
Ejemplo n.º 8
0
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"))
Ejemplo n.º 9
0
    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
Ejemplo n.º 10
0
    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
Ejemplo n.º 11
0
    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
Ejemplo n.º 12
0
    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