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
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)
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 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."
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()
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()
def translate_timeout_errors(): try: yield except asyncio.TimeoutError: raise ReqlTimeoutError()
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 raise_timeout(errback): if isinstance(errback.value, CancelledError): raise ReqlTimeoutError() else: raise errback.value
def wait_canceller(d): d.errback(ReqlTimeoutError())
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)))