Esempio n. 1
0
    def recvall(self, length, deadline):
        res = b"" if self._read_buffer is None else self._read_buffer
        timeout = None if deadline is None else max(0, deadline - time.time())
        self._socket.settimeout(timeout)
        while len(res) < length:
            while True:
                try:
                    chunk = self._socket.recv(length - len(res))
                    self._socket.settimeout(None)
                    break
                except socket.timeout:
                    self._read_buffer = res
                    self._socket.settimeout(None)
                    raise ReqlTimeoutError(self.host, self.port)
                except IOError as ex:
                    if ex.errno == errno.ECONNRESET:
                        self.close()
                        raise ReqlDriverError("Connection is closed.")
                    elif ex.errno == errno.EWOULDBLOCK:
                        # This should only happen with a timeout of 0
                        raise ReqlTimeoutError(self.host, self.port)
                    elif ex.errno != errno.EINTR:
                        raise ReqlDriverError(("Connection interrupted " +
                                               "receiving from %s:%s - %s") %
                                              (self.host, self.port, str(ex)))
                except Exception as ex:
                    self.close()
                    raise ReqlDriverError("Error receiving from %s:%s - %s" %
                                          (self.host, self.port, str(ex)))

            if len(chunk) == 0:
                self.close()
                raise ReqlDriverError("Connection is closed.")
            res += chunk
        return res
Esempio n. 2
0
 async def connect(self):
     # ssl_context = ssl.create_default_context()
     # ssl_context.verify_mode = ssl.CERT_REQUIRED
     # ssl_context.check_hostname = True  # redundant with match_hostname
     # self._socket = await open_connection(self.host, self.port, ssl=ssl)
     self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     await self._socket.connect((self.host, self.port))
     self._socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
     self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
     try:
         self._handshake.reset()
         response = None
         while True:
             request = self._handshake.next_message(response)
             if request is None:
                 break
             # This may happen in the `V1_0` protocol where we send two requests as
             # an optimization, then need to read each separately
             if request:
                 await self.sendall(request)
             # The response from the server is a null-terminated string
             response = (await self.read_until(b'\0'))[:-1]
     except (ReqlAuthError, ReqlTimeoutError):
         await self.close()
         raise
     except ReqlDriverError as ex:
         await self.close()
         error = str(ex)\
             .replace('receiving from', 'during handshake with')\
             .replace('sending to', 'during handshake with')
         raise ReqlDriverError(error)
     except socket.timeout as ex:
         await self.close()
         raise ReqlTimeoutError(self.host, self.port)
Esempio n. 3
0
 def _handleHandshakeTimeout(self):
     # If we are here, we failed to do the handshake before the timeout.
     # We close the connection and raise an ReqlTimeoutError in the
     # wait_for_handshake deferred.
     self._open = False
     self.transport.loseConnection()
     self.wait_for_handshake.errback(ReqlTimeoutError())
Esempio n. 4
0
    def connect(self, timeout):
        factory = DatabaseProtoFactory(timeout, self._handleResponse,
                                       self._parent.handshake)

        # We connect to the server, and send the handshake payload.
        pConnection = None
        try:
            pConnection = yield self._connectTimeout(factory, timeout)
        except Exception as e:
            raise ReqlDriverError(
                'Could not connect to {p.host}:{p.port}. Error: {exc}'.format(
                    p=self._parent, exc=str(e)))

        # Now, we need to wait for the handshake.
        try:
            yield pConnection.wait_for_handshake
        except ReqlAuthError as e:
            raise
        except ReqlTimeoutError as e:
            raise ReqlTimeoutError(self._parent.host, self._parent.port)
        except Exception as e:
            raise ReqlDriverError(
                'Connection interrupted during handshake with {p.host}:{p.port}. Error: {exc}'
                .format(p=self._parent, exc=str(e)))

        self._connection = pConnection

        returnValue(self._parent)
Esempio n. 5
0
def with_absolute_timeout(deadline, generator, **kwargs):
    if deadline is None:
        res = yield generator
    else:
        try:
            res = yield gen.with_timeout(deadline, generator, **kwargs)
        except gen.TimeoutError:
            raise ReqlTimeoutError()
    raise gen.Return(res)
