@@ -172,12 +172,16 @@ proc `$`(channel: YamuxChannel): string =
172
172
result &= " {" & s.foldl (if a != " " : a & " , " & b else : b, " " ) & " }"
173
173
174
174
proc lengthSendQueue (channel: YamuxChannel ): int =
175
+ # # Returns the length of what remains to be sent
176
+ # #
175
177
channel.sendQueue.foldl (a + b.data.len - b.sent, 0 )
176
178
177
179
proc lengthSendQueueWithLimit (channel: YamuxChannel ): int =
180
+ # # Returns the length of what remains to be sent, but limit the size of big messages.
181
+ # #
178
182
# 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.
181
185
channel.sendQueue.foldl (a + min (b.data.len - b.sent, channel.maxSendQueueSize div 3 ), 0 )
182
186
183
187
proc actuallyClose (channel: YamuxChannel ) {.async .} =
@@ -200,6 +204,9 @@ method closeImpl*(channel: YamuxChannel) {.async.} =
200
204
await channel.actuallyClose ()
201
205
202
206
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.
203
210
if channel.isReset:
204
211
return
205
212
trace " Reset channel"
@@ -220,11 +227,14 @@ proc reset(channel: YamuxChannel, isLocal: bool = false) {.async.} =
220
227
await channel.remoteClosed ()
221
228
channel.receivedData.fire ()
222
229
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.
225
231
channel.recvWindow = 0
226
232
227
233
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.
228
238
let inWindow = channel.recvWindow + channel.recvQueue.len
229
239
if inWindow > channel.maxRecvWindow div 2 :
230
240
return
@@ -242,6 +252,7 @@ method readOnce*(
242
252
pbytes: pointer ,
243
253
nbytes: int ):
244
254
Future [int ] {.async .} =
255
+ # # Read from a yamux channel
245
256
246
257
if channel.isReset:
247
258
raise if channel.remoteReset:
@@ -287,17 +298,18 @@ proc trySend(channel: YamuxChannel) {.async.} =
287
298
return
288
299
channel.isSending = true
289
300
defer : channel.isSending = false
301
+
290
302
while channel.sendQueue.len != 0 :
291
303
channel.sendQueue.keepItIf (not (it.fut.cancelled () and it.sent == 0 ))
292
304
if channel.sendWindow == 0 :
293
- trace " send window empty"
305
+ trace " trying to send while the sendWindow is empty"
294
306
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,
296
308
currentQueueSize = channel.lengthSendQueueWithLimit ()
297
309
try :
298
310
await channel.reset (true )
299
311
except CatchableError as exc:
300
- debug " failed to reset" , msg= exc.msg
312
+ warn " failed to reset" , msg= exc.msg
301
313
break
302
314
303
315
let
@@ -316,20 +328,24 @@ proc trySend(channel: YamuxChannel) {.async.} =
316
328
317
329
var futures: seq [Future [void ]]
318
330
while inBuffer < toSend:
331
+ # concatenate the different message we try to send into one buffer
319
332
let (data, sent, fut) = channel.sendQueue[0 ]
320
333
let bufferToSend = min (data.len - sent, toSend - inBuffer)
321
334
sendBuffer.toOpenArray (12 , 12 + toSend - 1 )[inBuffer..< (inBuffer+ bufferToSend)] =
322
335
channel.sendQueue[0 ].data.toOpenArray (sent, sent + bufferToSend - 1 )
323
336
channel.sendQueue[0 ].sent.inc (bufferToSend)
324
337
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
325
340
futures.add (fut)
326
341
channel.sendQueue.delete (0 )
327
342
inBuffer.inc (bufferToSend)
328
343
329
- trace " build send buffer" , h = $ header, msg = string . fromBytes (sendBuffer[ 12 ..^ 1 ])
344
+ trace " try to send the buffer" , h = $ header
330
345
channel.sendWindow.dec (toSend)
331
346
try : await channel.conn.write (sendBuffer)
332
347
except CatchableError as exc:
348
+ trace " failed to send the buffer"
333
349
let connDown = newLPStreamConnDownError (exc)
334
350
for fut in futures.items ():
335
351
fut.fail (connDown)
@@ -340,6 +356,8 @@ proc trySend(channel: YamuxChannel) {.async.} =
340
356
channel.activity = true
341
357
342
358
method write * (channel: YamuxChannel , msg: seq [byte ]): Future [void ] =
359
+ # # Write to yamux channel
360
+ # #
343
361
result = newFuture [void ](" Yamux Send" )
344
362
if channel.remoteReset:
345
363
result .fail (newLPStreamResetError ())
@@ -355,7 +373,9 @@ method write*(channel: YamuxChannel, msg: seq[byte]): Future[void] =
355
373
libp2p_yamux_recv_queue.observe (channel.lengthSendQueue ().int64 )
356
374
asyncSpawn channel.trySend ()
357
375
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
+ # #
359
379
if channel.opened:
360
380
trace " Try to open channel twice"
361
381
return
@@ -381,7 +401,7 @@ proc lenBySrc(m: Yamux, isSrc: bool): int =
381
401
for v in m.channels.values ():
382
402
if v.isSrc == isSrc: result += 1
383
403
384
- proc cleanupChann (m: Yamux , channel: YamuxChannel ) {.async .} =
404
+ proc cleanupChannel (m: Yamux , channel: YamuxChannel ) {.async .} =
385
405
await channel.join ()
386
406
m.channels.del (channel.id)
387
407
when defined (libp2p_yamux_metrics):
@@ -419,7 +439,7 @@ proc createStream(m: Yamux, id: uint32, isSrc: bool,
419
439
when defined (libp2p_agents_metrics):
420
440
result .shortAgent = m.connection.shortAgent
421
441
m.channels[id] = result
422
- asyncSpawn m.cleanupChann (result )
442
+ asyncSpawn m.cleanupChannel (result )
423
443
trace " created channel" , id, pid= m.connection.peerId
424
444
when defined (libp2p_yamux_metrics):
425
445
libp2p_yamux_channels.set (m.lenBySrc (isSrc).int64 , [$ isSrc, $ result .peerId])
@@ -440,7 +460,7 @@ method close*(m: Yamux) {.async.} =
440
460
trace " Closed yamux"
441
461
442
462
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
444
464
# #
445
465
try :
446
466
await m.streamHandler (channel)
@@ -474,6 +494,7 @@ method handle*(m: Yamux) {.async.} =
474
494
else :
475
495
if header.streamId in m.flushed:
476
496
m.flushed.del (header.streamId)
497
+
477
498
if header.streamId mod 2 == m.currentId mod 2 :
478
499
debug " Peer used our reserved stream id, skipping" , id= header.streamId, currentId= m.currentId, peerId= m.connection.peerId
479
500
raise newException (YamuxError , " Peer used our reserved stream id" )
0 commit comments