Skip to content

Don't try to close already broken connection during HELLO #516

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 6, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions neo4j/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,10 @@ def ping(cls, address, *, timeout=None, **config):
ssl_context=config.get_ssl_context(),
keep_alive=config.keep_alive,
)
except ServiceUnavailable:
return None
except BoltHandshakeError as e:
except (ServiceUnavailable, SessionExpired, BoltHandshakeError):
return None
else:
s.close()
_close_socket(s)
return protocol_version

@classmethod
Expand Down Expand Up @@ -250,8 +248,7 @@ def open(cls, address, *, auth=None, timeout=None, routing_context=None, **pool_
connection = Bolt4x3(address, s, pool_config.max_connection_lifetime, auth=auth, user_agent=pool_config.user_agent, routing_context=routing_context)
else:
log.debug("[#%04X] S: <CLOSE>", s.getpeername()[1])
s.shutdown(SHUT_RDWR)
s.close()
_close_socket(s)

supported_versions = Bolt.protocol_handlers().keys()
raise BoltHandshakeError("The Neo4J server does not support communication with this driver. This driver have support for Bolt Protocols {}".format(supported_versions), address=address, request_data=handshake, response_data=data)
Expand All @@ -260,8 +257,7 @@ def open(cls, address, *, auth=None, timeout=None, routing_context=None, **pool_
connection.hello()
except Exception as error:
log.debug("[#%04X] C: <CLOSE> %s", s.getsockname()[1], str(error))
s.shutdown(SHUT_RDWR)
s.close()
_close_socket(s)
raise error

return connection
Expand Down Expand Up @@ -955,7 +951,7 @@ def _connect(resolved_address, timeout, keep_alive):
except SocketTimeout:
log.debug("[#0000] C: <TIMEOUT> %s", resolved_address)
log.debug("[#0000] C: <CLOSE> %s", resolved_address)
s.close()
_close_socket(s)
raise ServiceUnavailable("Timed out trying to establish connection to {!r}".format(resolved_address))
except OSError as error:
log.debug("[#0000] C: <ERROR> %s %s", type(error).__name__,
Expand All @@ -976,7 +972,7 @@ def _secure(s, host, ssl_context):
sni_host = host if HAS_SNI and host else None
s = ssl_context.wrap_socket(s, server_hostname=sni_host)
except (SSLError, OSError) as cause:
s.close()
_close_socket(s)
error = BoltSecurityError(message="Failed to establish encrypted connection.", address=(host, local_port))
error.__cause__ = cause
raise error
Expand Down Expand Up @@ -1027,7 +1023,7 @@ def _handshake(s, resolved_address):
# If no data is returned after a successful select
# response, the server has closed the connection
log.debug("[#%04X] S: <CLOSE>", local_port)
s.close()
_close_socket(s)
raise ServiceUnavailable("Connection to {address} closed without handshake response".format(address=resolved_address))
if data_size != 4:
# Some garbled data has been received
Expand All @@ -1036,14 +1032,22 @@ def _handshake(s, resolved_address):
raise BoltProtocolError("Expected four byte Bolt handshake response from %r, received %r instead; check for incorrect port number" % (resolved_address, data), address=resolved_address)
elif data == b"HTTP":
log.debug("[#%04X] S: <CLOSE>", local_port)
s.close()
_close_socket(s)
raise ServiceUnavailable("Cannot to connect to Bolt service on {!r} "
"(looks like HTTP)".format(resolved_address))
agreed_version = data[-1], data[-2]
log.debug("[#%04X] S: <HANDSHAKE> 0x%06X%02X", local_port, agreed_version[1], agreed_version[0])
return s, agreed_version, handshake, data


def _close_socket(socket_):
try:
socket_.shutdown(SHUT_RDWR)
socket_.close()
except OSError:
pass


def connect(address, *, timeout, custom_resolver, ssl_context, keep_alive):
""" Connect and perform a handshake and return a valid Connection object,
assuming a protocol version can be agreed.
Expand All @@ -1063,7 +1067,7 @@ def connect(address, *, timeout, custom_resolver, ssl_context, keep_alive):
return _handshake(s, address)
except Exception as error:
if s:
s.close()
_close_socket(s)
last_error = error
if last_error is None:
raise ServiceUnavailable("Failed to resolve addresses for %s" % address)
Expand Down