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())
    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)
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 _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()
Exemple #5
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:
                        self.close()
                        # 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
    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)
def translate_timeout_errors():
    try:
        yield
    except asyncio.TimeoutError:
        raise ReqlTimeoutError()
Exemple #8
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)))
 def raise_timeout(errback):
     if isinstance(errback.value, CancelledError):
         raise ReqlTimeoutError()
     else:
         raise errback.value
 def wait_canceller(d):
     d.errback(ReqlTimeoutError())