def test_timeout_error_only_port():
    """
    Test timeout error raises error if only port is given.
    """

    with pytest.raises(ValueError) as exc:
        raise ReqlTimeoutError(port=1234)

    assert str(exc.value) == "If port is set, you must set host as well"
def test_timeout_error_only_host():
    """
    Test timeout error raises error if only host is given.
    """

    with pytest.raises(ValueError) as exc:
        raise ReqlTimeoutError(host="localhost")

    assert str(exc.value) == "If host is set, you must set port as well"
def test_timeout_error():
    """
    Test timeout error raised as expected without using host or port.
    """

    with pytest.raises(ReqlTimeoutError) as exc:
        raise ReqlTimeoutError()

    assert str(exc.value) == "Operation timed out."
def test_timeout_error_connection_error():
    """
    Test timeout error shows connection error if host and port are set.
    """

    host = "localhost"
    port = 1234

    with pytest.raises(ReqlTimeoutError) as exc:
        raise ReqlTimeoutError(host, port)

    assert str(exc.value
               ) == f"Could not connect to {host}:{port}, Operation timed out."
Esempio n. 10
0
    def _connectTimeout(self, factory, timeout):
        try:
            # TODO: use ssl options
            # TODO: this doesn't work for literal IPv6 addresses like '::1'
            args = "tcp:%s:%d" % (self._parent.host, self._parent.port)

            if timeout is not None:
                args = args + (":timeout=%d" % timeout)

            endpoint = clientFromString(reactor, args)
            p = yield endpoint.connect(factory)
            returnValue(p)
        except TimeoutError:
            raise ReqlTimeoutError()
Esempio n. 11
0
def _reql_timeout(seconds):
    '''
    Run a block with a timeout, raising `ReqlTimeoutError` if the block
    execution exceeds the timeout.

    :param float seconds: A timeout in seconds. If None, then no timeout is
        enforced.
    :raises ReqlTimeoutError: If execution time exceeds the timeout.
    '''
    if seconds is None:
        yield
    else:
        try:
            with trio.fail_after(seconds):
                yield
        except trio.TooSlow:
            raise ReqlTimeoutError()
Esempio n. 12
0
def translate_timeout_errors():
    try:
        yield
    except asyncio.TimeoutError:
        raise ReqlTimeoutError()
Esempio n. 13
0
    def connect(self, timeout):
        deadline = None if timeout is None else self._io_loop.time() + timeout

        try:
            if len(self._parent.ssl) > 0:
                ssl_options = {}
                if self._parent.ssl["ca_certs"]:
                    ssl_options['ca_certs'] = self._parent.ssl["ca_certs"]
                    ssl_options['cert_reqs'] = 2  # ssl.CERT_REQUIRED
                stream_future = TCPClient().connect(self._parent.host,
                                                    self._parent.port,
                                                    ssl_options=ssl_options)
            else:
                stream_future = TCPClient().connect(self._parent.host,
                                                    self._parent.port)

            self._stream = yield with_absolute_timeout(
                deadline,
                stream_future,
                io_loop=self._io_loop,
                quiet_exceptions=(iostream.StreamClosedError))
        except Exception as err:
            raise ReqlDriverError(
                'Could not connect to %s:%s. Error: %s' %
                (self._parent.host, self._parent.port, str(err)))

        self._stream.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY,
                                       1)
        self._stream.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE,
                                       1)

        try:
            self._parent.handshake.reset()
            response = None
            while True:
                request = self._parent.handshake.next_message(response)
                if request is None:
                    break
                # This may happen in the `V1_0` protocol where we send two requests as
                # an optimization, then need to read each separately
                if request is not "":
                    self._stream.write(request)

                response = yield with_absolute_timeout(
                    deadline,
                    self._stream.read_until(b'\0'),
                    io_loop=self._io_loop,
                    quiet_exceptions=(iostream.StreamClosedError))
                response = response[:-1]
        except ReqlAuthError:
            try:
                self._stream.close()
            except iostream.StreamClosedError:
                pass
            raise
        except ReqlTimeoutError:
            try:
                self._stream.close()
            except iostream.StreamClosedError:
                pass
            raise ReqlTimeoutError(self._parent.host, self._parent.port)
        except Exception as err:
            try:
                self._stream.close()
            except iostream.StreamClosedError:
                pass
            raise ReqlDriverError(
                'Connection interrupted during handshake with %s:%s. Error: %s'
                % (self._parent.host, self._parent.port, str(err)))

        # Start a parallel function to perform reads
        self._io_loop.add_callback(self._reader)
        raise gen.Return(self._parent)
