quic 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -121,11 +121,7 @@ static void quic_conn_raise_pending(quic_conn_t *c) {
121
121
  rb_exc_raise(exc);
122
122
  }
123
123
 
124
- /* Run body(arg) under rb_protect. An exception is kept in c->pending_exc
125
- (the first one wins; ngtcp2 stops at the first failing callback anyway)
126
- and turned into NGTCP2_ERR_CALLBACK_FAILURE, so that it never unwinds
127
- through ngtcp2. */
128
- static int quic_conn_protect(quic_conn_t *c, VALUE (*body)(VALUE), void *arg) {
124
+ int quic_conn_protect(quic_conn_t *c, VALUE (*body)(VALUE), void *arg) {
129
125
  int state = 0;
130
126
  rb_protect(body, (VALUE)arg, &state);
131
127
  if (state == 0)
@@ -373,91 +369,87 @@ void quic_conn_copy_alpn(quic_conn_t *c, VALUE settings_v) {
373
369
  &c->alpn_count, &c->alpn_buf);
374
370
  }
375
371
 
376
- /* Shared helper: look up the QUIC::Stream registered for stream_id in the
377
- owner connection's @streams Hash. Returns Qnil if not found (which can
378
- happen if the stream was already removed by a previous stream_close
379
- callback). */
380
- static VALUE quic_conn_lookup_stream(quic_conn_t *c, int64_t stream_id) {
381
- VALUE streams = rb_ivar_get(c->owner, rb_intern("@streams"));
382
- return rb_hash_aref(streams, LL2NUM(stream_id));
372
+ void quic_conn_give_back_peer_stream(ngtcp2_conn *conn, int64_t stream_id) {
373
+ if (!ngtcp2_conn_is_local_stream2(conn, stream_id) &&
374
+ ngtcp2_is_bidi_stream(stream_id)) {
375
+ ngtcp2_conn_extend_max_streams_bidi(conn, 1);
376
+ }
383
377
  }
384
378
 
385
- /* ngtcp2 stream callbacks. The Ruby-touching part of each is a *_body
386
- function run under rb_protect by quic_conn_protect, so that an exception
387
- (a frozen @streams, an allocation failure, ...) never unwinds through
388
- ngtcp2. The callback then returns NGTCP2_ERR_CALLBACK_FAILURE and the
389
- exception is re-raised once ngtcp2 has returned. */
390
-
391
- /* The arguments of a stream callback, handed to its body through
392
- rb_protect's single VALUE. Each body reads only the fields it needs. */
393
- struct quic_stream_cb_args {
394
- quic_conn_t *c;
395
- int64_t stream_id;
396
- uint32_t flags;
397
- const uint8_t *data;
398
- size_t datalen;
399
- uint64_t acked;
400
- uint64_t app_error_code;
401
- };
379
+ /* The ngtcp2 stream callbacks hand each stream to the stream handler (the
380
+ quic_handler_* functions below) or, without one, to its QUIC::Stream
381
+ (quic_stream_on_* in stream.c). */
402
382
 
403
- static VALUE quic_stream_open_body(VALUE arg) {
404
- struct quic_stream_cb_args *a = (struct quic_stream_cb_args *)arg;
405
- VALUE streams = rb_ivar_get(a->c->owner, rb_intern("@streams"));
406
- if (!NIL_P(rb_hash_aref(streams, LL2NUM(a->stream_id)))) {
407
- return Qnil; /* already known (opened by this endpoint) */
383
+ static int quic_handler_recv_stream_data(quic_conn_t *c, ngtcp2_conn *conn,
384
+ uint32_t flags, int64_t stream_id,
385
+ const uint8_t *data, size_t datalen) {
386
+ size_t consumed = 0;
387
+ int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) != 0;
388
+ if (c->handler->recv_stream_data(c->handler_ud, stream_id, data, datalen, fin,
389
+ c->now, &consumed) < 0) {
390
+ return NGTCP2_ERR_CALLBACK_FAILURE;
408
391
  }
409
- VALUE stream = quic_stream_new(a->stream_id, a->c->owner);
410
- rb_hash_aset(streams, LL2NUM(a->stream_id), stream);
411
- return Qnil;
392
+ /* What the handler consumed outright (for HTTP/3, everything but the
393
+ request body) goes straight back to the peer as credit. */
394
+ if (consumed > 0) {
395
+ if (ngtcp2_conn_extend_max_stream_offset(conn, stream_id, consumed) != 0) {
396
+ return NGTCP2_ERR_CALLBACK_FAILURE;
397
+ }
398
+ ngtcp2_conn_extend_max_offset(conn, consumed);
399
+ }
400
+ return 0;
412
401
  }
413
402
 
414
- void quic_conn_give_back_peer_stream(ngtcp2_conn *conn, int64_t stream_id) {
415
- if (!ngtcp2_conn_is_local_stream2(conn, stream_id) &&
416
- ngtcp2_is_bidi_stream(stream_id)) {
417
- ngtcp2_conn_extend_max_streams_bidi(conn, 1);
418
- }
403
+ static int quic_handler_acked_stream_data(quic_conn_t *c, int64_t stream_id,
404
+ uint64_t datalen) {
405
+ return c->handler->acked_stream_data(c->handler_ud, stream_id, datalen) < 0
406
+ ? NGTCP2_ERR_CALLBACK_FAILURE
407
+ : 0;
408
+ }
409
+
410
+ static int quic_handler_stream_close(quic_conn_t *c, ngtcp2_conn *conn,
411
+ uint32_t flags, int64_t stream_id,
412
+ uint64_t app_error_code) {
413
+ /* The handler keeps no stream waiting for the application, so the peer
414
+ gets its stream back at once. */
415
+ quic_conn_give_back_peer_stream(conn, stream_id);
416
+ int has_code = (flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET) != 0;
417
+ return c->handler->stream_close(c->handler_ud, stream_id, has_code,
418
+ app_error_code) < 0
419
+ ? NGTCP2_ERR_CALLBACK_FAILURE
420
+ : 0;
421
+ }
422
+
423
+ static int quic_handler_stream_reset(quic_conn_t *c, int64_t stream_id,
424
+ uint64_t final_size,
425
+ uint64_t app_error_code) {
426
+ return c->handler->stream_reset(c->handler_ud, stream_id, final_size,
427
+ app_error_code) < 0
428
+ ? NGTCP2_ERR_CALLBACK_FAILURE
429
+ : 0;
430
+ }
431
+
432
+ /* A handler built against ABI 1.0 lacks recv_stop_sending, and learns of
433
+ STOP_SENDING only when #write_pkt finds the send side shut
434
+ (stream_shut_write) or the stream closes. */
435
+ static int quic_handler_recv_stop_sending(quic_conn_t *c, int64_t stream_id,
436
+ uint64_t app_error_code) {
437
+ if (!QUIC_EXT_HANDLER_HAS(c->handler, recv_stop_sending))
438
+ return 0;
439
+ return c->handler->recv_stop_sending(c->handler_ud, stream_id,
440
+ app_error_code) < 0
441
+ ? NGTCP2_ERR_CALLBACK_FAILURE
442
+ : 0;
419
443
  }
420
444
 
445
+ /* Called only for a stream the peer opened. */
421
446
  static int quic_stream_open_cb(ngtcp2_conn *conn, int64_t stream_id,
422
447
  void *user_data) {
423
448
  (void)conn;
424
449
  quic_conn_t *c = (quic_conn_t *)user_data;
425
450
  if (c->handler)
426
451
  return 0; /* the handler keeps its own stream state */
427
- struct quic_stream_cb_args a = {.c = c, .stream_id = stream_id};
428
- return quic_conn_protect(c, quic_stream_open_body, &a);
429
- }
430
-
431
- static VALUE quic_recv_stream_data_body(VALUE arg) {
432
- struct quic_stream_cb_args *a = (struct quic_stream_cb_args *)arg;
433
- quic_conn_t *c = a->c;
434
- VALUE stream = quic_conn_lookup_stream(c, a->stream_id);
435
- if (NIL_P(stream))
436
- return Qnil;
437
-
438
- quic_stream_t *s;
439
- TypedData_Get_Struct(stream, quic_stream_t, &quic_stream_data_type, s);
440
-
441
- /* Surface peer-initiated streams to #accept_stream. The low stream-id bit
442
- marks the initiator (0 == client, 1 == server), so a client queues the
443
- odd ids and a server the even ones. Push once, on first data arrival,
444
- then mark so later data does not re-enqueue. */
445
- bool peer_initiated =
446
- c->is_server ? !(a->stream_id & 0x01) : (a->stream_id & 0x01);
447
- if (!s->accept_queued && peer_initiated) {
448
- VALUE accept_queue = rb_ivar_get(c->owner, rb_intern("@accept_queue"));
449
- rb_ary_push(accept_queue, stream);
450
- s->accept_queued = true;
451
- }
452
-
453
- if (a->datalen > 0) {
454
- VALUE recv_buffer = rb_ivar_get(stream, rb_intern("@recv_buffer"));
455
- rb_str_buf_cat(recv_buffer, (const char *)a->data, (long)a->datalen);
456
- }
457
- if (a->flags & NGTCP2_STREAM_DATA_FLAG_FIN) {
458
- s->fin_received = true;
459
- }
460
- return Qnil;
452
+ return quic_stream_on_open(c, stream_id);
461
453
  }
462
454
 
463
455
  static int quic_recv_stream_data_cb(ngtcp2_conn *conn, uint32_t flags,
@@ -465,64 +457,11 @@ static int quic_recv_stream_data_cb(ngtcp2_conn *conn, uint32_t flags,
465
457
  const uint8_t *data, size_t datalen,
466
458
  void *user_data, void *stream_user_data) {
467
459
  (void)offset;
468
- (void)stream_user_data;
469
460
  quic_conn_t *c = (quic_conn_t *)user_data;
470
- if (c->handler) {
471
- size_t consumed = 0;
472
- int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) != 0;
473
- if (c->handler->recv_stream_data(c->handler_ud, stream_id, data, datalen,
474
- fin, c->now, &consumed) < 0) {
475
- return NGTCP2_ERR_CALLBACK_FAILURE;
476
- }
477
- /* What the handler consumed outright (for HTTP/3, everything but the
478
- request body) goes straight back to the peer as credit. */
479
- if (consumed > 0) {
480
- if (ngtcp2_conn_extend_max_stream_offset(conn, stream_id, consumed) !=
481
- 0) {
482
- return NGTCP2_ERR_CALLBACK_FAILURE;
483
- }
484
- ngtcp2_conn_extend_max_offset(conn, consumed);
485
- }
486
- return 0;
487
- }
488
- struct quic_stream_cb_args a = {
489
- .c = c,
490
- .stream_id = stream_id,
491
- .flags = flags,
492
- .data = data,
493
- .datalen = datalen,
494
- };
495
- return quic_conn_protect(c, quic_recv_stream_data_body, &a);
496
- }
497
-
498
- static VALUE quic_acked_stream_data_offset_body(VALUE arg) {
499
- struct quic_stream_cb_args *a = (struct quic_stream_cb_args *)arg;
500
- VALUE stream = quic_conn_lookup_stream(a->c, a->stream_id);
501
- if (NIL_P(stream))
502
- return Qnil;
503
-
504
- quic_stream_t *s;
505
- TypedData_Get_Struct(stream, quic_stream_t, &quic_stream_data_type, s);
506
- s->acked_offset += a->acked;
507
-
508
- /* Shift any head Chunks of @pending_chunks whose end-offset is fully
509
- covered by acked_offset. Each Chunk's start-offset in the stream is
510
- pending_shifted (after previous shifts); its end-offset is
511
- pending_shifted + RSTRING_LEN(head). A stopped stream's
512
- @pending_chunks is empty, and acks for what it sent before shift
513
- nothing. */
514
- VALUE pending = rb_ivar_get(stream, rb_intern("@pending_chunks"));
515
- while (RARRAY_LEN(pending) > 0) {
516
- VALUE head = RARRAY_AREF(pending, 0);
517
- uint64_t head_end = s->pending_shifted + (uint64_t)RSTRING_LEN(head);
518
- if (head_end <= s->acked_offset) {
519
- rb_ary_shift(pending);
520
- s->pending_shifted = head_end;
521
- } else {
522
- break;
523
- }
524
- }
525
- return Qnil;
461
+ if (c->handler)
462
+ return quic_handler_recv_stream_data(c, conn, flags, stream_id, data,
463
+ datalen);
464
+ return quic_stream_on_recv_data(c, stream_user_data, flags, data, datalen);
526
465
  }
527
466
 
528
467
  static int quic_acked_stream_data_offset_cb(ngtcp2_conn *conn,
@@ -530,150 +469,45 @@ static int quic_acked_stream_data_offset_cb(ngtcp2_conn *conn,
530
469
  uint64_t datalen, void *user_data,
531
470
  void *stream_user_data) {
532
471
  (void)conn;
533
- (void)offset;
534
- (void)stream_user_data;
535
472
  quic_conn_t *c = (quic_conn_t *)user_data;
536
- if (c->handler) {
537
- return c->handler->acked_stream_data(c->handler_ud, stream_id, datalen) < 0
538
- ? NGTCP2_ERR_CALLBACK_FAILURE
539
- : 0;
540
- }
541
- struct quic_stream_cb_args a = {
542
- .c = c, .stream_id = stream_id, .acked = datalen};
543
- return quic_conn_protect(c, quic_acked_stream_data_offset_body, &a);
544
- }
545
-
546
- static VALUE quic_stream_close_body(VALUE arg) {
547
- struct quic_stream_cb_args *a = (struct quic_stream_cb_args *)arg;
548
- VALUE streams = rb_ivar_get(a->c->owner, rb_intern("@streams"));
549
- VALUE stream = rb_hash_aref(streams, LL2NUM(a->stream_id));
550
- if (NIL_P(stream)) {
551
- quic_conn_give_back_peer_stream(a->c->conn, a->stream_id);
552
- return Qnil;
553
- }
554
-
555
- quic_stream_t *s;
556
- TypedData_Get_Struct(stream, quic_stream_t, &quic_stream_data_type, s);
557
- s->closed = true;
558
- if (a->flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET) {
559
- s->close_has_app_error_code = true;
560
- s->close_app_error_code = a->app_error_code;
561
- }
562
- /* A stream still waiting in @accept_queue holds on to what it received.
563
- Were the peer given its stream back now, it could open and close
564
- streams until the queue had used up our memory, so it gets the stream
565
- back only once the application has accepted this one
566
- (QUIC::Stream#_accepted). */
567
- if (s->accept_queued && !s->accepted) {
568
- s->peer_stream_held = true;
569
- } else {
570
- quic_conn_give_back_peer_stream(a->c->conn, a->stream_id);
571
- }
572
- rb_hash_delete(streams, LL2NUM(a->stream_id));
573
- return Qnil;
473
+ if (c->handler)
474
+ return quic_handler_acked_stream_data(c, stream_id, datalen);
475
+ quic_stream_on_acked(stream_user_data, offset, datalen);
476
+ return 0;
574
477
  }
575
478
 
576
479
  static int quic_stream_close_cb(ngtcp2_conn *conn, uint32_t flags,
577
480
  int64_t stream_id, uint64_t app_error_code,
578
481
  void *user_data, void *stream_user_data) {
579
- (void)stream_user_data;
580
482
  quic_conn_t *c = (quic_conn_t *)user_data;
581
- if (c->handler) {
582
- /* The handler keeps no stream waiting for the application, so the peer
583
- gets its stream back at once. */
584
- quic_conn_give_back_peer_stream(conn, stream_id);
585
- int has_code = (flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET) != 0;
586
- return c->handler->stream_close(c->handler_ud, stream_id, has_code,
587
- app_error_code) < 0
588
- ? NGTCP2_ERR_CALLBACK_FAILURE
589
- : 0;
590
- }
591
- struct quic_stream_cb_args a = {
592
- .c = c,
593
- .stream_id = stream_id,
594
- .flags = flags,
595
- .app_error_code = app_error_code,
596
- };
597
- return quic_conn_protect(c, quic_stream_close_body, &a);
598
- }
599
-
600
- static VALUE quic_stream_reset_body(VALUE arg) {
601
- struct quic_stream_cb_args *a = (struct quic_stream_cb_args *)arg;
602
- VALUE stream = quic_conn_lookup_stream(a->c, a->stream_id);
603
- if (NIL_P(stream))
604
- return Qnil;
605
-
606
- quic_stream_t *s;
607
- TypedData_Get_Struct(stream, quic_stream_t, &quic_stream_data_type, s);
608
- s->reset = true;
609
- s->close_app_error_code = a->app_error_code;
610
- s->close_has_app_error_code = true;
611
- return Qnil;
483
+ if (c->handler)
484
+ return quic_handler_stream_close(c, conn, flags, stream_id, app_error_code);
485
+ return quic_stream_on_close(c, stream_user_data, stream_id, flags,
486
+ app_error_code);
612
487
  }
613
488
 
614
489
  static int quic_stream_reset_cb(ngtcp2_conn *conn, int64_t stream_id,
615
490
  uint64_t final_size, uint64_t app_error_code,
616
491
  void *user_data, void *stream_user_data) {
617
492
  (void)conn;
618
- (void)stream_user_data;
619
493
  quic_conn_t *c = (quic_conn_t *)user_data;
620
- if (c->handler) {
621
- return c->handler->stream_reset(c->handler_ud, stream_id, final_size,
622
- app_error_code) < 0
623
- ? NGTCP2_ERR_CALLBACK_FAILURE
624
- : 0;
625
- }
626
- struct quic_stream_cb_args a = {
627
- .c = c, .stream_id = stream_id, .app_error_code = app_error_code};
628
- return quic_conn_protect(c, quic_stream_reset_body, &a);
629
- }
630
-
631
- /* Nothing queued on stream can go out any more: drop it all, and have
632
- #write_pkt skip the stream from now on. ngtcp2 retransmits no STREAM
633
- frame of a stream it has reset, so it no longer reads the bytes it was
634
- given either. */
635
- static void quic_stream_stop(VALUE stream) {
636
- quic_stream_t *s;
637
- TypedData_Get_Struct(stream, quic_stream_t, &quic_stream_data_type, s);
638
- s->stopped = true;
639
- rb_ary_clear(rb_ivar_get(stream, rb_intern("@pending_chunks")));
640
- }
641
-
642
- static VALUE quic_recv_stop_sending_body(VALUE arg) {
643
- struct quic_stream_cb_args *a = (struct quic_stream_cb_args *)arg;
644
- VALUE stream = quic_conn_lookup_stream(a->c, a->stream_id);
645
- if (NIL_P(stream))
646
- return Qnil;
647
-
648
- quic_stream_t *s;
649
- TypedData_Get_Struct(stream, quic_stream_t, &quic_stream_data_type, s);
650
- s->stop_app_error_code = a->app_error_code;
651
- quic_stream_stop(stream);
652
- return Qnil;
494
+ if (c->handler)
495
+ return quic_handler_stream_reset(c, stream_id, final_size, app_error_code);
496
+ quic_stream_on_reset(stream_user_data, app_error_code);
497
+ return 0;
653
498
  }
654
499
 
655
500
  /* The peer sent STOP_SENDING. ngtcp2 shuts the send side and sends
656
- RESET_STREAM itself once this returns. A stream handler hears of it here
657
- (recv_stop_sending). One built against ABI 1.0 lacks that member, and
658
- learns of it only when #write_pkt finds the send side shut
659
- (stream_shut_write) or the stream closes. */
501
+ RESET_STREAM itself once this returns. */
660
502
  static int quic_recv_stop_sending_cb(ngtcp2_conn *conn, int64_t stream_id,
661
503
  uint64_t app_error_code, void *user_data,
662
504
  void *stream_user_data) {
663
505
  (void)conn;
664
- (void)stream_user_data;
665
506
  quic_conn_t *c = (quic_conn_t *)user_data;
666
- if (c->handler) {
667
- if (!QUIC_EXT_HANDLER_HAS(c->handler, recv_stop_sending))
668
- return 0;
669
- return c->handler->recv_stop_sending(c->handler_ud, stream_id,
670
- app_error_code) < 0
671
- ? NGTCP2_ERR_CALLBACK_FAILURE
672
- : 0;
673
- }
674
- struct quic_stream_cb_args a = {
675
- .c = c, .stream_id = stream_id, .app_error_code = app_error_code};
676
- return quic_conn_protect(c, quic_recv_stop_sending_body, &a);
507
+ if (c->handler)
508
+ return quic_handler_recv_stop_sending(c, stream_id, app_error_code);
509
+ quic_stream_on_recv_stop_sending(c, stream_user_data, app_error_code);
510
+ return 0;
677
511
  }
678
512
 
679
513
  /* The callbacks below matter only to a stream handler. Without one, the
@@ -761,142 +595,6 @@ void quic_conn_fill_common_callbacks(ngtcp2_callbacks *callbacks) {
761
595
  callbacks->handshake_completed = quic_handshake_completed_cb;
762
596
  }
763
597
 
764
- /* Find the first stream in @streams, stopped ones aside, that has either
765
- pending bytes or a pending FIN to flush. Phase 4 minimum: linear scan,
766
- take the first match (no round-robin). Sets *out_datav to the byte slice
767
- to send, *out_datavcnt to 0 or 1, *out_flags to
768
- NGTCP2_WRITE_STREAM_FLAG_FIN when applicable. Returns the stream's Ruby
769
- VALUE (or Qnil if no candidate). */
770
- static VALUE quic_conn_pick_send_stream(VALUE self, ngtcp2_vec *out_datav,
771
- size_t *out_datavcnt,
772
- uint32_t *out_flags,
773
- int64_t *out_stream_id) {
774
- VALUE streams = rb_ivar_get(self, rb_intern("@streams"));
775
- VALUE stream_values = rb_funcall(streams, rb_intern("values"), 0);
776
-
777
- for (long i = 0; i < RARRAY_LEN(stream_values); i++) {
778
- VALUE st = RARRAY_AREF(stream_values, i);
779
- quic_stream_t *s;
780
- TypedData_Get_Struct(st, quic_stream_t, &quic_stream_data_type, s);
781
- if (s->fin_flushed || s->stopped)
782
- continue;
783
-
784
- VALUE pending = rb_ivar_get(st, rb_intern("@pending_chunks"));
785
- uint64_t position = s->sent_offset - s->pending_shifted;
786
- long chunks_count = RARRAY_LEN(pending);
787
-
788
- /* Walk pending Chunks to find the one containing the next unsent byte. */
789
- long chunk_idx = -1;
790
- long offset_in_chunk = 0;
791
- for (long j = 0; j < chunks_count; j++) {
792
- VALUE chunk = RARRAY_AREF(pending, j);
793
- long clen = RSTRING_LEN(chunk);
794
- if (position < (uint64_t)clen) {
795
- chunk_idx = j;
796
- offset_in_chunk = (long)position;
797
- break;
798
- }
799
- position -= (uint64_t)clen;
800
- }
801
-
802
- if (chunk_idx >= 0) {
803
- VALUE chunk = RARRAY_AREF(pending, chunk_idx);
804
- out_datav->base = (uint8_t *)RSTRING_PTR(chunk) + offset_in_chunk;
805
- out_datav->len = (size_t)(RSTRING_LEN(chunk) - offset_in_chunk);
806
- *out_datavcnt = 1;
807
- *out_stream_id = s->stream_id;
808
- /* Attach FIN if this is the LAST chunk and we're going to send all
809
- remaining bytes of it (ngtcp2 may encode less, in which case FIN
810
- won't actually be flushed and we'll retry next call). */
811
- *out_flags = (s->fin_sent && chunk_idx == chunks_count - 1)
812
- ? NGTCP2_WRITE_STREAM_FLAG_FIN
813
- : 0;
814
- return st;
815
- }
816
-
817
- if (s->fin_sent && !s->fin_flushed) {
818
- /* No data to send but a pending FIN-only frame. */
819
- out_datav->base = NULL;
820
- out_datav->len = 0;
821
- *out_datavcnt = 0;
822
- *out_stream_id = s->stream_id;
823
- *out_flags = NGTCP2_WRITE_STREAM_FLAG_FIN;
824
- return st;
825
- }
826
- }
827
-
828
- return Qnil;
829
- }
830
-
831
- /* #write_pkt for the QUIC::Stream mode. If any stream has pending bytes or
832
- a pending FIN, route the packet through ngtcp2_conn_writev_stream so the
833
- stream data gets framed alongside connection-level frames. Falls back to
834
- conn-only when no stream is queued. Returns what ngtcp2 returned. */
835
- static ngtcp2_ssize quic_conn_write_pkt_streams(VALUE self, quic_conn_t *c,
836
- ngtcp2_path *path,
837
- ngtcp2_pkt_info *pi,
838
- uint8_t *dest, size_t destlen) {
839
- ngtcp2_vec datav;
840
- size_t datavcnt = 0;
841
- uint32_t writev_flags = 0;
842
- int64_t send_stream_id = -1;
843
- VALUE selected_stream = quic_conn_pick_send_stream(
844
- self, &datav, &datavcnt, &writev_flags, &send_stream_id);
845
-
846
- ngtcp2_ssize pdatalen = -1;
847
- ngtcp2_ssize n = ngtcp2_conn_writev_stream(
848
- c->conn, path, pi, dest, destlen, &pdatalen, writev_flags, send_stream_id,
849
- &datav, datavcnt, c->now);
850
-
851
- if ((n == NGTCP2_ERR_STREAM_DATA_BLOCKED || n == NGTCP2_ERR_STREAM_SHUT_WR) &&
852
- NIL_P(c->pending_exc)) {
853
- /* DATA_BLOCKED: the stream's queued data is beyond what the peer's flow
854
- control lets through right now. Keep it queued; it follows once the
855
- peer extends its window (MAX_STREAM_DATA / MAX_DATA).
856
- SHUT_WR: ngtcp2 shut the stream's send side without recv_stop_sending
857
- marking the stream, as #reset does. What is queued can never go out,
858
- so drop it.
859
- Either way, build the packet without the stream's data, so that ACKs
860
- and other frames still go out. */
861
- if (n == NGTCP2_ERR_STREAM_SHUT_WR)
862
- quic_stream_stop(selected_stream);
863
- selected_stream = Qnil;
864
- datavcnt = 0;
865
- writev_flags = 0;
866
- pdatalen = -1;
867
- n = ngtcp2_conn_writev_stream(c->conn, path, pi, dest, destlen, &pdatalen,
868
- 0, -1, NULL, 0, c->now);
869
- }
870
-
871
- if (n < 0 || !NIL_P(c->pending_exc))
872
- return n;
873
-
874
- /* Update the selected stream's accounting only when we actually sent
875
- bytes. pdatalen >= 0 means ngtcp2 framed that many data bytes into the
876
- packet; if 0, no data was framed (but the packet may still contain ACK
877
- or other frames). */
878
- if (!NIL_P(selected_stream) && pdatalen > 0) {
879
- quic_stream_t *s;
880
- TypedData_Get_Struct(selected_stream, quic_stream_t, &quic_stream_data_type,
881
- s);
882
- s->sent_offset += (uint64_t)pdatalen;
883
- /* FIN is only actually written when all requested data fits in the
884
- frame (see ngtcp2 docs on NGTCP2_WRITE_STREAM_FLAG_FIN). */
885
- if ((writev_flags & NGTCP2_WRITE_STREAM_FLAG_FIN) &&
886
- (size_t)pdatalen == datav.len) {
887
- s->fin_flushed = true;
888
- }
889
- } else if (!NIL_P(selected_stream) && datavcnt == 0 && n > 0 &&
890
- (writev_flags & NGTCP2_WRITE_STREAM_FLAG_FIN)) {
891
- /* FIN-only packet (no data) was successfully written. */
892
- quic_stream_t *s;
893
- TypedData_Get_Struct(selected_stream, quic_stream_t, &quic_stream_data_type,
894
- s);
895
- s->fin_flushed = true;
896
- }
897
- return n;
898
- }
899
-
900
598
  /* The number of vectors #write_pkt asks a stream handler for per packet. */
901
599
  #define QUIC_HANDLER_VECCNT 16
902
600
 
@@ -961,8 +659,8 @@ ngtcp2_ssize quic_conn_write_pkt_raw(VALUE self, quic_conn_t *c,
961
659
  c->now = quic_now();
962
660
  return c->handler ? quic_conn_write_pkt_handler(c, path, &pi, dest,
963
661
  QUIC_WRITE_PKT_BUFLEN)
964
- : quic_conn_write_pkt_streams(self, c, path, &pi, dest,
965
- QUIC_WRITE_PKT_BUFLEN);
662
+ : quic_streams_write_pkt(self, c, path, &pi, dest,
663
+ QUIC_WRITE_PKT_BUFLEN);
966
664
  }
967
665
 
968
666
  static VALUE quic_conn_write_pkt(int argc, VALUE *argv, VALUE self) {
@@ -1172,11 +870,7 @@ static VALUE quic_conn_open_bidi_stream(VALUE self) {
1172
870
  int rv = ngtcp2_conn_open_bidi_stream(c->conn, &stream_id, NULL);
1173
871
  if (rv != 0)
1174
872
  quic_raise_ngtcp2_error(rv);
1175
-
1176
- VALUE stream = quic_stream_new(stream_id, self);
1177
- VALUE streams = rb_ivar_get(self, rb_intern("@streams"));
1178
- rb_hash_aset(streams, LL2NUM(stream_id), stream);
1179
- return stream;
873
+ return quic_stream_open_local(self, c, stream_id);
1180
874
  }
1181
875
 
1182
876
  static VALUE quic_conn_open_uni_stream(VALUE self) {
@@ -1187,39 +881,26 @@ static VALUE quic_conn_open_uni_stream(VALUE self) {
1187
881
  int rv = ngtcp2_conn_open_uni_stream(c->conn, &stream_id, NULL);
1188
882
  if (rv != 0)
1189
883
  quic_raise_ngtcp2_error(rv);
1190
-
1191
- VALUE stream = quic_stream_new(stream_id, self);
1192
- VALUE streams = rb_ivar_get(self, rb_intern("@streams"));
1193
- rb_hash_aset(streams, LL2NUM(stream_id), stream);
1194
- return stream;
1195
- }
1196
-
1197
- /* Send an application CONNECTION_CLOSE (frame type 0x1d) to the peer and
1198
- transition the underlying ngtcp2_conn to the closing period. One UDP
1199
- datagram is written to the bound socket, once: nothing sends it again
1200
- for packets the peer keeps sending (an Endpoint does, for its own
1201
- connections), and #write_pkt raises QUIC::Error::Closed from here on.
1202
- Calling #close on a connection that is already in the closing or
1203
- draining period is a no-op (= returns nil without doing any I/O). */
1204
- static VALUE quic_conn_close_m(int argc, VALUE *argv, VALUE self) {
1205
- VALUE opts = Qnil;
1206
- rb_scan_args(argc, argv, "0:", &opts);
1207
-
1208
- uint64_t error_code = 0;
884
+ return quic_stream_open_local(self, c, stream_id);
885
+ }
886
+
887
+ /* #_close(error_code, reason), behind Pump#close: build an application
888
+ CONNECTION_CLOSE (frame type 0x1d) carrying error_code (nil: 0) and
889
+ reason (nil: none), and transition the underlying ngtcp2_conn to the
890
+ closing period. Returns the packet, for Pump#close to send through the
891
+ bound socket once: nothing sends it again for packets the peer keeps
892
+ sending (an Endpoint does, for its own connections), and #write_pkt
893
+ raises QUIC::Error::Closed from here on. Returns nil when there is
894
+ nothing to send: the connection is already in the closing or draining
895
+ period, it is an Endpoint's, or ngtcp2 could not build the packet. */
896
+ static VALUE quic_conn_close_m(VALUE self, VALUE error_code_v, VALUE reason_v) {
897
+ uint64_t error_code = NIL_P(error_code_v) ? 0 : NUM2ULL(error_code_v);
1209
898
  const uint8_t *reason_ptr = (const uint8_t *)"";
1210
899
  size_t reason_len = 0;
1211
-
1212
- if (!NIL_P(opts)) {
1213
- VALUE error_code_v = rb_hash_aref(opts, ID2SYM(rb_intern("error_code")));
1214
- VALUE reason_v = rb_hash_aref(opts, ID2SYM(rb_intern("reason")));
1215
- if (!NIL_P(error_code_v)) {
1216
- error_code = NUM2ULL(error_code_v);
1217
- }
1218
- if (!NIL_P(reason_v)) {
1219
- Check_Type(reason_v, T_STRING);
1220
- reason_ptr = (const uint8_t *)RSTRING_PTR(reason_v);
1221
- reason_len = (size_t)RSTRING_LEN(reason_v);
1222
- }
900
+ if (!NIL_P(reason_v)) {
901
+ Check_Type(reason_v, T_STRING);
902
+ reason_ptr = (const uint8_t *)RSTRING_PTR(reason_v);
903
+ reason_len = (size_t)RSTRING_LEN(reason_v);
1223
904
  }
1224
905
 
1225
906
  quic_conn_t *c = quic_conn_get(self);
@@ -1244,8 +925,9 @@ static VALUE quic_conn_close_m(int argc, VALUE *argv, VALUE self) {
1244
925
  return Qnil;
1245
926
  }
1246
927
 
1247
- VALUE sock = rb_ivar_get(self, rb_intern("@sock"));
1248
- if (NIL_P(sock)) {
928
+ /* Checked here, not by Pump#close, so that it comes after the cases
929
+ above, which need no socket. */
930
+ if (NIL_P(rb_ivar_get(self, rb_intern("@sock")))) {
1249
931
  rb_raise(rb_eQUICErrorNotBound,
1250
932
  "%" PRIsVALUE "#bind(sock) has not been called",
1251
933
  rb_obj_class(self));
@@ -1288,8 +970,7 @@ static VALUE quic_conn_close_m(int argc, VALUE *argv, VALUE self) {
1288
970
  }
1289
971
 
1290
972
  rb_str_set_len(buffer, n);
1291
- rb_funcall(sock, rb_intern("send"), 2, buffer, INT2NUM(0));
1292
- return Qnil;
973
+ return buffer;
1293
974
  }
1294
975
 
1295
976
  /* Why an Endpoint closed this connection; see quic_conn_t.error. Always nil
@@ -1311,6 +992,8 @@ void quic_conn_define_shared_methods(VALUE klass) {
1311
992
  0);
1312
993
  rb_define_method(klass, "open_bidi_stream", quic_conn_open_bidi_stream, 0);
1313
994
  rb_define_method(klass, "open_uni_stream", quic_conn_open_uni_stream, 0);
1314
- rb_define_method(klass, "close", quic_conn_close_m, -1);
995
+ /* #close itself is Pump's (lib/quic/connection.rb), which sends what
996
+ #_close returns; defining it here would hide Pump's. */
997
+ rb_define_private_method(klass, "_close", quic_conn_close_m, 2);
1315
998
  rb_define_method(klass, "error", quic_conn_error_m, 0);
1316
999
  }