fix connection event order when connection dies early (#351)
if the connection is already closed (because the remote closes during identfiy for example), an exception would be raised which would leave the connection in limbo, beacuse it would not go through the rest of internalConnect. Also, if the connection is already closed, the disconnect event would be scheduled before the connect event :/
This commit is contained in:
parent
6d91d61844
commit
16a008db75
|
@ -86,7 +86,7 @@ func shortLog*(c: ControlMessage): auto =
|
||||||
|
|
||||||
func shortLog*(msg: Message): auto =
|
func shortLog*(msg: Message): auto =
|
||||||
(
|
(
|
||||||
fromPeer: msg.fromPeer,
|
fromPeer: msg.fromPeer.pretty,
|
||||||
data: msg.data.shortLog,
|
data: msg.data.shortLog,
|
||||||
seqno: msg.seqno.shortLog,
|
seqno: msg.seqno.shortLog,
|
||||||
topicIDs: $msg.topicIDs,
|
topicIDs: $msg.topicIDs,
|
||||||
|
|
|
@ -205,10 +205,6 @@ proc disconnect*(s: Switch, peerId: PeerID): Future[void] {.gcsafe.} =
|
||||||
s.connManager.dropPeer(peerId)
|
s.connManager.dropPeer(peerId)
|
||||||
|
|
||||||
proc upgradeOutgoing(s: Switch, conn: Connection): Future[Connection] {.async, gcsafe.} =
|
proc upgradeOutgoing(s: Switch, conn: Connection): Future[Connection] {.async, gcsafe.} =
|
||||||
logScope:
|
|
||||||
conn = $conn
|
|
||||||
oid = $conn.oid
|
|
||||||
|
|
||||||
let sconn = await s.secure(conn) # secure the connection
|
let sconn = await s.secure(conn) # secure the connection
|
||||||
if isNil(sconn):
|
if isNil(sconn):
|
||||||
raise newException(CatchableError,
|
raise newException(CatchableError,
|
||||||
|
@ -218,21 +214,29 @@ proc upgradeOutgoing(s: Switch, conn: Connection): Future[Connection] {.async, g
|
||||||
raise newException(CatchableError,
|
raise newException(CatchableError,
|
||||||
"current version of nim-libp2p requires that secure protocol negotiates peerid")
|
"current version of nim-libp2p requires that secure protocol negotiates peerid")
|
||||||
|
|
||||||
trace "upgrading connection"
|
trace "upgrading connection", conn = $sconn, uoid = $conn.oid
|
||||||
let muxer = await s.mux(sconn) # mux it if possible
|
let muxer = await s.mux(sconn) # mux it if possible
|
||||||
if muxer == nil:
|
if muxer == nil:
|
||||||
# TODO this might be relaxed in the future
|
# TODO this might be relaxed in the future
|
||||||
raise newException(CatchableError,
|
raise newException(CatchableError,
|
||||||
"a muxer is required for outgoing connections")
|
"a muxer is required for outgoing connections")
|
||||||
|
|
||||||
|
try:
|
||||||
await s.identify(muxer)
|
await s.identify(muxer)
|
||||||
|
except CatchableError as exc:
|
||||||
|
# Identify is non-essential, though if it fails, it might indicate that
|
||||||
|
# the connection was closed already - this will be picked up by the read
|
||||||
|
# loop
|
||||||
|
debug "Could not identify connection",
|
||||||
|
err = exc.msg, conn = $conn, uoid = $conn.oid
|
||||||
|
|
||||||
if isNil(sconn.peerInfo):
|
if isNil(sconn.peerInfo):
|
||||||
await sconn.close()
|
await sconn.close()
|
||||||
raise newException(CatchableError,
|
raise newException(CatchableError,
|
||||||
"unable to identify connection, stopping upgrade")
|
"unable to identify connection, stopping upgrade")
|
||||||
|
|
||||||
trace "successfully upgraded outgoing connection", oid = sconn.oid
|
trace "successfully upgraded outgoing connection",
|
||||||
|
conn = $sconn, uoid = $conn.oid, oid = $sconn.oid
|
||||||
|
|
||||||
return sconn
|
return sconn
|
||||||
|
|
||||||
|
@ -267,7 +271,8 @@ proc upgradeIncoming(s: Switch, conn: Connection) {.async, gcsafe.} =
|
||||||
except CancelledError as exc:
|
except CancelledError as exc:
|
||||||
raise exc
|
raise exc
|
||||||
except CatchableError as exc:
|
except CatchableError as exc:
|
||||||
debug "ending secured handler", err = exc.msg
|
debug "ending secured handler",
|
||||||
|
err = exc.msg, conn = $conn, oid = $conn.oid
|
||||||
|
|
||||||
if (await ms.select(conn)): # just handshake
|
if (await ms.select(conn)): # just handshake
|
||||||
# add the secure handlers
|
# add the secure handlers
|
||||||
|
@ -281,9 +286,6 @@ proc upgradeIncoming(s: Switch, conn: Connection) {.async, gcsafe.} =
|
||||||
proc internalConnect(s: Switch,
|
proc internalConnect(s: Switch,
|
||||||
peerId: PeerID,
|
peerId: PeerID,
|
||||||
addrs: seq[MultiAddress]): Future[Connection] {.async.} =
|
addrs: seq[MultiAddress]): Future[Connection] {.async.} =
|
||||||
logScope:
|
|
||||||
peer = peerId
|
|
||||||
|
|
||||||
if s.peerInfo.peerId == peerId:
|
if s.peerInfo.peerId == peerId:
|
||||||
raise newException(CatchableError, "can't dial self!")
|
raise newException(CatchableError, "can't dial self!")
|
||||||
|
|
||||||
|
@ -300,12 +302,12 @@ proc internalConnect(s: Switch,
|
||||||
# This connection should already have been removed from the connection
|
# This connection should already have been removed from the connection
|
||||||
# manager - it's essentially a bug that we end up here - we'll fail
|
# manager - it's essentially a bug that we end up here - we'll fail
|
||||||
# for now, hoping that this will clean themselves up later...
|
# for now, hoping that this will clean themselves up later...
|
||||||
warn "dead connection in connection manager"
|
warn "dead connection in connection manager", peer = $peerId
|
||||||
await conn.close()
|
await conn.close()
|
||||||
raise newException(CatchableError, "Zombie connection encountered")
|
raise newException(CatchableError, "Zombie connection encountered")
|
||||||
|
|
||||||
trace "Reusing existing connection", oid = $conn.oid,
|
trace "Reusing existing connection",
|
||||||
direction = $conn.dir
|
oid = $conn.oid, direction = $conn.dir, peer = $peerId
|
||||||
|
|
||||||
return conn
|
return conn
|
||||||
|
|
||||||
|
@ -317,10 +319,10 @@ proc internalConnect(s: Switch,
|
||||||
let dialed = try:
|
let dialed = try:
|
||||||
await t.dial(a)
|
await t.dial(a)
|
||||||
except CancelledError as exc:
|
except CancelledError as exc:
|
||||||
trace "dialing canceled", exc = exc.msg
|
trace "dialing canceled", exc = exc.msg, peer = $peerId
|
||||||
raise exc
|
raise exc
|
||||||
except CatchableError as exc:
|
except CatchableError as exc:
|
||||||
trace "dialing failed", exc = exc.msg
|
trace "dialing failed", exc = exc.msg, peer = $peerId
|
||||||
libp2p_failed_dials.inc()
|
libp2p_failed_dials.inc()
|
||||||
continue # Try the next address
|
continue # Try the next address
|
||||||
|
|
||||||
|
@ -344,6 +346,7 @@ proc internalConnect(s: Switch,
|
||||||
|
|
||||||
conn = upgraded
|
conn = upgraded
|
||||||
trace "dial successful",
|
trace "dial successful",
|
||||||
|
peer = $peerId,
|
||||||
oid = $upgraded.oid,
|
oid = $upgraded.oid,
|
||||||
peerInfo = shortLog(upgraded.peerInfo)
|
peerInfo = shortLog(upgraded.peerInfo)
|
||||||
break
|
break
|
||||||
|
@ -354,6 +357,14 @@ proc internalConnect(s: Switch,
|
||||||
if isNil(conn): # None of the addresses connected
|
if isNil(conn): # None of the addresses connected
|
||||||
raise newException(CatchableError, "Unable to establish outgoing link")
|
raise newException(CatchableError, "Unable to establish outgoing link")
|
||||||
|
|
||||||
|
if conn.closed():
|
||||||
|
# This can happen if one of the peer event handlers deems the peer
|
||||||
|
# unworthy and disconnects it
|
||||||
|
raise newLPStreamClosedError()
|
||||||
|
|
||||||
|
await s.triggerConnEvent(
|
||||||
|
peerId, ConnEvent(kind: ConnEventKind.Connected, incoming: false))
|
||||||
|
|
||||||
proc peerCleanup() {.async.} =
|
proc peerCleanup() {.async.} =
|
||||||
try:
|
try:
|
||||||
await conn.closeEvent.wait()
|
await conn.closeEvent.wait()
|
||||||
|
@ -362,21 +373,15 @@ proc internalConnect(s: Switch,
|
||||||
except CancelledError:
|
except CancelledError:
|
||||||
# This is top-level procedure which will work as separate task, so it
|
# This is top-level procedure which will work as separate task, so it
|
||||||
# do not need to propogate CancelledError.
|
# do not need to propogate CancelledError.
|
||||||
trace "Unexpected cancellation in switch peer connect cleanup"
|
trace "Unexpected cancellation in switch peer connect cleanup",
|
||||||
|
peer = $peerId
|
||||||
except CatchableError as exc:
|
except CatchableError as exc:
|
||||||
trace "Unexpected exception in switch peer connect cleanup",
|
trace "Unexpected exception in switch peer connect cleanup",
|
||||||
errMsg = exc.msg
|
errMsg = exc.msg, peer = $peerId
|
||||||
|
|
||||||
# All the errors are handled inside `cleanup()` procedure.
|
# All the errors are handled inside `cleanup()` procedure.
|
||||||
asyncSpawn peerCleanup()
|
asyncSpawn peerCleanup()
|
||||||
|
|
||||||
await s.triggerConnEvent(
|
|
||||||
peerId, ConnEvent(kind: ConnEventKind.Connected, incoming: false))
|
|
||||||
|
|
||||||
if conn.closed():
|
|
||||||
# This can happen if one of the peer event handlers deems the peer
|
|
||||||
# unworthy and disconnects it
|
|
||||||
raise newException(CatchableError, "Connection closed during handshake")
|
|
||||||
|
|
||||||
return conn
|
return conn
|
||||||
|
|
||||||
|
@ -498,7 +503,13 @@ proc muxerHandler(s: Switch, muxer: Muxer) {.async, gcsafe.} =
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await s.identify(muxer)
|
await s.identify(muxer)
|
||||||
|
except CatchableError as exc:
|
||||||
|
# Identify is non-essential, though if it fails, it might indicate that
|
||||||
|
# the connection was closed already - this will be picked up by the read
|
||||||
|
# loop
|
||||||
|
debug "Could not identify connection", err = exc.msg
|
||||||
|
|
||||||
|
try:
|
||||||
let peerId = muxer.connection.peerInfo.peerId
|
let peerId = muxer.connection.peerInfo.peerId
|
||||||
|
|
||||||
proc peerCleanup() {.async.} =
|
proc peerCleanup() {.async.} =
|
||||||
|
@ -509,9 +520,9 @@ proc muxerHandler(s: Switch, muxer: Muxer) {.async, gcsafe.} =
|
||||||
except CancelledError:
|
except CancelledError:
|
||||||
# This is top-level procedure which will work as separate task, so it
|
# This is top-level procedure which will work as separate task, so it
|
||||||
# do not need to propogate CancelledError.
|
# do not need to propogate CancelledError.
|
||||||
trace "Unexpected cancellation in switch muxer cleanup"
|
debug "Unexpected cancellation in switch muxer cleanup"
|
||||||
except CatchableError as exc:
|
except CatchableError as exc:
|
||||||
trace "Unexpected exception in switch muxer cleanup",
|
debug "Unexpected exception in switch muxer cleanup",
|
||||||
errMsg = exc.msg
|
errMsg = exc.msg
|
||||||
|
|
||||||
proc peerStartup() {.async.} =
|
proc peerStartup() {.async.} =
|
||||||
|
@ -522,15 +533,16 @@ proc muxerHandler(s: Switch, muxer: Muxer) {.async, gcsafe.} =
|
||||||
except CancelledError:
|
except CancelledError:
|
||||||
# This is top-level procedure which will work as separate task, so it
|
# This is top-level procedure which will work as separate task, so it
|
||||||
# do not need to propogate CancelledError.
|
# do not need to propogate CancelledError.
|
||||||
trace "Unexpected cancellation in switch muxer startup"
|
debug "Unexpected cancellation in switch muxer startup"
|
||||||
except CatchableError as exc:
|
except CatchableError as exc:
|
||||||
trace "Unexpected exception in switch muxer startup",
|
debug "Unexpected exception in switch muxer startup",
|
||||||
errMsg = exc.msg
|
errMsg = exc.msg
|
||||||
|
|
||||||
|
# All the errors are handled inside `peerStartup()` procedure.
|
||||||
|
asyncSpawn peerStartup()
|
||||||
|
|
||||||
# All the errors are handled inside `peerCleanup()` procedure.
|
# All the errors are handled inside `peerCleanup()` procedure.
|
||||||
asyncSpawn peerCleanup()
|
asyncSpawn peerCleanup()
|
||||||
# All the errors are handled inside `peerStartup()` procedure.
|
|
||||||
asyncSpawn peerStartup()
|
|
||||||
|
|
||||||
except CancelledError as exc:
|
except CancelledError as exc:
|
||||||
await muxer.close()
|
await muxer.close()
|
||||||
|
|
Loading…
Reference in New Issue