mirror of
https://github.com/vacp2p/nim-libp2p.git
synced 2025-01-30 10:26:48 +00:00
d02735dc46
Peer Info is now for local peer data only. For other peers info, use the peer store. Previous reference to peer info are replaced with the peerid
227 lines
6.4 KiB
Nim
227 lines
6.4 KiB
Nim
## Nim-LibP2P
|
|
## Copyright (c) 2021 Status Research & Development GmbH
|
|
## Licensed under either of
|
|
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
## at your option.
|
|
## This file may not be copied, modified, or distributed except according to
|
|
## those terms.
|
|
|
|
{.push raises: [Defect].}
|
|
|
|
import std/[tables, sequtils]
|
|
import pkg/[chronos, chronicles, metrics]
|
|
|
|
import ../upgrademngrs/upgrade,
|
|
../muxers/muxer
|
|
|
|
export Upgrade
|
|
|
|
logScope:
|
|
topics = "libp2p muxedupgrade"
|
|
|
|
type
|
|
MuxedUpgrade* = ref object of Upgrade
|
|
muxers*: Table[string, MuxerProvider]
|
|
streamHandler*: StreamHandler
|
|
|
|
proc identify*(
|
|
self: MuxedUpgrade,
|
|
muxer: Muxer) {.async, gcsafe.} =
|
|
# new stream for identify
|
|
var stream = await muxer.newStream()
|
|
if stream == nil:
|
|
return
|
|
|
|
try:
|
|
await self.identify(stream)
|
|
when defined(libp2p_agents_metrics):
|
|
muxer.connection.shortAgent = stream.shortAgent
|
|
finally:
|
|
await stream.closeWithEOF()
|
|
|
|
proc mux*(
|
|
self: MuxedUpgrade,
|
|
conn: Connection): Future[Muxer] {.async, gcsafe.} =
|
|
## mux outgoing connection
|
|
|
|
trace "Muxing connection", conn
|
|
if self.muxers.len == 0:
|
|
warn "no muxers registered, skipping upgrade flow", conn
|
|
return
|
|
|
|
let muxerName = await self.ms.select(conn, toSeq(self.muxers.keys()))
|
|
if muxerName.len == 0 or muxerName == "na":
|
|
debug "no muxer available, early exit", conn
|
|
return
|
|
|
|
trace "Found a muxer", conn, muxerName
|
|
|
|
# create new muxer for connection
|
|
let muxer = self.muxers[muxerName].newMuxer(conn)
|
|
|
|
# install stream handler
|
|
muxer.streamHandler = self.streamHandler
|
|
|
|
self.connManager.storeConn(conn)
|
|
|
|
# store it in muxed connections if we have a peer for it
|
|
self.connManager.storeMuxer(muxer, muxer.handle()) # store muxer and start read loop
|
|
|
|
try:
|
|
await self.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", conn, msg = exc.msg
|
|
|
|
return muxer
|
|
|
|
method upgradeOutgoing*(
|
|
self: MuxedUpgrade,
|
|
conn: Connection): Future[Connection] {.async, gcsafe.} =
|
|
trace "Upgrading outgoing connection", conn
|
|
|
|
let sconn = await self.secure(conn) # secure the connection
|
|
if isNil(sconn):
|
|
raise newException(UpgradeFailedError,
|
|
"unable to secure connection, stopping upgrade")
|
|
|
|
let muxer = await self.mux(sconn) # mux it if possible
|
|
if muxer == nil:
|
|
# TODO this might be relaxed in the future
|
|
raise newException(UpgradeFailedError,
|
|
"a muxer is required for outgoing connections")
|
|
|
|
when defined(libp2p_agents_metrics):
|
|
conn.shortAgent = muxer.connection.shortAgent
|
|
|
|
if sconn.closed():
|
|
await sconn.close()
|
|
raise newException(UpgradeFailedError,
|
|
"Connection closed or missing peer info, stopping upgrade")
|
|
|
|
trace "Upgraded outgoing connection", conn, sconn
|
|
|
|
return sconn
|
|
|
|
method upgradeIncoming*(
|
|
self: MuxedUpgrade,
|
|
incomingConn: Connection) {.async, gcsafe.} = # noraises
|
|
trace "Upgrading incoming connection", incomingConn
|
|
let ms = MultistreamSelect.new()
|
|
|
|
# secure incoming connections
|
|
proc securedHandler(conn: Connection,
|
|
proto: string)
|
|
{.async, gcsafe, closure.} =
|
|
trace "Starting secure handler", conn
|
|
let secure = self.secureManagers.filterIt(it.codec == proto)[0]
|
|
|
|
var cconn = conn
|
|
try:
|
|
var sconn = await secure.secure(cconn, false)
|
|
if isNil(sconn):
|
|
return
|
|
|
|
cconn = sconn
|
|
# add the muxer
|
|
for muxer in self.muxers.values:
|
|
ms.addHandler(muxer.codecs, muxer)
|
|
|
|
# handle subsequent secure requests
|
|
await ms.handle(cconn)
|
|
except CatchableError as exc:
|
|
debug "Exception in secure handler during incoming upgrade", msg = exc.msg, conn
|
|
if not cconn.isUpgraded:
|
|
cconn.upgrade(exc)
|
|
finally:
|
|
if not isNil(cconn):
|
|
await cconn.close()
|
|
|
|
trace "Stopped secure handler", conn
|
|
|
|
try:
|
|
if (await ms.select(incomingConn)): # just handshake
|
|
# add the secure handlers
|
|
for k in self.secureManagers:
|
|
ms.addHandler(k.codec, securedHandler)
|
|
|
|
# handle un-secured connections
|
|
# we handshaked above, set this ms handler as active
|
|
await ms.handle(incomingConn, active = true)
|
|
except CatchableError as exc:
|
|
debug "Exception upgrading incoming", exc = exc.msg
|
|
if not incomingConn.isUpgraded:
|
|
incomingConn.upgrade(exc)
|
|
finally:
|
|
if not isNil(incomingConn):
|
|
await incomingConn.close()
|
|
|
|
proc muxerHandler(
|
|
self: MuxedUpgrade,
|
|
muxer: Muxer) {.async, gcsafe.} =
|
|
let
|
|
conn = muxer.connection
|
|
|
|
# store incoming connection
|
|
self.connManager.storeConn(conn)
|
|
|
|
# store muxer and muxed connection
|
|
self.connManager.storeMuxer(muxer)
|
|
|
|
try:
|
|
await self.identify(muxer)
|
|
except IdentifyError 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", conn, msg = exc.msg
|
|
except LPStreamClosedError as exc:
|
|
debug "Identify stream closed", conn, msg = exc.msg
|
|
except LPStreamEOFError as exc:
|
|
debug "Identify stream EOF", conn, msg = exc.msg
|
|
except CancelledError as exc:
|
|
await muxer.close()
|
|
raise exc
|
|
except CatchableError as exc:
|
|
await muxer.close()
|
|
trace "Exception in muxer handler", conn, msg = exc.msg
|
|
|
|
proc init*(
|
|
T: type MuxedUpgrade,
|
|
identity: Identify,
|
|
muxers: Table[string, MuxerProvider],
|
|
secureManagers: openarray[Secure] = [],
|
|
connManager: ConnManager,
|
|
ms: MultistreamSelect): T =
|
|
|
|
let upgrader = T(
|
|
identity: identity,
|
|
muxers: muxers,
|
|
secureManagers: @secureManagers,
|
|
connManager: connManager,
|
|
ms: ms)
|
|
|
|
upgrader.streamHandler = proc(conn: Connection)
|
|
{.async, gcsafe, raises: [Defect].} =
|
|
trace "Starting stream handler", conn
|
|
try:
|
|
await upgrader.ms.handle(conn) # handle incoming connection
|
|
except CancelledError as exc:
|
|
raise exc
|
|
except CatchableError as exc:
|
|
trace "exception in stream handler", conn, msg = exc.msg
|
|
finally:
|
|
await conn.closeWithEOF()
|
|
trace "Stream handler done", conn
|
|
|
|
for _, val in muxers:
|
|
val.streamHandler = upgrader.streamHandler
|
|
val.muxerHandler = proc(muxer: Muxer): Future[void]
|
|
{.raises: [Defect].} =
|
|
upgrader.muxerHandler(muxer)
|
|
|
|
return upgrader
|