quic 0.0.5 → 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.
data/ext/quic/stream.h CHANGED
@@ -1,27 +1,47 @@
1
1
  #ifndef QUIC_STREAM_H
2
2
  #define QUIC_STREAM_H 1
3
3
 
4
+ #include "connection_common.h"
4
5
  #include "quic.h"
5
6
 
6
7
  extern VALUE rb_cQUICStream;
7
8
 
8
9
  void Init_quic_stream(VALUE rb_mQUICArg);
9
10
 
10
- /* Internal helpers used by connection_common.c stream callbacks and
11
- write_pkt's stream-aware path. */
11
+ /* One write's bytes, kept until the peer acknowledges them. Outside the
12
+ Ruby heap: ngtcp2 keeps pointers into data to retransmit from, and
13
+ GC.compact moves an embedded String. */
14
+ typedef struct quic_send_chunk {
15
+ struct quic_send_chunk *next;
16
+ size_t len;
17
+ uint8_t data[];
18
+ } quic_send_chunk;
12
19
 
13
20
  typedef struct {
21
+ /* The QUIC::Stream wrapping this struct, for the stream callbacks, which
22
+ get the struct from ngtcp2's stream_user_data. It needs no mark, as it
23
+ holds the struct; quic_stream_compact follows it when GC.compact moves
24
+ it. */
25
+ VALUE self;
14
26
  int64_t stream_id;
15
- /* Cumulative bytes handed to ngtcp2 via writev_stream so far. Increases
16
- monotonically; used to derive the next send position within
17
- @pending_chunks. */
18
- uint64_t sent_offset;
19
- /* Cumulative bytes acked by the peer (per acked_stream_data_offset).
20
- Increases monotonically. */
21
- uint64_t acked_offset;
22
- /* Cumulative bytes shifted out of @pending_chunks. Always
23
- <= acked_offset (we only shift a Chunk after its end is acked). */
24
- uint64_t pending_shifted;
27
+ /* The send buffer: what #write queued and the peer has not acknowledged,
28
+ as chunks in stream order. Every offset below is a position in the
29
+ stream. The buffer is freed only where ngtcp2 can no longer read it:
30
+ as the peer acknowledges it, when the stream closes, and in dfree. */
31
+ quic_send_chunk *send_head;
32
+ quic_send_chunk *send_tail;
33
+ /* The chunk holding the next byte to hand to ngtcp2 (sent_offset), and
34
+ where in it; NULL once everything queued has been handed over. That
35
+ chunk ends after sent_offset, which acked_offset never passes, so an
36
+ acknowledgement never frees it. */
37
+ quic_send_chunk *send_next;
38
+ size_t send_next_off;
39
+ uint64_t head_offset; /* where send_head->data[0] sits */
40
+ uint64_t queued_offset; /* just past the last byte queued */
41
+ uint64_t sent_offset; /* just past the last byte handed to ngtcp2 */
42
+ uint64_t acked_offset; /* just past the last byte acknowledged */
43
+ /* What the chunks take from xmalloc, headers included; part of dsize. */
44
+ size_t buffered;
25
45
  bool fin_received; /* recv_stream_data delivered FIN */
26
46
  bool fin_sent; /* #write(fin: true) queued FIN */
27
47
  bool fin_flushed; /* write_pkt actually wrote the FIN frame */
@@ -29,10 +49,13 @@ typedef struct {
29
49
  bool closed; /* stream_close callback fired */
30
50
  uint64_t close_app_error_code;
31
51
  bool close_has_app_error_code;
32
- /* The send side is shut: the peer's STOP_SENDING arrived, or ngtcp2
33
- reported the send side shut while writing. @pending_chunks has been
34
- emptied, so the offsets above no longer describe it, and #write_pkt
35
- skips the stream. */
52
+ /* The send side is shut (quic_stream_stop): the peer's STOP_SENDING
53
+ arrived, #reset was called, ngtcp2 reported the send side shut while
54
+ writing, or the stream closed. Nothing queued goes out any more,
55
+ #write_pkt skips the stream, and what it had not sent no longer counts
56
+ in quic_conn_t.stream_unsent. The send buffer stays until the stream
57
+ closes: ngtcp2 may still hold pointers into it at this point
58
+ (recv_stop_sending runs before it drops the stream's queued frames). */
36
59
  bool stopped;
37
60
  uint64_t stop_app_error_code; /* the STOP_SENDING's, 0 if none arrived */
38
61
  /* Set once a peer-initiated stream has been pushed onto the owning
@@ -46,12 +69,35 @@ typedef struct {
46
69
  bool peer_stream_held;
47
70
  } quic_stream_t;
48
71
 
49
- extern const rb_data_type_t quic_stream_data_type;
72
+ /* What a connection without a stream handler does with its streams, as
73
+ QUIC::Streams. connection_common.c hands its ngtcp2 stream callbacks and
74
+ #write_pkt here, and keeps only the choice between this and the
75
+ handler. */
50
76
 
51
- /* Allocate a new QUIC::Stream Ruby object for stream_id with a
52
- zero-initialized quic_stream_t, and set its ivars (@id / @client /
53
- @pending_chunks / @recv_buffer). @client is owner, the Client or Server
54
- the stream belongs to; the ivar keeps its name for both. */
55
- VALUE quic_stream_new(int64_t stream_id, VALUE owner);
77
+ /* Make a QUIC::Stream for stream_id, a stream #open_bidi_stream or
78
+ #open_uni_stream has just opened on the connection self (wrapping c),
79
+ and register it. Returns the Stream. */
80
+ VALUE quic_stream_open_local(VALUE self, quic_conn_t *c, int64_t stream_id);
81
+
82
+ /* The ngtcp2 stream callbacks. s is the stream's stream_user_data: NULL for
83
+ a stream whose QUIC::Stream could not be made, which they ignore. Those
84
+ returning int return 0, or NGTCP2_ERR_CALLBACK_FAILURE when Ruby code
85
+ raised; the exception waits in c->pending_exc. */
86
+ int quic_stream_on_open(quic_conn_t *c, int64_t stream_id);
87
+ int quic_stream_on_recv_data(quic_conn_t *c, quic_stream_t *s, uint32_t flags,
88
+ const uint8_t *data, size_t datalen);
89
+ void quic_stream_on_acked(quic_stream_t *s, uint64_t offset, uint64_t datalen);
90
+ int quic_stream_on_close(quic_conn_t *c, quic_stream_t *s, int64_t stream_id,
91
+ uint32_t flags, uint64_t app_error_code);
92
+ void quic_stream_on_reset(quic_stream_t *s, uint64_t app_error_code);
93
+ void quic_stream_on_recv_stop_sending(quic_conn_t *c, quic_stream_t *s,
94
+ uint64_t app_error_code);
95
+
96
+ /* #write_pkt for the connection self (wrapping c): build the next packet
97
+ into dest, with data from the first stream in @streams that has any.
98
+ Returns what ngtcp2_conn_writev_stream returned. Raises nothing. */
99
+ ngtcp2_ssize quic_streams_write_pkt(VALUE self, quic_conn_t *c,
100
+ ngtcp2_path *path, ngtcp2_pkt_info *pi,
101
+ uint8_t *dest, size_t destlen);
56
102
 
57
103
  #endif /* QUIC_STREAM_H */
@@ -108,6 +108,17 @@ module QUIC
108
108
  stream
109
109
  end
110
110
 
111
+ # Send an application CONNECTION_CLOSE carrying error_code and reason and
112
+ # enter the closing period. Raises QUIC::Error::NotBound unless #bind was
113
+ # called, except on a connection an Endpoint made, whose CONNECTION_CLOSE
114
+ # goes out through Endpoint#write_pkt. A no-op once the connection is
115
+ # closing or draining.
116
+ def close(error_code: 0, reason: nil)
117
+ packet = _close(error_code, reason)
118
+ @sock.send(packet, 0) if packet
119
+ nil
120
+ end
121
+
111
122
  private
112
123
 
113
124
  # A C stream handler (quic/ext.h) registered on the connection owns
data/lib/quic/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module QUIC
4
- VERSION = "0.0.5"
4
+ VERSION = "0.0.7"
5
5
  end
data/sig/quic.rbs CHANGED
@@ -321,21 +321,23 @@ module QUIC
321
321
 
322
322
  # Blocks (by internally calling #pump_once on the owning Client or
323
323
  # Server) until the peer's flow control window has room for the full
324
- # payload, then queues all bytes and returns data.bytesize. Requires the
325
- # owning connection to be bound to a socket via #bind; raises
326
- # QUIC::Error::NotBound otherwise. Raises QUIC::Error::StreamClosed,
327
- # while waiting too, once the stream has been reset or closed, or the
328
- # peer has sent STOP_SENDING. STOP_SENDING also drops what was queued
329
- # but not yet sent.
324
+ # payload, then queues all bytes and returns data.bytesize. The window is
325
+ # the smaller of the stream's and the connection's, and the connection's
326
+ # is shared with what the other streams of the connection have queued
327
+ # but not yet sent. Requires the owning connection to be bound to a
328
+ # socket via #bind; raises QUIC::Error::NotBound otherwise. Raises
329
+ # QUIC::Error::StreamClosed, while waiting too, once the stream has been
330
+ # reset or closed, or the peer has sent STOP_SENDING. STOP_SENDING also
331
+ # drops what was queued but not yet sent.
330
332
  def write: (String data, ?fin: bool) -> Integer
331
333
 
332
334
  # Non-blocking variant. Queues as much of `data` as the current flow
333
- # control window allows and returns the byte count actually queued.
334
- # Raises QUIC::Error::WaitWritable (mixed in with IO::WaitWritable) when
335
- # the window is zero and the payload is non-empty, and
336
- # QUIC::Error::StreamClosed as #write does. If only a partial prefix is
337
- # accepted, `fin: true` is NOT propagated; the caller must re-issue with
338
- # `fin: true` on the trailing chunk.
335
+ # control window (see #write) allows and returns the byte count actually
336
+ # queued. Raises QUIC::Error::WaitWritable (mixed in with
337
+ # IO::WaitWritable) when the window is zero and the payload is non-empty,
338
+ # and QUIC::Error::StreamClosed as #write does. If only a partial prefix
339
+ # is accepted, `fin: true` is NOT propagated; the caller must re-issue
340
+ # with `fin: true` on the trailing chunk.
339
341
  def write_nonblock: (String data, ?fin: bool) -> Integer
340
342
  def eof?: () -> bool
341
343
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yusuke Nakamura
@@ -93,14 +93,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: 3.2.0
96
+ version: '0'
97
97
  required_rubygems_version: !ruby/object:Gem::Requirement
98
98
  requirements:
99
99
  - - ">="
100
100
  - !ruby/object:Gem::Version
101
101
  version: '0'
102
102
  requirements: []
103
- rubygems_version: 4.0.16
103
+ rubygems_version: 4.0.20
104
104
  specification_version: 4
105
105
  summary: Thin Ruby binding around ngtcp2 for the QUIC transport protocol, using picotls
106
106
  for TLS 1.3 over the system OpenSSL.