Skip to content

Commit eb0890c

Browse files
authored
docs: add comments and improve yamux readability (#1006)
1 parent 9bc5ec1 commit eb0890c

File tree

2 files changed

+35
-14
lines changed

2 files changed

+35
-14
lines changed

libp2p/muxers/yamux/yamux.nim

+33-12
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,16 @@ proc `$`(channel: YamuxChannel): string =
172172
result &= " {" & s.foldl(if a != "": a & ", " & b else: b, "") & "}"
173173

174174
proc lengthSendQueue(channel: YamuxChannel): int =
175+
## Returns the length of what remains to be sent
176+
##
175177
channel.sendQueue.foldl(a + b.data.len - b.sent, 0)
176178

177179
proc lengthSendQueueWithLimit(channel: YamuxChannel): int =
180+
## Returns the length of what remains to be sent, but limit the size of big messages.
181+
##
178182
# For leniency, limit big messages size to the third of maxSendQueueSize
179-
# This value is arbitrary, it's not in the specs
180-
# It permits to store up to 3 big messages if the peer is stalling.
183+
# This value is arbitrary, it's not in the specs, it permits to store up to
184+
# 3 big messages if the peer is stalling.
181185
channel.sendQueue.foldl(a + min(b.data.len - b.sent, channel.maxSendQueueSize div 3), 0)
182186

183187
proc actuallyClose(channel: YamuxChannel) {.async.} =
@@ -200,6 +204,9 @@ method closeImpl*(channel: YamuxChannel) {.async.} =
200204
await channel.actuallyClose()
201205

202206
proc reset(channel: YamuxChannel, isLocal: bool = false) {.async.} =
207+
# If we reset locally, we want to flush up to a maximum of recvWindow
208+
# bytes. It's because the peer we're connected to can send us data before
209+
# it receives the reset.
203210
if channel.isReset:
204211
return
205212
trace "Reset channel"
@@ -220,11 +227,14 @@ proc reset(channel: YamuxChannel, isLocal: bool = false) {.async.} =
220227
await channel.remoteClosed()
221228
channel.receivedData.fire()
222229
if not isLocal:
223-
# If we reset locally, we want to flush up to a maximum of recvWindow
224-
# bytes. We use the recvWindow in the proc cleanupChann.
230+
# If the reset is remote, there's no reason to flush anything.
225231
channel.recvWindow = 0
226232

227233
proc updateRecvWindow(channel: YamuxChannel) {.async.} =
234+
## Send to the peer a window update when the recvWindow is empty enough
235+
##
236+
# In order to avoid spamming a window update everytime a byte is read,
237+
# we send it everytime half of the maxRecvWindow is read.
228238
let inWindow = channel.recvWindow + channel.recvQueue.len
229239
if inWindow > channel.maxRecvWindow div 2:
230240
return
@@ -242,6 +252,7 @@ method readOnce*(
242252
pbytes: pointer,
243253
nbytes: int):
244254
Future[int] {.async.} =
255+
## Read from a yamux channel
245256

246257
if channel.isReset:
247258
raise if channel.remoteReset:
@@ -287,17 +298,18 @@ proc trySend(channel: YamuxChannel) {.async.} =
287298
return
288299
channel.isSending = true
289300
defer: channel.isSending = false
301+
290302
while channel.sendQueue.len != 0:
291303
channel.sendQueue.keepItIf(not (it.fut.cancelled() and it.sent == 0))
292304
if channel.sendWindow == 0:
293-
trace "send window empty"
305+
trace "trying to send while the sendWindow is empty"
294306
if channel.lengthSendQueueWithLimit() > channel.maxSendQueueSize:
295-
debug "channel send queue too big, resetting", maxSendQueueSize=channel.maxSendQueueSize,
307+
trace "channel send queue too big, resetting", maxSendQueueSize=channel.maxSendQueueSize,
296308
currentQueueSize = channel.lengthSendQueueWithLimit()
297309
try:
298310
await channel.reset(true)
299311
except CatchableError as exc:
300-
debug "failed to reset", msg=exc.msg
312+
warn "failed to reset", msg=exc.msg
301313
break
302314

303315
let
@@ -316,20 +328,24 @@ proc trySend(channel: YamuxChannel) {.async.} =
316328

317329
var futures: seq[Future[void]]
318330
while inBuffer < toSend:
331+
# concatenate the different message we try to send into one buffer
319332
let (data, sent, fut) = channel.sendQueue[0]
320333
let bufferToSend = min(data.len - sent, toSend - inBuffer)
321334
sendBuffer.toOpenArray(12, 12 + toSend - 1)[inBuffer..<(inBuffer+bufferToSend)] =
322335
channel.sendQueue[0].data.toOpenArray(sent, sent + bufferToSend - 1)
323336
channel.sendQueue[0].sent.inc(bufferToSend)
324337
if channel.sendQueue[0].sent >= data.len:
338+
# if every byte of the message is in the buffer, add the write future to the
339+
# sequence of futures to be completed (or failed) when the buffer is sent
325340
futures.add(fut)
326341
channel.sendQueue.delete(0)
327342
inBuffer.inc(bufferToSend)
328343

329-
trace "build send buffer", h = $header, msg=string.fromBytes(sendBuffer[12..^1])
344+
trace "try to send the buffer", h = $header
330345
channel.sendWindow.dec(toSend)
331346
try: await channel.conn.write(sendBuffer)
332347
except CatchableError as exc:
348+
trace "failed to send the buffer"
333349
let connDown = newLPStreamConnDownError(exc)
334350
for fut in futures.items():
335351
fut.fail(connDown)
@@ -340,6 +356,8 @@ proc trySend(channel: YamuxChannel) {.async.} =
340356
channel.activity = true
341357

342358
method write*(channel: YamuxChannel, msg: seq[byte]): Future[void] =
359+
## Write to yamux channel
360+
##
343361
result = newFuture[void]("Yamux Send")
344362
if channel.remoteReset:
345363
result.fail(newLPStreamResetError())
@@ -355,7 +373,9 @@ method write*(channel: YamuxChannel, msg: seq[byte]): Future[void] =
355373
libp2p_yamux_recv_queue.observe(channel.lengthSendQueue().int64)
356374
asyncSpawn channel.trySend()
357375

358-
proc open*(channel: YamuxChannel) {.async.} =
376+
proc open(channel: YamuxChannel) {.async.} =
377+
## Open a yamux channel by sending a window update with Syn or Ack flag
378+
##
359379
if channel.opened:
360380
trace "Try to open channel twice"
361381
return
@@ -381,7 +401,7 @@ proc lenBySrc(m: Yamux, isSrc: bool): int =
381401
for v in m.channels.values():
382402
if v.isSrc == isSrc: result += 1
383403

384-
proc cleanupChann(m: Yamux, channel: YamuxChannel) {.async.} =
404+
proc cleanupChannel(m: Yamux, channel: YamuxChannel) {.async.} =
385405
await channel.join()
386406
m.channels.del(channel.id)
387407
when defined(libp2p_yamux_metrics):
@@ -419,7 +439,7 @@ proc createStream(m: Yamux, id: uint32, isSrc: bool,
419439
when defined(libp2p_agents_metrics):
420440
result.shortAgent = m.connection.shortAgent
421441
m.channels[id] = result
422-
asyncSpawn m.cleanupChann(result)
442+
asyncSpawn m.cleanupChannel(result)
423443
trace "created channel", id, pid=m.connection.peerId
424444
when defined(libp2p_yamux_metrics):
425445
libp2p_yamux_channels.set(m.lenBySrc(isSrc).int64, [$isSrc, $result.peerId])
@@ -440,7 +460,7 @@ method close*(m: Yamux) {.async.} =
440460
trace "Closed yamux"
441461

442462
proc handleStream(m: Yamux, channel: YamuxChannel) {.async.} =
443-
## call the muxer stream handler for this channel
463+
## Call the muxer stream handler for this channel
444464
##
445465
try:
446466
await m.streamHandler(channel)
@@ -474,6 +494,7 @@ method handle*(m: Yamux) {.async.} =
474494
else:
475495
if header.streamId in m.flushed:
476496
m.flushed.del(header.streamId)
497+
477498
if header.streamId mod 2 == m.currentId mod 2:
478499
debug "Peer used our reserved stream id, skipping", id=header.streamId, currentId=m.currentId, peerId=m.connection.peerId
479500
raise newException(YamuxError, "Peer used our reserved stream id")

tests/testyamux.nim

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ suite "Yamux":
3636
yamuxa.close(), yamuxb.close(),
3737
handlera, handlerb)
3838

39-
suite "Basic":
40-
asyncTest "Simple test":
39+
suite "Simple Reading/Writing yamux messages":
40+
asyncTest "Roundtrip of small messages":
4141
mSetup()
4242

4343
yamuxb.streamHandler = proc(conn: Connection) {.async.} =

0 commit comments

Comments
 (0)