Skip to content

Commit f6b0254

Browse files
authored
Don't try to close already broken connection during HELLO (#516)
* Don't try to close already broken connection during HELLO. * Refactor closing of sockets into separate function. This allows to categorically ignore failures when closing a socket.
1 parent c5e09fc commit f6b0254

File tree

1 file changed

+17
-13
lines changed

1 file changed

+17
-13
lines changed

neo4j/io/__init__.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -198,12 +198,10 @@ def ping(cls, address, *, timeout=None, **config):
198198
ssl_context=config.get_ssl_context(),
199199
keep_alive=config.keep_alive,
200200
)
201-
except ServiceUnavailable:
202-
return None
203-
except BoltHandshakeError as e:
201+
except (ServiceUnavailable, SessionExpired, BoltHandshakeError):
204202
return None
205203
else:
206-
s.close()
204+
_close_socket(s)
207205
return protocol_version
208206

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

256253
supported_versions = Bolt.protocol_handlers().keys()
257254
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)
@@ -260,8 +257,7 @@ def open(cls, address, *, auth=None, timeout=None, routing_context=None, **pool_
260257
connection.hello()
261258
except Exception as error:
262259
log.debug("[#%04X] C: <CLOSE> %s", s.getsockname()[1], str(error))
263-
s.shutdown(SHUT_RDWR)
264-
s.close()
260+
_close_socket(s)
265261
raise error
266262

267263
return connection
@@ -955,7 +951,7 @@ def _connect(resolved_address, timeout, keep_alive):
955951
except SocketTimeout:
956952
log.debug("[#0000] C: <TIMEOUT> %s", resolved_address)
957953
log.debug("[#0000] C: <CLOSE> %s", resolved_address)
958-
s.close()
954+
_close_socket(s)
959955
raise ServiceUnavailable("Timed out trying to establish connection to {!r}".format(resolved_address))
960956
except OSError as error:
961957
log.debug("[#0000] C: <ERROR> %s %s", type(error).__name__,
@@ -976,7 +972,7 @@ def _secure(s, host, ssl_context):
976972
sni_host = host if HAS_SNI and host else None
977973
s = ssl_context.wrap_socket(s, server_hostname=sni_host)
978974
except (SSLError, OSError) as cause:
979-
s.close()
975+
_close_socket(s)
980976
error = BoltSecurityError(message="Failed to establish encrypted connection.", address=(host, local_port))
981977
error.__cause__ = cause
982978
raise error
@@ -1027,7 +1023,7 @@ def _handshake(s, resolved_address):
10271023
# If no data is returned after a successful select
10281024
# response, the server has closed the connection
10291025
log.debug("[#%04X] S: <CLOSE>", local_port)
1030-
s.close()
1026+
_close_socket(s)
10311027
raise ServiceUnavailable("Connection to {address} closed without handshake response".format(address=resolved_address))
10321028
if data_size != 4:
10331029
# Some garbled data has been received
@@ -1036,14 +1032,22 @@ def _handshake(s, resolved_address):
10361032
raise BoltProtocolError("Expected four byte Bolt handshake response from %r, received %r instead; check for incorrect port number" % (resolved_address, data), address=resolved_address)
10371033
elif data == b"HTTP":
10381034
log.debug("[#%04X] S: <CLOSE>", local_port)
1039-
s.close()
1035+
_close_socket(s)
10401036
raise ServiceUnavailable("Cannot to connect to Bolt service on {!r} "
10411037
"(looks like HTTP)".format(resolved_address))
10421038
agreed_version = data[-1], data[-2]
10431039
log.debug("[#%04X] S: <HANDSHAKE> 0x%06X%02X", local_port, agreed_version[1], agreed_version[0])
10441040
return s, agreed_version, handshake, data
10451041

10461042

1043+
def _close_socket(socket_):
1044+
try:
1045+
socket_.shutdown(SHUT_RDWR)
1046+
socket_.close()
1047+
except OSError:
1048+
pass
1049+
1050+
10471051
def connect(address, *, timeout, custom_resolver, ssl_context, keep_alive):
10481052
""" Connect and perform a handshake and return a valid Connection object,
10491053
assuming a protocol version can be agreed.
@@ -1063,7 +1067,7 @@ def connect(address, *, timeout, custom_resolver, ssl_context, keep_alive):
10631067
return _handshake(s, address)
10641068
except Exception as error:
10651069
if s:
1066-
s.close()
1070+
_close_socket(s)
10671071
last_error = error
10681072
if last_error is None:
10691073
raise ServiceUnavailable("Failed to resolve addresses for %s" % address)

0 commit comments

Comments
 (0)