Esempio n. 14
0
 def raise_timeout(errback):
     if isinstance(errback.value, CancelledError):
         raise ReqlTimeoutError()
     else:
         raise errback.value
Esempio n. 15
0
 def wait_canceller(d):
     d.errback(ReqlTimeoutError())
Esempio n. 16
0
    def __init__(self, parent, timeout):
        self.host = parent._parent.host
        self.port = parent._parent.port
        self._read_buffer = None
        self._socket = None
        self.ssl = parent._parent.ssl

        deadline = time.time() + timeout

        try:
            self._socket = socket.create_connection((self.host, self.port),
                                                    timeout)
            self._socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
            self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)

            if len(self.ssl) > 0:
                try:
                    if hasattr(ssl, "SSLContext"
                               ):  # Python2.7 and 3.2+, or backports.ssl
                        ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
                        if hasattr(ssl_context, "options"):
                            ssl_context.options |= getattr(
                                ssl, "OP_NO_SSLv2", 0)
                            ssl_context.options |= getattr(
                                ssl, "OP_NO_SSLv3", 0)
                        ssl_context.verify_mode = ssl.CERT_REQUIRED
                        ssl_context.check_hostname = (
                            True  # redundant with match_hostname
                        )
                        ssl_context.load_verify_locations(self.ssl["ca_certs"])
                        self._socket = ssl_context.wrap_socket(
                            self._socket, server_hostname=self.host)
                    else:  # this does not disable SSLv2 or SSLv3
                        self._socket = ssl.wrap_socket(
                            self._socket,
                            cert_reqs=ssl.CERT_REQUIRED,
                            ssl_version=ssl.PROTOCOL_SSLv23,
                            ca_certs=self.ssl["ca_certs"],
                        )
                except IOError as err:
                    self._socket.close()

                    if "EOF occurred in violation of protocol" in str(
                            err) or "sslv3 alert handshake failure" in str(
                                err):
                        # probably on an older version of OpenSSL
                        raise ReqlDriverError(
                            "SSL handshake failed, likely because Python is linked against an old version of OpenSSL "
                            "that does not support either TLSv1.2 or any of the allowed ciphers. This can be worked "
                            "around by lowering the security setting on the server with the options "
                            "`--tls-min-protocol TLSv1 --tls-ciphers "
                            "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:AES256-SHA` (see server log for more "
                            "information): %s" % str(err))
                    else:
                        raise ReqlDriverError(
                            "SSL handshake failed (see server log for more information): %s"
                            % str(err))
                try:
                    match_hostname(self._socket.getpeercert(),
                                   hostname=self.host)
                except CertificateError:
                    self._socket.close()
                    raise

            parent._parent.handshake.reset()
            response = None
            while True:
                request = parent._parent.handshake.next_message(response)
                if request is None:
                    break
                # This may happen in the `V1_0` protocol where we send two requests as
                # an optimization, then need to read each separately
                if request is not "":
                    self.sendall(request)

                # The response from the server is a null-terminated string
                response = b""
                while True:
                    char = self.recvall(1, deadline)
                    if char == b"\0":
                        break
                    response += char
        except (ReqlAuthError, ReqlTimeoutError):
            self.close()
            raise
        except ReqlDriverError as ex:
            self.close()
            error = (str(ex).replace("receiving from",
                                     "during handshake with").replace(
                                         "sending to",
                                         "during handshake with"))
            raise ReqlDriverError(error)
        except socket.timeout as ex:
            self.close()
            raise ReqlTimeoutError(self.host, self.port)
        except Exception as ex:
            self.close()
            raise ReqlDriverError("Could not connect to %s:%s. Error: %s" %
                                  (self.host, self.port, str(ex)))