Skip to content

Commit c468106

Browse files
authored
Fix closure of sockets after failed connection (#795)
* Fix closure of sockets after failed connection * Fix missing await and logging after socket broke
1 parent 8cbcd83 commit c468106

File tree

3 files changed

+33
-22
lines changed

3 files changed

+33
-22
lines changed

neo4j/_async/io/_bolt.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ def time_remaining():
352352
bolt_cls = AsyncBolt5x0
353353
else:
354354
log.debug("[#%04X] S: <CLOSE>", s.getsockname()[1])
355-
AsyncBoltSocket.close_socket(s)
355+
await AsyncBoltSocket.close_socket(s)
356356

357357
supported_versions = cls.protocol_handlers().keys()
358358
raise BoltHandshakeError(
@@ -374,7 +374,7 @@ def time_remaining():
374374
finally:
375375
connection.socket.set_deadline(None)
376376
except Exception as e:
377-
log.debug("[#%04X] C: <OPEN FAILED> %r", s.getsockname()[1], e)
377+
log.debug("[#%04X] C: <OPEN FAILED> %r", connection.local_port, e)
378378
connection.kill()
379379
raise
380380

neo4j/_async_compat/network/_bolt_socket.py

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,8 @@ async def _connect_secure(cls, resolved_address, timeout, keep_alive, ssl):
253253
raise
254254
except (SSLError, CertificateError) as error:
255255
local_port = s.getsockname()[1]
256+
if s:
257+
await cls.close_socket(s)
256258
raise BoltSecurityError(
257259
message="Failed to establish encrypted connection.",
258260
address=(resolved_address.host_name, local_port)
@@ -261,7 +263,8 @@ async def _connect_secure(cls, resolved_address, timeout, keep_alive, ssl):
261263
log.debug("[#0000] C: <ERROR> %s %s", type(error).__name__,
262264
" ".join(map(repr, error.args)))
263265
log.debug("[#0000] C: <CLOSE> %s", resolved_address)
264-
s.close()
266+
if s:
267+
await cls.close_socket(s)
265268
raise ServiceUnavailable(
266269
"Failed to establish connection to {!r} (reason {})".format(
267270
resolved_address, error))
@@ -334,14 +337,20 @@ async def _handshake(self, resolved_address):
334337

335338
@classmethod
336339
async def close_socket(cls, socket_):
337-
try:
338-
if isinstance(socket_, AsyncBoltSocket):
340+
if isinstance(socket_, AsyncBoltSocket):
341+
try:
339342
await socket_.close()
340-
else:
343+
except OSError:
344+
pass
345+
else:
346+
try:
341347
socket_.shutdown(SHUT_RDWR)
348+
except OSError:
349+
pass
350+
try:
342351
socket_.close()
343-
except OSError:
344-
pass
352+
except OSError:
353+
pass
345354

346355
@classmethod
347356
async def connect(cls, address, *, timeout, custom_resolver, ssl_context,
@@ -463,8 +472,7 @@ def sendall(self, data):
463472
return self._wait_for_io(self._socket.sendall, data)
464473

465474
def close(self):
466-
self._socket.shutdown(SHUT_RDWR)
467-
self._socket.close()
475+
self.close_socket(self._socket)
468476

469477
def kill(self):
470478
self._socket.close()
@@ -509,7 +517,7 @@ def _connect(cls, resolved_address, timeout, keep_alive):
509517
log.debug("[#0000] C: <ERROR> %s %s", type(error).__name__,
510518
" ".join(map(repr, error.args)))
511519
log.debug("[#0000] C: <CLOSE> %s", resolved_address)
512-
s.close()
520+
cls.close_socket(s)
513521
raise ServiceUnavailable(
514522
"Failed to establish connection to {!r} (reason {})".format(
515523
resolved_address, error))
@@ -524,6 +532,7 @@ def _secure(cls, s, host, ssl_context):
524532
sni_host = host if HAS_SNI and host else None
525533
s = ssl_context.wrap_socket(s, server_hostname=sni_host)
526534
except (OSError, SSLError, CertificateError) as cause:
535+
cls.close_socket(s)
527536
raise BoltSecurityError(
528537
message="Failed to establish encrypted connection.",
529538
address=(host, local_port)
@@ -582,20 +591,20 @@ def _handshake(cls, s, resolved_address):
582591
# If no data is returned after a successful select
583592
# response, the server has closed the connection
584593
log.debug("[#%04X] S: <CLOSE>", local_port)
585-
BoltSocket.close_socket(s)
594+
cls.close_socket(s)
586595
raise ServiceUnavailable(
587596
"Connection to {address} closed without handshake response".format(
588597
address=resolved_address))
589598
if data_size != 4:
590599
# Some garbled data has been received
591600
log.debug("[#%04X] S: @*#!", local_port)
592-
s.close()
601+
cls.close_socket(s)
593602
raise BoltProtocolError(
594603
"Expected four byte Bolt handshake response from %r, received %r instead; check for incorrect port number" % (
595604
resolved_address, data), address=resolved_address)
596605
elif data == b"HTTP":
597606
log.debug("[#%04X] S: <CLOSE>", local_port)
598-
BoltSocket.close_socket(s)
607+
cls.close_socket(s)
599608
raise ServiceUnavailable(
600609
"Cannot to connect to Bolt service on {!r} "
601610
"(looks like HTTP)".format(resolved_address))
@@ -606,12 +615,14 @@ def _handshake(cls, s, resolved_address):
606615

607616
@classmethod
608617
def close_socket(cls, socket_):
618+
if isinstance(socket_, BoltSocket):
619+
socket_ = socket_._socket
609620
try:
610-
if isinstance(socket_, BoltSocket):
611-
socket_.close()
612-
else:
613-
socket_.shutdown(SHUT_RDWR)
614-
socket_.close()
621+
socket_.shutdown(SHUT_RDWR)
622+
except OSError:
623+
pass
624+
try:
625+
socket_.close()
615626
except OSError:
616627
pass
617628

@@ -647,11 +658,11 @@ def connect(cls, address, *, timeout, custom_resolver, ssl_context,
647658
log.debug("[#%04X] C: <CONNECTION FAILED> %s", local_port,
648659
err_str)
649660
if s:
650-
BoltSocket.close_socket(s)
661+
cls.close_socket(s)
651662
errors.append(error)
652663
except Exception:
653664
if s:
654-
BoltSocket.close_socket(s)
665+
cls.close_socket(s)
655666
raise
656667
if not errors:
657668
raise ServiceUnavailable(

neo4j/_sync/io/_bolt.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ def time_remaining():
374374
finally:
375375
connection.socket.set_deadline(None)
376376
except Exception as e:
377-
log.debug("[#%04X] C: <OPEN FAILED> %r", s.getsockname()[1], e)
377+
log.debug("[#%04X] C: <OPEN FAILED> %r", connection.local_port, e)
378378
connection.kill()
379379
raise
380380

0 commit comments

Comments
 (0)