diff --git a/examples/client.cc b/examples/client.cc index b482d034ecd9f6858a1a169e54cb9220abfc9efd..f2c444299d37b3381ad8f49805b1a6785f90c421 100644 --- a/examples/client.cc +++ b/examples/client.cc @@ -479,7 +479,7 @@ int recv_crypto_data(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, } // namespace namespace { -int recv_stream_data(ngtcp2_conn *conn, int64_t stream_id, int fin, +int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, uint64_t offset, const uint8_t *data, size_t datalen, void *user_data, void *stream_user_data) { if (!config.quiet && !config.no_quic_dump) { @@ -488,7 +488,7 @@ int recv_stream_data(ngtcp2_conn *conn, int64_t stream_id, int fin, auto c = static_cast<Client *>(user_data); - if (c->recv_stream_data(stream_id, fin, data, datalen) != 0) { + if (c->recv_stream_data(flags, stream_id, data, datalen) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -1682,10 +1682,10 @@ int Client::submit_http_request(const Stream *stream) { return 0; } -int Client::recv_stream_data(int64_t stream_id, int fin, const uint8_t *data, - size_t datalen) { - auto nconsumed = - nghttp3_conn_read_stream(httpconn_, stream_id, data, datalen, fin); +int Client::recv_stream_data(uint32_t flags, int64_t stream_id, + const uint8_t *data, size_t datalen) { + auto nconsumed = nghttp3_conn_read_stream( + httpconn_, stream_id, data, datalen, flags & NGTCP2_STREAM_DATA_FLAG_FIN); if (nconsumed < 0) { std::cerr << "nghttp3_conn_read_stream: " << nghttp3_strerror(nconsumed) << std::endl; diff --git a/examples/client.h b/examples/client.h index e84434ad5fb337db0f92f7f7c643f0ca64804b47..f1b4a92e857db4a891b1b65fd07edb6cb7f56c4a 100644 --- a/examples/client.h +++ b/examples/client.h @@ -249,7 +249,7 @@ public: int setup_httpconn(); int submit_http_request(const Stream *stream); - int recv_stream_data(int64_t stream_id, int fin, const uint8_t *data, + int recv_stream_data(uint32_t flags, int64_t stream_id, const uint8_t *data, size_t datalen); int acked_stream_data_offset(int64_t stream_id, uint64_t datalen); int http_acked_stream_data(int64_t stream_id, size_t datalen); diff --git a/examples/server.cc b/examples/server.cc index 70aa4daeb4aa92905f3546df5651dc3b98a19240..97d512650a0042427e06397e3e4a60799f2c7923 100644 --- a/examples/server.cc +++ b/examples/server.cc @@ -882,12 +882,12 @@ int recv_crypto_data(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, } // namespace namespace { -int recv_stream_data(ngtcp2_conn *conn, int64_t stream_id, int fin, +int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, uint64_t offset, const uint8_t *data, size_t datalen, void *user_data, void *stream_user_data) { auto h = static_cast<Handler *>(user_data); - if (h->recv_stream_data(stream_id, fin, data, datalen) != 0) { + if (h->recv_stream_data(flags, stream_id, data, datalen) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -1966,7 +1966,7 @@ void Handler::schedule_retransmit() { ev_timer_again(loop_, &rttimer_); } -int Handler::recv_stream_data(int64_t stream_id, uint8_t fin, +int Handler::recv_stream_data(uint32_t flags, int64_t stream_id, const uint8_t *data, size_t datalen) { if (!config.quiet && !config.no_quic_dump) { debug::print_stream_data(stream_id, data, datalen); @@ -1976,8 +1976,8 @@ int Handler::recv_stream_data(int64_t stream_id, uint8_t fin, return 0; } - auto nconsumed = - nghttp3_conn_read_stream(httpconn_, stream_id, data, datalen, fin); + auto nconsumed = nghttp3_conn_read_stream( + httpconn_, stream_id, data, datalen, flags & NGTCP2_STREAM_DATA_FLAG_FIN); if (nconsumed < 0) { std::cerr << "nghttp3_conn_read_stream: " << nghttp3_strerror(nconsumed) << std::endl; diff --git a/examples/server.h b/examples/server.h index 710d34011fa7889fad6bdac738aa9370fd41bdf2..9954ca4c6bbaa1ed772baa45274b5fa141893a12 100644 --- a/examples/server.h +++ b/examples/server.h @@ -242,7 +242,7 @@ public: Server *server() const; const Address &remote_addr() const; ngtcp2_conn *conn() const; - int recv_stream_data(int64_t stream_id, uint8_t fin, const uint8_t *data, + int recv_stream_data(uint32_t flags, int64_t stream_id, const uint8_t *data, size_t datalen); int acked_stream_data_offset(int64_t stream_id, uint64_t datalen); const ngtcp2_cid *scid() const; diff --git a/lib/includes/ngtcp2/ngtcp2.h b/lib/includes/ngtcp2/ngtcp2.h index fa077b4b2a504133a72b0033012168a69cbc50ec..c112776bdd6a29df2b8854fcfbb795e13a363b61 100644 --- a/lib/includes/ngtcp2/ngtcp2.h +++ b/lib/includes/ngtcp2/ngtcp2.h @@ -1261,23 +1261,46 @@ typedef int (*ngtcp2_decrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead, typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp, const uint8_t *hp_key, const uint8_t *sample); +/** + * @enum + * + * ngtcp2_stream_data_flag defines the properties of the data emitted + * via :type:`ngtcp2_recv_stream_data` callback function. + */ +typedef enum ngtcp2_stream_data_flag { + NGTCP2_STREAM_DATA_FLAG_NONE = 0x00, + /** + * NGTCP2_STREAM_DATA_FLAG_FIN indicates that this chunk of data is + * final piece of an incoming stream. + */ + NGTCP2_STREAM_DATA_FLAG_FIN = 0x01, + /** + * NGTCP2_STREAM_DATA_FLAG_0RTT indicates that this chunk of data + * contains data received in 0RTT packet and the handshake has not + * been completed yet, which means that the data might be replayed. + */ + NGTCP2_STREAM_DATA_FLAG_0RTT = 0x02 +} ngtcp2_stream_data_flag; + /** * @functypedef * * :type:`ngtcp2_recv_stream_data` is invoked when stream data is - * received. The stream is specified by |stream_id|. If |fin| is - * nonzero, this portion of the data is the last data in this stream. - * |offset| is the offset where this data begins. The library ensures - * that data is passed to the application in the non-decreasing order - * of |offset|. The data is passed as |data| of length |datalen|. - * |datalen| may be 0 if and only if |fin| is nonzero. + * received. The stream is specified by |stream_id|. |flags| is the + * bitwise-OR of zero or more of ngtcp2_stream_data_flag. If |flags| + * & :enum:`NGTCP2_STREAM_DATA_FLAG_FIN` is nonzero, this portion of + * the data is the last data in this stream. |offset| is the offset + * where this data begins. The library ensures that data is passed to + * the application in the non-decreasing order of |offset|. The data + * is passed as |data| of length |datalen|. |datalen| may be 0 if and + * only if |fin| is nonzero. * * The callback function must return 0 if it succeeds, or * :enum:`NGTCP2_ERR_CALLBACK_FAILURE` which makes the library return * immediately. */ -typedef int (*ngtcp2_recv_stream_data)(ngtcp2_conn *conn, int64_t stream_id, - int fin, uint64_t offset, +typedef int (*ngtcp2_recv_stream_data)(ngtcp2_conn *conn, uint32_t flags, + int64_t stream_id, uint64_t offset, const uint8_t *data, size_t datalen, void *user_data, void *stream_user_data); diff --git a/lib/ngtcp2_conn.c b/lib/ngtcp2_conn.c index 3cf43d17c04872fda5fd46867d45169d0f925429..1e6da73b1f4c6cd91d5ca4635107102c5b995a33 100644 --- a/lib/ngtcp2_conn.c +++ b/lib/ngtcp2_conn.c @@ -81,7 +81,7 @@ static int conn_call_handshake_completed(ngtcp2_conn *conn) { } static int conn_call_recv_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, - int fin, uint64_t offset, + uint32_t flags, uint64_t offset, const uint8_t *data, size_t datalen) { int rv; @@ -89,7 +89,7 @@ static int conn_call_recv_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, return 0; } - rv = conn->callbacks.recv_stream_data(conn, strm->stream_id, fin, offset, + rv = conn->callbacks.recv_stream_data(conn, flags, strm->stream_id, offset, data, datalen, conn->user_data, strm->stream_user_data); if (rv != 0) { @@ -4873,6 +4873,8 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, const uint8_t *data; int rv; uint64_t offset; + uint32_t sdflags; + int handshake_completed = conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED; for (;;) { /* Stop calling callback if application has called @@ -4891,10 +4893,16 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, offset = rx_offset; rx_offset += datalen; - rv = conn_call_recv_stream_data(conn, strm, - (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) && - rx_offset == strm->rx.last_offset, - offset, data, datalen); + sdflags = NGTCP2_STREAM_DATA_FLAG_NONE; + if ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) && + rx_offset == strm->rx.last_offset) { + sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN; + } + if (!handshake_completed) { + sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT; + } + + rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data, datalen); if (rv != 0) { return rv; } @@ -5054,6 +5062,7 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr, int local_stream; int bidi; size_t datalen = ngtcp2_vec_len(fr->data, fr->datacnt); + uint32_t sdflags = NGTCP2_STREAM_DATA_FLAG_NONE; local_stream = conn_local_stream(conn, fr->stream_id); bidi = bidi_stream(fr->stream_id); @@ -5167,7 +5176,8 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr, } if (fr_end_offset == rx_offset) { - rv = conn_call_recv_stream_data(conn, strm, 1, rx_offset, NULL, 0); + rv = conn_call_recv_stream_data(conn, strm, NGTCP2_STREAM_DATA_FLAG_FIN, + rx_offset, NULL, 0); if (rv != 0) { return rv; } @@ -5219,7 +5229,14 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr, rx_offset == strm->rx.last_offset; if (fin || datalen) { - rv = conn_call_recv_stream_data(conn, strm, fin, offset, data, datalen); + if (fin) { + sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN; + } + if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { + sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT; + } + rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data, + datalen); if (rv != 0) { return rv; } diff --git a/tests/ngtcp2_conn_test.c b/tests/ngtcp2_conn_test.c index dbc96bce2a72aa745ce17d74e4d3464ea1c9c28a..5ab7f6a97bda6ecc7b087cd05bc74c53040fac0a 100644 --- a/tests/ngtcp2_conn_test.c +++ b/tests/ngtcp2_conn_test.c @@ -134,7 +134,7 @@ typedef struct { recv_stream_data callback. */ struct { int64_t stream_id; - int fin; + uint32_t flags; size_t datalen; } stream_data; } my_user_data; @@ -281,10 +281,10 @@ static int recv_crypto_data_server(ngtcp2_conn *conn, return 0; } -static int recv_stream_data(ngtcp2_conn *conn, int64_t stream_id, int fin, - uint64_t offset, const uint8_t *data, - size_t datalen, void *user_data, - void *stream_user_data) { +static int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, + int64_t stream_id, uint64_t offset, + const uint8_t *data, size_t datalen, + void *user_data, void *stream_user_data) { my_user_data *ud = user_data; (void)conn; (void)offset; @@ -293,7 +293,7 @@ static int recv_stream_data(ngtcp2_conn *conn, int64_t stream_id, int fin, if (ud) { ud->stream_data.stream_id = stream_id; - ud->stream_data.fin = fin; + ud->stream_data.flags = flags; ud->stream_data.datalen = datalen; } @@ -301,13 +301,13 @@ static int recv_stream_data(ngtcp2_conn *conn, int64_t stream_id, int fin, } static int -recv_stream_data_shutdown_stream_read(ngtcp2_conn *conn, int64_t stream_id, - int fin, uint64_t offset, +recv_stream_data_shutdown_stream_read(ngtcp2_conn *conn, uint32_t flags, + int64_t stream_id, uint64_t offset, const uint8_t *data, size_t datalen, void *user_data, void *stream_user_data) { int rv; - recv_stream_data(conn, stream_id, fin, offset, data, datalen, user_data, + recv_stream_data(conn, flags, stream_id, offset, data, datalen, user_data, stream_user_data); rv = ngtcp2_conn_shutdown_stream_read(conn, stream_id, NGTCP2_APP_ERR01); @@ -2789,7 +2789,8 @@ void test_ngtcp2_conn_recv_stream_data(void) { CU_ASSERT(0 == rv); CU_ASSERT(4 == ud.stream_data.stream_id); - CU_ASSERT(0 == ud.stream_data.fin); + CU_ASSERT(!(ud.stream_data.flags & NGTCP2_STREAM_DATA_FLAG_FIN)); + CU_ASSERT(!(ud.stream_data.flags & NGTCP2_STREAM_DATA_FLAG_0RTT)); CU_ASSERT(111 == ud.stream_data.datalen); fr.type = NGTCP2_FRAME_STREAM; @@ -2808,7 +2809,7 @@ void test_ngtcp2_conn_recv_stream_data(void) { CU_ASSERT(0 == rv); CU_ASSERT(4 == ud.stream_data.stream_id); - CU_ASSERT(1 == ud.stream_data.fin); + CU_ASSERT(ud.stream_data.flags & NGTCP2_STREAM_DATA_FLAG_FIN); CU_ASSERT(99 == ud.stream_data.datalen); ngtcp2_conn_del(conn); @@ -2835,7 +2836,7 @@ void test_ngtcp2_conn_recv_stream_data(void) { CU_ASSERT(0 == rv); CU_ASSERT(4 == ud.stream_data.stream_id); - CU_ASSERT(0 == ud.stream_data.fin); + CU_ASSERT(!(ud.stream_data.flags & NGTCP2_STREAM_DATA_FLAG_FIN)); CU_ASSERT(111 == ud.stream_data.datalen); fr.type = NGTCP2_FRAME_STREAM; @@ -2852,7 +2853,7 @@ void test_ngtcp2_conn_recv_stream_data(void) { CU_ASSERT(0 == rv); CU_ASSERT(4 == ud.stream_data.stream_id); - CU_ASSERT(1 == ud.stream_data.fin); + CU_ASSERT(ud.stream_data.flags & NGTCP2_STREAM_DATA_FLAG_FIN); CU_ASSERT(0 == ud.stream_data.datalen); ngtcp2_conn_del(conn); @@ -2880,7 +2881,7 @@ void test_ngtcp2_conn_recv_stream_data(void) { CU_ASSERT(0 == rv); CU_ASSERT(4 == ud.stream_data.stream_id); - CU_ASSERT(1 == ud.stream_data.fin); + CU_ASSERT(ud.stream_data.flags & NGTCP2_STREAM_DATA_FLAG_FIN); CU_ASSERT(111 == ud.stream_data.datalen); pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->oscid, @@ -2891,7 +2892,7 @@ void test_ngtcp2_conn_recv_stream_data(void) { CU_ASSERT(0 == rv); CU_ASSERT(0 == ud.stream_data.stream_id); - CU_ASSERT(0 == ud.stream_data.fin); + CU_ASSERT(!(ud.stream_data.flags & NGTCP2_STREAM_DATA_FLAG_FIN)); CU_ASSERT(0 == ud.stream_data.datalen); ngtcp2_conn_del(conn); @@ -2933,7 +2934,7 @@ void test_ngtcp2_conn_recv_stream_data(void) { CU_ASSERT(0 == rv); CU_ASSERT(4 == ud.stream_data.stream_id); - CU_ASSERT(1 == ud.stream_data.fin); + CU_ASSERT(ud.stream_data.flags & NGTCP2_STREAM_DATA_FLAG_FIN); CU_ASSERT(599 == ud.stream_data.datalen); ngtcp2_conn_del(conn); @@ -2976,7 +2977,7 @@ void test_ngtcp2_conn_recv_stream_data(void) { CU_ASSERT(0 == rv); CU_ASSERT(4 == ud.stream_data.stream_id); - CU_ASSERT(1 == ud.stream_data.fin); + CU_ASSERT(ud.stream_data.flags & NGTCP2_STREAM_DATA_FLAG_FIN); CU_ASSERT(599 == ud.stream_data.datalen); ngtcp2_conn_del(conn); @@ -3002,7 +3003,7 @@ void test_ngtcp2_conn_recv_stream_data(void) { CU_ASSERT(0 == rv); CU_ASSERT(3 == ud.stream_data.stream_id); - CU_ASSERT(0 == ud.stream_data.fin); + CU_ASSERT(!(ud.stream_data.flags & NGTCP2_STREAM_DATA_FLAG_FIN)); CU_ASSERT(911 == ud.stream_data.datalen); ngtcp2_conn_del(conn); @@ -3255,7 +3256,7 @@ void test_ngtcp2_conn_recv_stream_data(void) { CU_ASSERT(0 == rv); CU_ASSERT(4 == ud.stream_data.stream_id); - CU_ASSERT(0 == ud.stream_data.fin); + CU_ASSERT(!(ud.stream_data.flags & NGTCP2_STREAM_DATA_FLAG_FIN)); CU_ASSERT(599 == ud.stream_data.datalen); ngtcp2_conn_del(conn); @@ -3515,10 +3516,13 @@ void test_ngtcp2_conn_recv_early_data(void) { ngtcp2_strm *strm; ngtcp2_cid rcid; int rv; + my_user_data ud; rcid_init(&rcid); setup_early_server(&conn); + conn->callbacks.recv_stream_data = recv_stream_data; + conn->user_data = &ud; fr.type = NGTCP2_FRAME_CRYPTO; fr.crypto.offset = 0; @@ -3551,9 +3555,12 @@ void test_ngtcp2_conn_recv_early_data(void) { conn->version, &fr, null_key, null_iv, null_hp_key, sizeof(null_key), sizeof(null_iv)); + memset(&ud, 0, sizeof(ud)); rv = ngtcp2_conn_read_pkt(conn, &null_path, buf, pktlen, ++t); CU_ASSERT(0 == rv); + CU_ASSERT(4 == ud.stream_data.stream_id); + CU_ASSERT(ud.stream_data.flags & NGTCP2_STREAM_DATA_FLAG_0RTT); spktlen = ngtcp2_conn_write_pkt(conn, NULL, buf, sizeof(buf), ++t);