diff --git a/examples/client.cc b/examples/client.cc index 95380b77751e48c2930441489a549d401181d98d..86174e73759984dda3f305c8d75c4445ee4ad507 100644 --- a/examples/client.cc +++ b/examples/client.cc @@ -499,7 +499,7 @@ int recv_crypto_data(ngtcp2_conn *conn, uint64_t offset, const uint8_t *data, } // namespace namespace { -int recv_stream_data(ngtcp2_conn *conn, uint64_t stream_id, uint8_t fin, +int recv_stream_data(ngtcp2_conn *conn, uint64_t stream_id, int fin, uint64_t offset, const uint8_t *data, size_t datalen, void *user_data, void *stream_user_data) { if (!config.quiet) { diff --git a/examples/server.cc b/examples/server.cc index ca0df29267704db63fa4b2becf3edb9c6601a139..a42d35dc2fd2e397be0661bd99287ad6be73137f 100644 --- a/examples/server.cc +++ b/examples/server.cc @@ -869,7 +869,7 @@ int recv_crypto_data(ngtcp2_conn *conn, uint64_t offset, const uint8_t *data, } // namespace namespace { -int recv_stream_data(ngtcp2_conn *conn, uint64_t stream_id, uint8_t fin, +int recv_stream_data(ngtcp2_conn *conn, uint64_t stream_id, int fin, uint64_t offset, const uint8_t *data, size_t datalen, void *user_data, void *stream_user_data) { auto h = static_cast<Handler *>(user_data); diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 683b31e045baf3db774505dab1affe71b59724ba..288332fc1959979530d0b928eed3f6ddf0bc376a 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -35,6 +35,7 @@ set(ngtcp2_SOURCES ngtcp2_pkt.c ngtcp2_conv.c ngtcp2_str.c + ngtcp2_vec.c ngtcp2_buf.c ngtcp2_conn.c ngtcp2_mem.c diff --git a/lib/Makefile.am b/lib/Makefile.am index a4a3e1afcbf0e9e101c357503443b874e206dab5..2521ebd10f313e5809a0d5673300d18aac6ec295 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -35,6 +35,7 @@ OBJECTS = \ ngtcp2_pkt.c \ ngtcp2_conv.c \ ngtcp2_str.c \ + ngtcp2_vec.c \ ngtcp2_buf.c \ ngtcp2_conn.c \ ngtcp2_mem.c \ @@ -60,6 +61,7 @@ HFILES = \ ngtcp2_pkt.h \ ngtcp2_conv.h \ ngtcp2_str.h \ + ngtcp2_vec.h \ ngtcp2_buf.h \ ngtcp2_conn.h \ ngtcp2_mem.h \ diff --git a/lib/includes/ngtcp2/ngtcp2.h b/lib/includes/ngtcp2/ngtcp2.h index 1faa722d067ba5a4efce8894312a190477c14449..f410819f1144f597d3e1fe31d4f9158db8f2ef1f 100644 --- a/lib/includes/ngtcp2/ngtcp2.h +++ b/lib/includes/ngtcp2/ngtcp2.h @@ -374,8 +374,12 @@ typedef struct { uint8_t fin; uint64_t stream_id; uint64_t offset; - size_t datalen; - const uint8_t *data; + /* datacnt is the number of elements that data contains. Although + the length of data is 1 in this definition, the library may + allocate extra bytes to hold more elements. */ + size_t datacnt; + /* data is the array of ngtcp2_vec which references data. */ + ngtcp2_vec data[1]; } ngtcp2_stream; typedef struct { @@ -1027,7 +1031,7 @@ typedef ssize_t (*ngtcp2_encrypt_pn)(ngtcp2_conn *conn, uint8_t *dest, size_t noncelen, void *user_data); typedef int (*ngtcp2_recv_stream_data)(ngtcp2_conn *conn, uint64_t stream_id, - uint8_t fin, uint64_t offset, + int fin, 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 c414f46889615cef81dcb66ed83feebae5708ad3..37d37c00e11a713f8d6e51fe731b91cdc7f8d096 100644 --- a/lib/ngtcp2_conn.c +++ b/lib/ngtcp2_conn.c @@ -33,6 +33,7 @@ #include "ngtcp2_log.h" #include "ngtcp2_cid.h" #include "ngtcp2_conv.h" +#include "ngtcp2_vec.h" /* * conn_local_stream returns nonzero if |stream_id| indicates that it @@ -78,7 +79,7 @@ static int conn_call_handshake_completed(ngtcp2_conn *conn) { } static int conn_call_recv_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, - uint8_t fin, uint64_t offset, + int fin, uint64_t offset, const uint8_t *data, size_t datalen) { int rv; @@ -170,6 +171,17 @@ static int pktns_init(ngtcp2_pktns *pktns, int delayed_ack, ngtcp2_cc_stat *ccs, return 0; } +static int cycle_less(const ngtcp2_pq_entry *lhs, const ngtcp2_pq_entry *rhs) { + ngtcp2_strm *ls = ngtcp2_struct_of(lhs, ngtcp2_strm, pe); + ngtcp2_strm *rs = ngtcp2_struct_of(rhs, ngtcp2_strm, pe); + + if (ls->cycle < rs->cycle) { + return rs->cycle - ls->cycle <= 1; + } + + return ls->cycle - rs->cycle > 1; +} + static void pktns_free(ngtcp2_pktns *pktns, ngtcp2_mem *mem) { ngtcp2_frame_chain_list_del(pktns->frq, mem); @@ -206,6 +218,8 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, goto fail_strms_init; } + ngtcp2_pq_init(&(*pconn)->tx_strmq, cycle_less, mem); + rv = ngtcp2_idtr_init(&(*pconn)->remote_bidi_idtr, !server, mem); if (rv != 0) { goto fail_remote_bidi_idtr_init; @@ -380,6 +394,7 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) { ngtcp2_idtr_free(&conn->remote_uni_idtr); ngtcp2_idtr_free(&conn->remote_bidi_idtr); + ngtcp2_pq_free(&conn->tx_strmq); ngtcp2_map_each_free(&conn->strms, delete_strms_each, conn->mem); ngtcp2_map_free(&conn->strms); @@ -659,7 +674,8 @@ static size_t conn_retry_early_payloadlen(ngtcp2_conn *conn) { for (frc = conn->pktns.frq; frc; frc = frc->next) { assert(frc->fr.type == NGTCP2_FRAME_STREAM); - len += 1 /* Type */ + frc->fr.stream.datalen + + len += 1 /* Type */ + + ngtcp2_vec_len(frc->fr.stream.data, frc->fr.stream.datacnt) + 8 * 3 /* Stream ID, Offset, and Length */; } @@ -705,45 +721,6 @@ static int conn_split_crypto_frame(ngtcp2_conn *conn, ngtcp2_frame_chain **pfrc, return 0; } -/* - * conn_split_stream_frame splits a STREAM frame (*pfrc)->fr.stream if - * the length of payload is more then |left|. The new - * ngtcp2_frame_chain is inserted after the first item pointed by - * |*pfrc|. - */ -static int conn_split_stream_frame(ngtcp2_conn *conn, ngtcp2_frame_chain **pfrc, - size_t left) { - ngtcp2_stream *fr = &(*pfrc)->fr.stream, *nfr; - ngtcp2_frame_chain *nfrc; - int rv; - - if (fr->datalen <= left) { - return 0; - } - - rv = ngtcp2_frame_chain_new(&nfrc, conn->mem); - if (rv != 0) { - return rv; - } - - nfr = &nfrc->fr.stream; - nfr->type = NGTCP2_FRAME_STREAM; - nfr->flags = 0; - nfr->fin = fr->fin; - nfr->stream_id = fr->stream_id; - nfr->offset = fr->offset + left; - nfr->datalen = fr->datalen - left; - nfr->data = fr->data + left; - - fr->datalen = left; - fr->fin = 0; - - nfrc->next = (*pfrc)->next; - (*pfrc)->next = nfrc; - - return 0; -} - /* * conn_write_handshake_pkt writes handshake packet in the buffer * pointed by |dest| whose length is |destlen|. |type| specifies long @@ -766,7 +743,9 @@ static ssize_t conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest, ngtcp2_ppe ppe; ngtcp2_pkt_hd hd; ngtcp2_frame_chain **pfrc; + ngtcp2_stream_frame_chain *nsfrc; ngtcp2_frame *ackfr = NULL, lfr; + ngtcp2_strm *strm; ssize_t spktlen; ngtcp2_crypto_ctx ctx; ngtcp2_rtb_entry *rtbent; @@ -776,7 +755,6 @@ static ssize_t conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest, size_t min_payloadlen; uint8_t flags = NGTCP2_RTB_FLAG_NONE; int pkt_empty = 1; - uint64_t written_stream_id = UINT64_MAX; switch (type) { case NGTCP2_PKT_INITIAL: @@ -838,7 +816,8 @@ static ssize_t conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest, } } - if (!pktns->frq && !ackfr) { + if (!pktns->frq && !ackfr && + (type != NGTCP2_PKT_0RTT_PROTECTED || ngtcp2_pq_empty(&conn->tx_strmq))) { return 0; } @@ -872,33 +851,19 @@ static ssize_t conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest, switch ((*pfrc)->fr.type) { case NGTCP2_FRAME_CRYPTO: assert(type != NGTCP2_PKT_0RTT_PROTECTED); - if (ngtcp2_ppe_left(&ppe) < - NGTCP2_CRYPTO_OVERHEAD + NGTCP2_MIN_FRAME_PAYLOADLEN) { + left = ngtcp2_ppe_left(&ppe); + if (left < NGTCP2_CRYPTO_OVERHEAD + NGTCP2_MIN_FRAME_PAYLOADLEN) { goto frq_finish; } - left = ngtcp2_ppe_left(&ppe) - NGTCP2_CRYPTO_OVERHEAD; + left -= NGTCP2_CRYPTO_OVERHEAD; rv = conn_split_crypto_frame(conn, pfrc, left); if (rv != 0) { return rv; } break; case NGTCP2_FRAME_STREAM: - assert(type == NGTCP2_PKT_0RTT_PROTECTED); - if ((written_stream_id != UINT64_MAX && - written_stream_id != (*pfrc)->fr.stream.stream_id) || - ngtcp2_ppe_left(&ppe) < - NGTCP2_STREAM_OVERHEAD + NGTCP2_MIN_FRAME_PAYLOADLEN) { - goto frq_finish; - } - - written_stream_id = (*pfrc)->fr.stream.stream_id; - - left = ngtcp2_ppe_left(&ppe) - NGTCP2_STREAM_OVERHEAD; - rv = conn_split_stream_frame(conn, pfrc, left); - if (rv != 0) { - return rv; - } + assert(0); break; } @@ -913,6 +878,41 @@ static ssize_t conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest, frq_finish: + if (type == NGTCP2_PKT_0RTT_PROTECTED && *pfrc == NULL && + !conn->pktns.tx_ckm) { + for (; !ngtcp2_pq_empty(&conn->tx_strmq);) { + strm = ngtcp2_conn_tx_strmq_top(conn); + if (ngtcp2_strm_streamfrq_empty(strm)) { + ngtcp2_conn_tx_strmq_pop(conn); + continue; + } + + left = ngtcp2_ppe_left(&ppe); + + if (left < NGTCP2_STREAM_OVERHEAD + NGTCP2_MIN_FRAME_PAYLOADLEN) { + break; + } + + left -= NGTCP2_STREAM_OVERHEAD; + rv = ngtcp2_strm_streamfrq_pop(strm, &nsfrc, left); + if (rv != 0) { + return rv; + } + + rv = conn_ppe_write_frame(conn, &ppe, &hd, &nsfrc->frc.fr); + if (rv != 0) { + assert(0); + } + + *pfrc = &nsfrc->frc; + pfrc = &(*pfrc)->next; + + pkt_empty = 0; + + break; + } + } + if (pkt_empty) { ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, "packet transmission canceled"); @@ -1293,17 +1293,17 @@ static ssize_t conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, int rv; ngtcp2_ppe ppe; ngtcp2_pkt_hd hd; - ngtcp2_frame *ackfr; + ngtcp2_frame *ackfr = NULL; ssize_t nwrite; ngtcp2_crypto_ctx ctx; ngtcp2_frame_chain **pfrc, *nfrc, *frc; + ngtcp2_stream_frame_chain *nsfrc; ngtcp2_rtb_entry *ent; - ngtcp2_strm *strm, *strm_next; + ngtcp2_strm *strm; int pkt_empty = 1; ngtcp2_acktr_ack_entry *ack_ent = NULL; size_t ndatalen = 0; int send_stream = 0; - int ack_only; ngtcp2_pktns *pktns = &conn->pktns; size_t left; uint64_t written_stream_id = UINT64_MAX; @@ -1317,6 +1317,7 @@ static ssize_t conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, } } + /* TODO Take into account stream frames */ if ((pktns->frq || send_stream || conn_should_send_max_data(conn)) && conn->unsent_max_rx_offset > conn->max_rx_offset) { rv = ngtcp2_frame_chain_new(&nfrc, conn->mem); @@ -1331,54 +1332,6 @@ static ssize_t conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, conn->max_rx_offset = conn->unsent_max_rx_offset; } - while (conn->fc_strms) { - strm = conn->fc_strms; - rv = ngtcp2_frame_chain_new(&nfrc, conn->mem); - if (rv != 0) { - return rv; - } - nfrc->fr.type = NGTCP2_FRAME_MAX_STREAM_DATA; - nfrc->fr.max_stream_data.stream_id = strm->stream_id; - nfrc->fr.max_stream_data.max_stream_data = strm->unsent_max_rx_offset; - nfrc->next = pktns->frq; - pktns->frq = nfrc; - - strm->max_rx_offset = strm->unsent_max_rx_offset; - - strm_next = strm->fc_next; - conn->fc_strms = strm_next; - if (strm_next) { - strm_next->fc_pprev = &conn->fc_strms; - } - strm->fc_next = NULL; - strm->fc_pprev = NULL; - } - - ack_only = - !send_stream && - conn->unsent_max_remote_stream_id_bidi == - conn->max_remote_stream_id_bidi && - conn->unsent_max_remote_stream_id_uni == conn->max_remote_stream_id_uni && - pktns->frq == NULL; - - if (ack_only && conn->rcs.probe_pkt_left) { - /* Sending ACK only packet does not elicit ACK, therefore it is - not suitable for probe packet. */ - return 0; - } - - ackfr = NULL; - rv = conn_create_ack_frame(conn, &ackfr, &pktns->acktr, ts, - !ack_only /* nodelay */, - conn->local_settings.ack_delay_exponent); - if (rv != 0) { - return rv; - } - - if (ackfr == NULL && ack_only) { - return 0; - } - ngtcp2_pkt_hd_init( &hd, NGTCP2_PKT_FLAG_NONE, NGTCP2_PKT_SHORT, &conn->dcid, &conn->scid, pktns->last_tx_pkt_num + 1, @@ -1397,21 +1350,7 @@ static ssize_t conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, rv = ngtcp2_ppe_encode_hd(&ppe, &hd); if (rv != 0) { - goto fail; - } - - if (ackfr) { - rv = conn_ppe_write_frame(conn, &ppe, &hd, ackfr); - if (rv != 0) { - goto fail; - } - ngtcp2_acktr_commit_ack(&pktns->acktr); - pkt_empty = 0; - - ack_ent = ngtcp2_acktr_add_ack(&pktns->acktr, hd.pkt_num, &ackfr->ack, ts, - 0 /*ack_only*/); - /* Now ackfr is owned by conn->acktr. */ - ackfr = NULL; + return rv; } for (pfrc = &pktns->frq; *pfrc;) { @@ -1436,28 +1375,7 @@ static ssize_t conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, } break; case NGTCP2_FRAME_STREAM: - strm = ngtcp2_conn_find_stream(conn, (*pfrc)->fr.stream.stream_id); - if (strm == NULL || (strm->flags & NGTCP2_STRM_FLAG_SENT_RST)) { - frc = *pfrc; - *pfrc = (*pfrc)->next; - ngtcp2_frame_chain_del(frc, conn->mem); - continue; - } - - if ((written_stream_id != UINT64_MAX && - written_stream_id != (*pfrc)->fr.stream.stream_id) || - ngtcp2_ppe_left(&ppe) < - NGTCP2_STREAM_OVERHEAD + NGTCP2_MIN_FRAME_PAYLOADLEN) { - goto frq_finish; - } - - written_stream_id = (*pfrc)->fr.stream.stream_id; - - rv = conn_split_stream_frame( - conn, pfrc, ngtcp2_ppe_left(&ppe) - NGTCP2_STREAM_OVERHEAD); - if (rv != 0) { - return rv; - } + assert(0); break; case NGTCP2_FRAME_MAX_STREAM_ID: { int cancel; @@ -1479,7 +1397,7 @@ static ssize_t conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, case NGTCP2_FRAME_MAX_STREAM_DATA: strm = ngtcp2_conn_find_stream(conn, (*pfrc)->fr.max_stream_data.stream_id); - if (strm == NULL || + if (strm == NULL || (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) || (*pfrc)->fr.max_stream_data.max_stream_data < strm->max_rx_offset) { frc = *pfrc; *pfrc = (*pfrc)->next; @@ -1496,13 +1414,13 @@ static ssize_t conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, } break; case NGTCP2_FRAME_CRYPTO: - if (ngtcp2_ppe_left(&ppe) < - NGTCP2_CRYPTO_OVERHEAD + NGTCP2_MIN_FRAME_PAYLOADLEN) { + left = ngtcp2_ppe_left(&ppe); + if (left < NGTCP2_CRYPTO_OVERHEAD + NGTCP2_MIN_FRAME_PAYLOADLEN) { goto frq_finish; } - rv = conn_split_crypto_frame( - conn, pfrc, ngtcp2_ppe_left(&ppe) - NGTCP2_CRYPTO_OVERHEAD); + left -= NGTCP2_CRYPTO_OVERHEAD; + rv = conn_split_crypto_frame(conn, pfrc, left); if (rv != 0) { return rv; } @@ -1523,8 +1441,9 @@ frq_finish: /* Write MAX_STREAM_ID after RST_STREAM so that we can extend stream ID space in one packet. */ - if (*pfrc == NULL && conn->unsent_max_remote_stream_id_bidi > - conn->max_remote_stream_id_bidi) { + if (rv != NGTCP2_ERR_NOBUF && *pfrc == NULL && + conn->unsent_max_remote_stream_id_bidi > + conn->max_remote_stream_id_bidi) { rv = ngtcp2_frame_chain_new(&nfrc, conn->mem); if (rv != 0) { return rv; @@ -1545,7 +1464,7 @@ frq_finish: } } - if (*pfrc == NULL && + if (rv != NGTCP2_ERR_NOBUF && *pfrc == NULL && conn->unsent_max_remote_stream_id_uni > conn->max_remote_stream_id_uni) { rv = ngtcp2_frame_chain_new(&nfrc, conn->mem); if (rv != 0) { @@ -1567,9 +1486,82 @@ frq_finish: } } + if (rv != NGTCP2_ERR_NOBUF && *pfrc == NULL) { + for (; !ngtcp2_pq_empty(&conn->tx_strmq);) { + strm = ngtcp2_conn_tx_strmq_top(conn); + + if (!(strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) && + strm->max_rx_offset < strm->unsent_max_rx_offset) { + rv = ngtcp2_frame_chain_new(&nfrc, conn->mem); + if (rv != 0) { + return rv; + } + nfrc->fr.type = NGTCP2_FRAME_MAX_STREAM_DATA; + nfrc->fr.max_stream_data.stream_id = strm->stream_id; + nfrc->fr.max_stream_data.max_stream_data = strm->unsent_max_rx_offset; + ngtcp2_list_insert(nfrc, pfrc); + + rv = conn_ppe_write_frame(conn, &ppe, &hd, &nfrc->fr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + break; + } + + pkt_empty = 0; + pfrc = &(*pfrc)->next; + strm->max_rx_offset = strm->unsent_max_rx_offset; + } + + for (;;) { + if (ngtcp2_strm_streamfrq_empty(strm)) { + ngtcp2_conn_tx_strmq_pop(conn); + if (written_stream_id == UINT64_MAX) { + break; + } + goto tx_strmq_finish; + } + + left = ngtcp2_ppe_left(&ppe); + + if (left < NGTCP2_STREAM_OVERHEAD + NGTCP2_MIN_FRAME_PAYLOADLEN) { + if (written_stream_id != UINT64_MAX) { + ngtcp2_conn_tx_strmq_pop(conn); + ++strm->cycle; + rv = ngtcp2_conn_tx_strmq_push(conn, strm); + if (rv != 0) { + return rv; + } + } + goto tx_strmq_finish; + } + + left -= NGTCP2_STREAM_OVERHEAD; + rv = ngtcp2_strm_streamfrq_pop(strm, &nsfrc, left); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + return rv; + } + + rv = conn_ppe_write_frame(conn, &ppe, &hd, &nsfrc->frc.fr); + if (rv != 0) { + assert(0); + } + + *pfrc = &nsfrc->frc; + pfrc = &(*pfrc)->next; + + written_stream_id = strm->stream_id; + + pkt_empty = 0; + } + } + } + +tx_strmq_finish: + left = ngtcp2_ppe_left(&ppe); - if (send_stream && + if (rv != NGTCP2_ERR_NOBUF && send_stream && (written_stream_id == UINT64_MAX || written_stream_id == data_strm->stream_id) && *pfrc == NULL && @@ -1580,41 +1572,83 @@ frq_finish: fin = fin && ndatalen == datalen; - rv = ngtcp2_frame_chain_new(&nfrc, conn->mem); + rv = ngtcp2_stream_frame_chain_new(&nsfrc, conn->mem); if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); return rv; } - nfrc->fr.type = NGTCP2_FRAME_STREAM; - nfrc->fr.stream.flags = 0; - nfrc->fr.stream.fin = fin; - nfrc->fr.stream.stream_id = data_strm->stream_id; - nfrc->fr.stream.offset = data_strm->tx_offset; - nfrc->fr.stream.datalen = ndatalen; - nfrc->fr.stream.data = data; + nsfrc->fr.type = NGTCP2_FRAME_STREAM; + nsfrc->fr.flags = 0; + nsfrc->fr.fin = fin; + nsfrc->fr.stream_id = data_strm->stream_id; + nsfrc->fr.offset = data_strm->tx_offset; + if (ndatalen) { + nsfrc->fr.datacnt = 1; + nsfrc->fr.data[0].len = ndatalen; + nsfrc->fr.data[0].base = (uint8_t *)data; + } else { + nsfrc->fr.datacnt = 0; + } - rv = conn_ppe_write_frame(conn, &ppe, &hd, &nfrc->fr); + rv = conn_ppe_write_frame(conn, &ppe, &hd, &nsfrc->frc.fr); if (rv != 0) { - assert(NGTCP2_ERR_NOBUF == rv); - ngtcp2_frame_chain_del(nfrc, conn->mem); - send_stream = 0; + assert(0); + } + + *pfrc = &nsfrc->frc; + pfrc = &(*pfrc)->next; + + pkt_empty = 0; + } else { + send_stream = 0; + } + + if (pkt_empty && conn->rcs.probe_pkt_left) { + /* Sending ACK only packet does not elicit ACK, therefore it is + not suitable for probe packet. */ + ngtcp2_log_tx_cancel(&conn->log, &hd); + return rv; + } + + rv = conn_create_ack_frame(conn, &ackfr, &pktns->acktr, ts, + !pkt_empty /* nodelay */, + conn->local_settings.ack_delay_exponent); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + return rv; + } + + if (ackfr) { + rv = conn_ppe_write_frame(conn, &ppe, &hd, ackfr); + if (rv != 0) { + assert(rv == NGTCP2_ERR_NOBUF); + ngtcp2_mem_free(conn->mem, ackfr); } else { - *pfrc = nfrc; - pfrc = &(*pfrc)->next; + ngtcp2_acktr_commit_ack(&pktns->acktr); + pkt_empty = 0; + ack_ent = ngtcp2_acktr_add_ack(&pktns->acktr, hd.pkt_num, &ackfr->ack, ts, + 0 /*ack_only*/); + /* Now ackfr is owned by conn->acktr. */ pkt_empty = 0; } - } else { - send_stream = 0; + ackfr = NULL; } if (pkt_empty) { + /* TODO We might have NGTCP2_ERR_NOBUF before creating ACK + frame */ ngtcp2_log_tx_cancel(&conn->log, &hd); - return rv; + return 0; } + /* TODO Push STREAM frame back to ngtcp2_strm if there is an error + before ngtcp2_rtb_entry is safely created and added. */ + nwrite = ngtcp2_ppe_final(&ppe, NULL); if (nwrite < 0) { + assert(ngtcp2_err_is_fatal((int)nwrite)); return nwrite; } @@ -1622,6 +1656,7 @@ frq_finish: rv = ngtcp2_rtb_entry_new(&ent, &hd, NULL, ts, (size_t)nwrite, NGTCP2_RTB_FLAG_NONE, conn->mem); if (rv != 0) { + assert(ngtcp2_err_is_fatal((int)nwrite)); return rv; } @@ -1654,10 +1689,6 @@ frq_finish: ++pktns->last_tx_pkt_num; return nwrite; - -fail: - ngtcp2_mem_free(conn->mem, ackfr); - return rv; } /* @@ -2088,6 +2119,52 @@ static int conn_on_version_negotiation(ngtcp2_conn *conn, return 0; } +/* + * conn_resched_frames reschedules frames linked from |*pfrc| for + * retransmission. + */ +static int conn_resched_frames(ngtcp2_conn *conn, ngtcp2_pktns *pktns, + ngtcp2_frame_chain **pfrc) { + ngtcp2_frame_chain **first = pfrc; + ngtcp2_stream_frame_chain *frc; + ngtcp2_stream *fr; + ngtcp2_strm *strm; + int rv; + + for (; *pfrc;) { + if ((*pfrc)->fr.type == NGTCP2_FRAME_STREAM) { + frc = (ngtcp2_stream_frame_chain *)*pfrc; + *pfrc = frc->next; + frc->next = NULL; + fr = &frc->fr; + + strm = ngtcp2_conn_find_stream(conn, fr->stream_id); + if (!strm) { + ngtcp2_stream_frame_chain_del(frc, conn->mem); + continue; + } + rv = ngtcp2_strm_streamfrq_push(strm, frc); + if (rv != 0) { + ngtcp2_stream_frame_chain_del(frc, conn->mem); + return rv; + } + if (!ngtcp2_strm_is_tx_queued(strm)) { + rv = ngtcp2_conn_tx_strmq_push(conn, strm); + if (rv != 0) { + return rv; + } + } + continue; + } + pfrc = &(*pfrc)->next; + } + + *pfrc = pktns->frq; + pktns->frq = *first; + + return 0; +} + /* * conn_on_retry is called when Retry packet is received. The * function decodes the data in the buffer pointed by |payload| whose @@ -2113,6 +2190,7 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, uint8_t *p; ngtcp2_rtb *rtb = &conn->pktns.rtb; uint8_t cidbuf[sizeof(retry.odcid.data) * 2 + 1]; + ngtcp2_frame_chain *frc = NULL; if (conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) { return 0; @@ -2151,8 +2229,17 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, ngtcp2_crypto_km_del(conn->early_ckm, conn->mem); conn->early_ckm = NULL; - rv = ngtcp2_rtb_remove_all(rtb, &conn->pktns.frq); + rv = ngtcp2_rtb_remove_all(rtb, &frc); if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + ngtcp2_frame_chain_list_del(frc, conn->mem); + return rv; + } + + rv = conn_resched_frames(conn, &conn->pktns, &frc); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + ngtcp2_frame_chain_list_del(frc, conn->mem); return rv; } @@ -2184,10 +2271,28 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, return 0; } -static int pktns_detect_lost_pkt(ngtcp2_pktns *pktns, ngtcp2_rcvry_stat *rcs, - uint64_t largest_ack, ngtcp2_tstamp ts) { - return ngtcp2_rtb_detect_lost_pkt(&pktns->rtb, &pktns->frq, rcs, largest_ack, - pktns->last_tx_pkt_num, ts); +int ngtcp2_conn_detect_lost_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns, + ngtcp2_rcvry_stat *rcs, uint64_t largest_ack, + ngtcp2_tstamp ts) { + ngtcp2_frame_chain *frc = NULL; + int rv; + + rv = ngtcp2_rtb_detect_lost_pkt(&pktns->rtb, &frc, rcs, largest_ack, + pktns->last_tx_pkt_num, ts); + if (rv != 0) { + /* TODO assert this */ + assert(ngtcp2_err_is_fatal(rv)); + ngtcp2_frame_chain_list_del(frc, conn->mem); + return rv; + } + + rv = conn_resched_frames(conn, pktns, &frc); + if (rv != 0) { + ngtcp2_frame_chain_list_del(frc, conn->mem); + return rv; + } + + return 0; } static int pktns_pkt_lost(ngtcp2_pktns *pktns) { @@ -2211,6 +2316,7 @@ static int conn_recv_ack(ngtcp2_conn *conn, ngtcp2_pktns *pktns, const ngtcp2_pkt_hd *hd, ngtcp2_ack *fr, ngtcp2_tstamp ts) { int rv; + ngtcp2_frame_chain *frc = NULL; rv = ngtcp2_pkt_validate_ack(fr); if (rv != 0) { @@ -2222,15 +2328,27 @@ static int conn_recv_ack(ngtcp2_conn *conn, ngtcp2_pktns *pktns, return rv; } - rv = ngtcp2_rtb_recv_ack(&pktns->rtb, &pktns->frq, hd, fr, conn, ts); + rv = ngtcp2_rtb_recv_ack(&pktns->rtb, &frc, hd, fr, conn, ts); + if (rv != 0) { + /* TODO assert this */ + assert(ngtcp2_err_is_fatal(rv)); + ngtcp2_frame_chain_list_del(frc, conn->mem); + return rv; + } + + /* TODO We don't need to do this for Initial and Handshake packet + because they don't include STREAM frame. */ + rv = conn_resched_frames(conn, pktns, &frc); if (rv != 0) { + ngtcp2_frame_chain_list_del(frc, conn->mem); return rv; } if (!ngtcp2_pkt_handshake_pkt(hd)) { conn->largest_ack = ngtcp2_max(conn->largest_ack, (int64_t)fr->largest_ack); - rv = pktns_detect_lost_pkt(pktns, &conn->rcs, fr->largest_ack, ts); + rv = ngtcp2_conn_detect_lost_pkt(conn, pktns, &conn->rcs, fr->largest_ack, + ts); if (rv != 0) { return rv; } @@ -2510,24 +2628,6 @@ static ssize_t conn_decrypt_pn(ngtcp2_conn *conn, ngtcp2_pkt_hd *hd, return p - dest; } -static void conn_extend_max_stream_offset(ngtcp2_conn *conn, ngtcp2_strm *strm, - size_t datalen) { - if (strm->unsent_max_rx_offset <= NGTCP2_MAX_VARINT - datalen) { - strm->unsent_max_rx_offset += datalen; - } - - if (!(strm->flags & - (NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_STOP_SENDING)) && - !strm->fc_pprev && conn_should_send_max_stream_data(conn, strm)) { - strm->fc_pprev = &conn->fc_strms; - if (conn->fc_strms) { - strm->fc_next = conn->fc_strms; - conn->fc_strms->fc_pprev = &strm->fc_next; - } - conn->fc_strms = strm; - } -} - /* * conn_emit_pending_crypto_data delivers pending stream data to the * application due to packet reordering. @@ -2661,6 +2761,7 @@ static int pktns_pkt_num_is_duplicate(ngtcp2_pktns *pktns, uint64_t pkt_num) { static int pktns_commit_recv_pkt_num(ngtcp2_pktns *pktns, uint64_t pkt_num) { int rv; ngtcp2_psl_it it; + ngtcp2_range key; rv = ngtcp2_gaptr_push(&pktns->pngap, pkt_num, 1); if (rv != 0) { @@ -2669,7 +2770,8 @@ static int pktns_commit_recv_pkt_num(ngtcp2_pktns *pktns, uint64_t pkt_num) { if (ngtcp2_psl_len(&pktns->pngap.gap) > 256) { it = ngtcp2_psl_begin(&pktns->pngap.gap); - return ngtcp2_psl_remove(&pktns->pngap.gap, NULL, ngtcp2_psl_it_range(&it)); + key = ngtcp2_psl_it_range(&it); + return ngtcp2_psl_remove(&pktns->pngap.gap, NULL, &key); } return 0; @@ -3288,6 +3390,7 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { uint64_t rx_offset, fr_end_offset; int local_stream; int bidi; + size_t datalen = ngtcp2_vec_len(fr->data, fr->datacnt); local_stream = conn_local_stream(conn, fr->stream_id); bidi = bidi_stream(fr->stream_id); @@ -3313,7 +3416,7 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { idtr = &conn->remote_uni_idtr; } - if (NGTCP2_MAX_VARINT - fr->datalen < fr->offset) { + if (NGTCP2_MAX_VARINT - datalen < fr->offset) { return NGTCP2_ERR_PROTO; } @@ -3347,20 +3450,20 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { } } - fr_end_offset = fr->offset + fr->datalen; + fr_end_offset = fr->offset + datalen; if (strm->max_rx_offset < fr_end_offset) { return NGTCP2_ERR_FLOW_CONTROL; } if (strm->last_rx_offset < fr_end_offset) { - size_t datalen = fr_end_offset - strm->last_rx_offset; + size_t len = fr_end_offset - strm->last_rx_offset; - if (conn_max_data_violated(conn, datalen)) { + if (conn_max_data_violated(conn, len)) { return NGTCP2_ERR_FLOW_CONTROL; } - conn->rx_offset += datalen; + conn->rx_offset += len; } rx_offset = ngtcp2_strm_rx_offset(strm); @@ -3382,17 +3485,6 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { strm->app_error_code); } - /* Since strm is now in closed (remote), we don't have to send - MAX_STREAM_DATA anymore. */ - if (strm->fc_pprev) { - *strm->fc_pprev = strm->fc_next; - if (strm->fc_next) { - strm->fc_next->fc_pprev = strm->fc_pprev; - } - strm->fc_pprev = NULL; - strm->fc_next = NULL; - } - if (fr_end_offset == rx_offset) { rv = conn_call_recv_stream_data(conn, strm, 1, rx_offset, NULL, 0); if (rv != 0) { @@ -3421,30 +3513,41 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { if (fr->offset <= rx_offset) { size_t ncut = rx_offset - fr->offset; - const uint8_t *data = fr->data + ncut; - size_t datalen = fr->datalen - ncut; uint64_t offset = rx_offset; + const uint8_t *data; + int fin; - rx_offset += datalen; - rv = ngtcp2_rob_remove_prefix(&strm->rob, rx_offset); - if (rv != 0) { - return rv; - } + if (fr->datacnt) { + data = fr->data[0].base + ncut; + datalen -= ncut; - rv = conn_call_recv_stream_data(conn, strm, - (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) && - rx_offset == strm->last_rx_offset, - offset, data, datalen); - if (rv != 0) { - return rv; + rx_offset += datalen; + rv = ngtcp2_rob_remove_prefix(&strm->rob, rx_offset); + if (rv != 0) { + return rv; + } + } else { + data = NULL; + datalen = 0; } - rv = conn_emit_pending_stream_data(conn, strm, rx_offset); - if (rv != 0) { - return rv; + fin = (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) && + rx_offset == strm->last_rx_offset; + + if (fin || datalen) { + rv = conn_call_recv_stream_data(conn, strm, fin, offset, data, datalen); + if (rv != 0) { + return rv; + } + + rv = conn_emit_pending_stream_data(conn, strm, rx_offset); + if (rv != 0) { + return rv; + } } - } else { - rv = ngtcp2_strm_recv_reordering(strm, fr->data, fr->datalen, fr->offset); + } else if (fr->datacnt) { + rv = ngtcp2_strm_recv_reordering(strm, fr->data[0].base, fr->data[0].len, + fr->offset); if (rv != 0) { return rv; } @@ -3503,17 +3606,6 @@ static int conn_stop_sending(ngtcp2_conn *conn, ngtcp2_strm *strm, frc->next = pktns->frq; pktns->frq = frc; - /* Since STREAM is being reset, we don't have to send - MAX_STREAM_DATA anymore */ - if (strm->fc_pprev) { - *strm->fc_pprev = strm->fc_next; - if (strm->fc_next) { - strm->fc_next->fc_pprev = strm->fc_pprev; - } - strm->fc_pprev = NULL; - strm->fc_next = NULL; - } - return 0; } @@ -3629,6 +3721,8 @@ static int conn_recv_stop_sending(ngtcp2_conn *conn, strm->flags |= NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_SENT_RST; + ngtcp2_strm_streamfrq_clear(strm); + return ngtcp2_conn_close_stream_if_shut_rdwr(conn, strm, fr->app_error_code); } @@ -4093,7 +4187,8 @@ static ssize_t conn_recv_pkt(ngtcp2_conn *conn, const uint8_t *pkt, if (rv != 0) { return rv; } - conn_update_rx_bw(conn, fr->stream.datalen, ts); + conn_update_rx_bw( + conn, ngtcp2_vec_len(fr->stream.data, fr->stream.datacnt), ts); break; case NGTCP2_FRAME_CRYPTO: rv = conn_recv_crypto(conn, pktns->crypto_rx_offset_base, @@ -4402,7 +4497,7 @@ static ssize_t conn_handshake(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, } if (conn->state == NGTCP2_CS_CLIENT_INITIAL) { - require_padding = !conn->pktns.frq; + require_padding = ngtcp2_pq_empty(&conn->tx_strmq); nwrite = conn_write_client_initial(conn, dest, destlen, require_padding, ts); if (nwrite < 0) { @@ -4617,7 +4712,7 @@ static ssize_t conn_write_stream_early(ngtcp2_conn *conn, uint8_t *dest, ngtcp2_crypto_ctx ctx; ngtcp2_ppe ppe; ngtcp2_rtb_entry *ent; - ngtcp2_frame_chain *frc; + ngtcp2_stream_frame_chain *frc; ngtcp2_frame localfr; ngtcp2_pkt_hd hd; int rv; @@ -4671,26 +4766,31 @@ static ssize_t conn_write_stream_early(ngtcp2_conn *conn, uint8_t *dest, fin = fin && ndatalen == datalen; - rv = ngtcp2_frame_chain_new(&frc, conn->mem); + rv = ngtcp2_stream_frame_chain_new(&frc, conn->mem); if (rv != 0) { return rv; } frc->fr.type = NGTCP2_FRAME_STREAM; - frc->fr.stream.flags = 0; - frc->fr.stream.fin = fin; - frc->fr.stream.stream_id = strm->stream_id; - frc->fr.stream.offset = strm->tx_offset; - frc->fr.stream.datalen = ndatalen; - frc->fr.stream.data = data; + frc->fr.flags = 0; + frc->fr.fin = fin; + frc->fr.stream_id = strm->stream_id; + frc->fr.offset = strm->tx_offset; + if (ndatalen) { + frc->fr.datacnt = 1; + frc->fr.data[0].len = ndatalen; + frc->fr.data[0].base = (uint8_t *)data; + } else { + frc->fr.datacnt = 0; + } - rv = ngtcp2_ppe_encode_frame(&ppe, &frc->fr); + rv = ngtcp2_ppe_encode_frame(&ppe, &frc->frc.fr); if (rv != 0) { - ngtcp2_frame_chain_del(frc, conn->mem); + ngtcp2_stream_frame_chain_del(frc, conn->mem); return rv; } - ngtcp2_log_tx_fr(&conn->log, &hd, &frc->fr); + ngtcp2_log_tx_fr(&conn->log, &hd, &frc->frc.fr); if (require_padding) { localfr.type = NGTCP2_FRAME_PADDING; @@ -4701,14 +4801,14 @@ static ssize_t conn_write_stream_early(ngtcp2_conn *conn, uint8_t *dest, nwrite = ngtcp2_ppe_final(&ppe, NULL); if (nwrite < 0) { - ngtcp2_frame_chain_del(frc, conn->mem); + ngtcp2_stream_frame_chain_del(frc, conn->mem); return nwrite; } - rv = ngtcp2_rtb_entry_new(&ent, &hd, frc, ts, (size_t)nwrite, + rv = ngtcp2_rtb_entry_new(&ent, &hd, &frc->frc, ts, (size_t)nwrite, NGTCP2_RTB_FLAG_NONE, conn->mem); if (rv != 0) { - ngtcp2_frame_chain_del(frc, conn->mem); + ngtcp2_stream_frame_chain_del(frc, conn->mem); return rv; } @@ -5353,6 +5453,7 @@ ssize_t ngtcp2_conn_write_stream(ngtcp2_conn *conn, uint8_t *dest, nwrite = conn_write_pkt(conn, dest, ngtcp2_min(destlen, cwnd), pdatalen, strm, fin, data, datalen, ts); + if (nwrite) { return nwrite; } @@ -5522,11 +5623,8 @@ int ngtcp2_conn_close_stream(ngtcp2_conn *conn, ngtcp2_strm *strm, } } - if (strm->fc_pprev) { - *strm->fc_pprev = strm->fc_next; - if (strm->fc_next) { - strm->fc_next->fc_pprev = strm->fc_pprev; - } + if (ngtcp2_strm_is_tx_queued(strm)) { + ngtcp2_pq_remove(&conn->tx_strmq, &strm->pe); } ngtcp2_strm_free(strm); @@ -5560,6 +5658,8 @@ static int conn_shutdown_stream_write(ngtcp2_conn *conn, ngtcp2_strm *strm, strm->flags |= NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_SENT_RST; strm->app_error_code = app_error_code; + ngtcp2_strm_streamfrq_clear(strm); + return conn_rst_stream(conn, strm, app_error_code); } @@ -5634,6 +5734,28 @@ int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, uint64_t stream_id, return conn_shutdown_stream_read(conn, strm, app_error_code); } +static int conn_extend_max_stream_offset(ngtcp2_conn *conn, ngtcp2_strm *strm, + size_t datalen) { + ngtcp2_strm *top; + + if (strm->unsent_max_rx_offset <= NGTCP2_MAX_VARINT - datalen) { + strm->unsent_max_rx_offset += datalen; + } + + if (!(strm->flags & + (NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_STOP_SENDING)) && + !ngtcp2_strm_is_tx_queued(strm) && + conn_should_send_max_stream_data(conn, strm)) { + if (!ngtcp2_pq_empty(&conn->tx_strmq)) { + top = ngtcp2_conn_tx_strmq_top(conn); + strm->cycle = top->cycle; + } + return ngtcp2_conn_tx_strmq_push(conn, strm); + } + + return 0; +} + int ngtcp2_conn_extend_max_stream_offset(ngtcp2_conn *conn, uint64_t stream_id, size_t datalen) { ngtcp2_strm *strm; @@ -5643,9 +5765,7 @@ int ngtcp2_conn_extend_max_stream_offset(ngtcp2_conn *conn, uint64_t stream_id, return NGTCP2_ERR_STREAM_NOT_FOUND; } - conn_extend_max_stream_offset(conn, strm, datalen); - - return 0; + return conn_extend_max_stream_offset(conn, strm, datalen); } void ngtcp2_conn_extend_max_offset(ngtcp2_conn *conn, size_t datalen) { @@ -5682,10 +5802,26 @@ uint32_t ngtcp2_conn_get_negotiated_version(ngtcp2_conn *conn) { int ngtcp2_conn_early_data_rejected(ngtcp2_conn *conn) { ngtcp2_pktns *pktns = &conn->pktns; ngtcp2_rtb *rtb = &conn->pktns.rtb; + ngtcp2_frame_chain *frc = NULL; + int rv; conn->flags |= NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED; - return ngtcp2_rtb_remove_all(rtb, &pktns->frq); + rv = ngtcp2_rtb_remove_all(rtb, &frc); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + ngtcp2_frame_chain_list_del(frc, conn->mem); + return rv; + } + + rv = conn_resched_frames(conn, pktns, &frc); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + ngtcp2_frame_chain_list_del(frc, conn->mem); + return rv; + } + + return rv; } void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, uint64_t rtt, @@ -5814,7 +5950,8 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { } ++rcs->handshake_count; } else if (rcs->loss_time) { - rv = pktns_detect_lost_pkt(pktns, rcs, (uint64_t)conn->largest_ack, ts); + rv = ngtcp2_conn_detect_lost_pkt(conn, pktns, rcs, + (uint64_t)conn->largest_ack, ts); if (rv != 0) { return rv; } @@ -5894,3 +6031,19 @@ int ngtcp2_conn_set_retry_ocid(ngtcp2_conn *conn, const ngtcp2_cid *ocid) { return 0; } + +ngtcp2_strm *ngtcp2_conn_tx_strmq_top(ngtcp2_conn *conn) { + assert(!ngtcp2_pq_empty(&conn->tx_strmq)); + return ngtcp2_struct_of(ngtcp2_pq_top(&conn->tx_strmq), ngtcp2_strm, pe); +} + +void ngtcp2_conn_tx_strmq_pop(ngtcp2_conn *conn) { + ngtcp2_strm *strm = ngtcp2_conn_tx_strmq_top(conn); + assert(strm); + ngtcp2_pq_pop(&conn->tx_strmq); + strm->pe.index = NGTCP2_PQ_BAD_INDEX; +} + +int ngtcp2_conn_tx_strmq_push(ngtcp2_conn *conn, ngtcp2_strm *strm) { + return ngtcp2_pq_push(&conn->tx_strmq, &strm->pe); +} diff --git a/lib/ngtcp2_conn.h b/lib/ngtcp2_conn.h index d1d49c62acbe3462aac9b1e44fb5618e22378612..a2d846c8732a71bc4fe865b5a7c8508f53a8da93 100644 --- a/lib/ngtcp2_conn.h +++ b/lib/ngtcp2_conn.h @@ -41,6 +41,7 @@ #include "ngtcp2_str.h" #include "ngtcp2_pkt.h" #include "ngtcp2_log.h" +#include "ngtcp2_pq.h" typedef enum { /* Client specific handshake states */ @@ -247,7 +248,8 @@ struct ngtcp2_conn { ngtcp2_pktns pktns; ngtcp2_strm crypto; ngtcp2_map strms; - ngtcp2_strm *fc_strms; + /* tx_strmq contains ngtcp2_strm which has frames to send. */ + ngtcp2_pq tx_strmq; ngtcp2_idtr remote_bidi_idtr; ngtcp2_idtr remote_uni_idtr; ngtcp2_rcvry_stat rcs; @@ -423,4 +425,31 @@ void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, uint64_t rtt, void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn); +int ngtcp2_conn_detect_lost_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns, + ngtcp2_rcvry_stat *rcs, uint64_t largest_ack, + ngtcp2_tstamp ts); + +/* + * ngtcp2_conn_tx_strmq_top returns the ngtcp2_strm which sits on the + * top of queue. tx_strmq must not be empty. + */ +ngtcp2_strm *ngtcp2_conn_tx_strmq_top(ngtcp2_conn *conn); + +/* + * ngtcp2_conn_tx_strmq_pop pops the ngtcp2_strm from the queue. + * tx_strmq must not be empty. + */ +void ngtcp2_conn_tx_strmq_pop(ngtcp2_conn *conn); + +/* + * ngtcp2_conn_tx_strmq_push pushes |strm| into tx_strmq. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGTCP2_ERR_NOMEM + * Out of memory. + */ +int ngtcp2_conn_tx_strmq_push(ngtcp2_conn *conn, ngtcp2_strm *strm); + #endif /* NGTCP2_CONN_H */ diff --git a/lib/ngtcp2_gaptr.c b/lib/ngtcp2_gaptr.c index 9278dc2d25e7851f6b94f287e72ecc9c18172709..0fb1760d901796027efd779bbb3130fe4a1eb7b5 100644 --- a/lib/ngtcp2_gaptr.c +++ b/lib/ngtcp2_gaptr.c @@ -58,29 +58,28 @@ void ngtcp2_gaptr_free(ngtcp2_gaptr *gaptr) { int ngtcp2_gaptr_push(ngtcp2_gaptr *gaptr, uint64_t offset, size_t datalen) { int rv; - ngtcp2_range m, l, r, q = {offset, offset + datalen}; - const ngtcp2_range *k; + ngtcp2_range k, m, l, r, q = {offset, offset + datalen}; ngtcp2_psl_it it; it = ngtcp2_psl_lower_bound(&gaptr->gap, &q); for (; !ngtcp2_psl_it_end(&it);) { k = ngtcp2_psl_it_range(&it); - m = ngtcp2_range_intersect(&q, k); + m = ngtcp2_range_intersect(&q, &k); if (!ngtcp2_range_len(&m)) { break; } - if (ngtcp2_range_eq(k, &m)) { - rv = ngtcp2_psl_remove(&gaptr->gap, &it, k); + if (ngtcp2_range_eq(&k, &m)) { + rv = ngtcp2_psl_remove(&gaptr->gap, &it, &k); if (rv != 0) { return rv; } continue; } - ngtcp2_range_cut(&l, &r, k, &m); + ngtcp2_range_cut(&l, &r, &k, &m); if (ngtcp2_range_len(&l)) { - ngtcp2_psl_update_range(&gaptr->gap, k, &l); + ngtcp2_psl_update_range(&gaptr->gap, &k, &l); if (ngtcp2_range_len(&r)) { rv = ngtcp2_psl_insert(&gaptr->gap, &it, &r, NULL); @@ -89,7 +88,7 @@ int ngtcp2_gaptr_push(ngtcp2_gaptr *gaptr, uint64_t offset, size_t datalen) { } } } else if (ngtcp2_range_len(&r)) { - ngtcp2_psl_update_range(&gaptr->gap, k, &r); + ngtcp2_psl_update_range(&gaptr->gap, &k, &r); } ngtcp2_psl_it_next(&it); } @@ -98,14 +97,15 @@ int ngtcp2_gaptr_push(ngtcp2_gaptr *gaptr, uint64_t offset, size_t datalen) { uint64_t ngtcp2_gaptr_first_gap_offset(ngtcp2_gaptr *gaptr) { ngtcp2_psl_it it = ngtcp2_psl_begin(&gaptr->gap); - const ngtcp2_range *r = ngtcp2_psl_it_range(&it); - return r->begin; + ngtcp2_range r = ngtcp2_psl_it_range(&it); + return r.begin; } int ngtcp2_gaptr_is_pushed(ngtcp2_gaptr *gaptr, uint64_t offset, size_t datalen) { ngtcp2_range q = {offset, offset + datalen}; ngtcp2_psl_it it = ngtcp2_psl_lower_bound(&gaptr->gap, &q); - ngtcp2_range m = ngtcp2_range_intersect(&q, ngtcp2_psl_it_range(&it)); + ngtcp2_range k = ngtcp2_psl_it_range(&it); + ngtcp2_range m = ngtcp2_range_intersect(&q, &k); return ngtcp2_range_len(&m) == 0; } diff --git a/lib/ngtcp2_log.c b/lib/ngtcp2_log.c index 62671459da84c70cd6b1deeead120ee6bfccd388..ac4bacdc6af06a780d84ea7eeecd59fcc5266ea1 100644 --- a/lib/ngtcp2_log.c +++ b/lib/ngtcp2_log.c @@ -30,6 +30,7 @@ #include <errno.h> #include "ngtcp2_str.h" +#include "ngtcp2_vec.h" void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid, ngtcp2_printf log_printf, ngtcp2_tstamp ts, @@ -198,7 +199,8 @@ static void log_fr_stream(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, (NGTCP2_LOG_PKT " STREAM(0x%02x) id=0x%" PRIx64 " fin=%d offset=%" PRIu64 " len=%" PRIu64 " uni=%d\n"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type | fr->flags, fr->stream_id, - fr->fin, fr->offset, fr->datalen, (fr->stream_id & 0x2) != 0); + fr->fin, fr->offset, ngtcp2_vec_len(fr->data, fr->datacnt), + (fr->stream_id & 0x2) != 0); } static void log_fr_ack(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, @@ -711,5 +713,5 @@ void ngtcp2_log_info(ngtcp2_log *log, ngtcp2_log_event ev, const char *fmt, void ngtcp2_log_tx_cancel(ngtcp2_log *log, const ngtcp2_pkt_hd *hd) { ngtcp2_log_info(log, NGTCP2_LOG_EVENT_PKT, "cancel tx pkt %" PRIu64 " type=%s(0x%02x)", hd->pkt_num, - hd->type); + strpkttype(hd), hd->type); } diff --git a/lib/ngtcp2_pkt.c b/lib/ngtcp2_pkt.c index 21f957cc6718943823e82929212110e78affdb72..a41154e341b2ed1c0b2d36b01fd0913091d63a4b 100644 --- a/lib/ngtcp2_pkt.c +++ b/lib/ngtcp2_pkt.c @@ -462,6 +462,8 @@ ssize_t ngtcp2_pkt_decode_stream_frame(ngtcp2_stream *dest, if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } + } else { + len = payloadlen; } p = payload + 1; @@ -480,20 +482,23 @@ ssize_t ngtcp2_pkt_decode_stream_frame(ngtcp2_stream *dest, } if (type & NGTCP2_STREAM_LEN_BIT) { - dest->datalen = datalen; p += ndatalen; - dest->data = p; - p += dest->datalen; - - assert((size_t)(p - payload) == len); + } else { + datalen = payloadlen - (size_t)(p - payload); + } - return (ssize_t)len; + if (datalen) { + dest->data[0].len = datalen; + dest->data[0].base = (uint8_t *)p; + dest->datacnt = 1; + p += datalen; + } else { + dest->datacnt = 0; } - dest->datalen = payloadlen - (size_t)(p - payload); - dest->data = p; + assert((size_t)(p - payload) == len); - return (ssize_t)payloadlen; + return (ssize_t)len; } ssize_t ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, const uint8_t *payload, @@ -1294,6 +1299,8 @@ ssize_t ngtcp2_pkt_encode_stream_frame(uint8_t *out, size_t outlen, size_t len = 1; uint8_t flags = NGTCP2_STREAM_LEN_BIT; uint8_t *p; + size_t i; + size_t datalen = 0; if (fr->fin) { flags |= NGTCP2_STREAM_FIN_BIT; @@ -1305,8 +1312,13 @@ ssize_t ngtcp2_pkt_encode_stream_frame(uint8_t *out, size_t outlen, } len += ngtcp2_put_varint_len(fr->stream_id); - len += ngtcp2_put_varint_len(fr->datalen); - len += fr->datalen; + + for (i = 0; i < fr->datacnt; ++i) { + datalen += fr->data[i].len; + } + + len += ngtcp2_put_varint_len(datalen); + len += datalen; if (outlen < len) { return NGTCP2_ERR_NOBUF; @@ -1324,10 +1336,12 @@ ssize_t ngtcp2_pkt_encode_stream_frame(uint8_t *out, size_t outlen, p = ngtcp2_put_varint(p, fr->offset); } - p = ngtcp2_put_varint(p, fr->datalen); + p = ngtcp2_put_varint(p, datalen); - if (fr->datalen) { - p = ngtcp2_cpymem(p, fr->data, fr->datalen); + for (i = 0; i < fr->datacnt; ++i) { + assert(fr->data[i].len); + assert(fr->data[i].base); + p = ngtcp2_cpymem(p, fr->data[i].base, fr->data[i].len); } assert((size_t)(p - out) == len); diff --git a/lib/ngtcp2_pq.c b/lib/ngtcp2_pq.c index ead720251ab1006856dc4605098db8afe1e97d19..176268a3ce2857c4e2c6877cf84b4c8f90174d44 100644 --- a/lib/ngtcp2_pq.c +++ b/lib/ngtcp2_pq.c @@ -87,11 +87,8 @@ int ngtcp2_pq_push(ngtcp2_pq *pq, ngtcp2_pq_entry *item) { } ngtcp2_pq_entry *ngtcp2_pq_top(ngtcp2_pq *pq) { - if (pq->length == 0) { - return NULL; - } else { - return pq->q[0]; - } + assert(pq->length); + return pq->q[0]; } static void bubble_down(ngtcp2_pq *pq, size_t index) { diff --git a/lib/ngtcp2_pq.h b/lib/ngtcp2_pq.h index 0625cc1bc0a33bd847251e5f767792f46a6f4905..982661b155cc0a96cc1f1978e201465e1b656781 100644 --- a/lib/ngtcp2_pq.h +++ b/lib/ngtcp2_pq.h @@ -36,13 +36,19 @@ /* Implementation of priority queue */ -/* "less" function, return nonzero if |lhs| is less than |rhs|. */ -typedef int (*ngtcp2_less)(const void *lhs, const void *rhs); +/* NGTCP2_PQ_BAD_INDEX is the priority queue index which indicates + that an entry is not queued. Assigning this value to + ngtcp2_pq_entry.index can check that the entry is queued or not. */ +#define NGTCP2_PQ_BAD_INDEX SIZE_MAX typedef struct { size_t index; } ngtcp2_pq_entry; +/* "less" function, return nonzero if |lhs| is less than |rhs|. */ +typedef int (*ngtcp2_less)(const ngtcp2_pq_entry *lhs, + const ngtcp2_pq_entry *rhs); + typedef struct { /* The pointer to the pointer to the item stored */ ngtcp2_pq_entry **q; @@ -80,8 +86,8 @@ void ngtcp2_pq_free(ngtcp2_pq *pq); int ngtcp2_pq_push(ngtcp2_pq *pq, ngtcp2_pq_entry *item); /* - * Returns item at the top of the queue |pq|. If the queue is empty, - * this function returns NULL. + * Returns item at the top of the queue |pq|. It is undefined if the + * queue is empty. */ ngtcp2_pq_entry *ngtcp2_pq_top(ngtcp2_pq *pq); diff --git a/lib/ngtcp2_psl.c b/lib/ngtcp2_psl.c index 35896d05452d1fde75df5de966790624a533be95..a20ecd465a6be7ed2b94c1d8d523baf58480e0da 100644 --- a/lib/ngtcp2_psl.c +++ b/lib/ngtcp2_psl.c @@ -607,6 +607,6 @@ int ngtcp2_psl_it_end(const ngtcp2_psl_it *it) { return ngtcp2_range_eq(&end, &it->blk->nodes[it->i].range); } -const ngtcp2_range *ngtcp2_psl_it_range(const ngtcp2_psl_it *it) { - return &it->blk->nodes[it->i].range; +ngtcp2_range ngtcp2_psl_it_range(const ngtcp2_psl_it *it) { + return it->blk->nodes[it->i].range; } diff --git a/lib/ngtcp2_psl.h b/lib/ngtcp2_psl.h index 95352d34815094e1af1170b26696ce080362cf85..17ae0e0a68228d908868a8b6349e0be12544b134 100644 --- a/lib/ngtcp2_psl.h +++ b/lib/ngtcp2_psl.h @@ -226,6 +226,6 @@ int ngtcp2_psl_it_end(const ngtcp2_psl_it *it); * returns nonzero. In this case, this function returns {UINT64_MAX, * UINT64_MAX}. */ -const ngtcp2_range *ngtcp2_psl_it_range(const ngtcp2_psl_it *it); +ngtcp2_range ngtcp2_psl_it_range(const ngtcp2_psl_it *it); #endif /* NGTCP2_PSL_H */ diff --git a/lib/ngtcp2_rtb.c b/lib/ngtcp2_rtb.c index 868700106e0138b592ee42d234bf56126ab82982..ae1b1385826cfa20a0f189f6933dbc52e36f9ecf 100644 --- a/lib/ngtcp2_rtb.c +++ b/lib/ngtcp2_rtb.c @@ -30,6 +30,7 @@ #include "ngtcp2_macro.h" #include "ngtcp2_conn.h" #include "ngtcp2_log.h" +#include "ngtcp2_vec.h" int ngtcp2_frame_chain_new(ngtcp2_frame_chain **pfrc, ngtcp2_mem *mem) { *pfrc = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_frame_chain)); @@ -60,6 +61,24 @@ void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, ngtcp2_mem *mem) { void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc) { frc->next = NULL; } +int ngtcp2_stream_frame_chain_new(ngtcp2_stream_frame_chain **pfrc, + ngtcp2_mem *mem) { + *pfrc = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_stream_frame_chain)); + if (*pfrc == NULL) { + return NGTCP2_ERR_NOMEM; + } + + ngtcp2_frame_chain_init(&(*pfrc)->frc); + (*pfrc)->pe.index = NGTCP2_PQ_BAD_INDEX; + + return 0; +} + +void ngtcp2_stream_frame_chain_del(ngtcp2_stream_frame_chain *frc, + ngtcp2_mem *mem) { + ngtcp2_mem_free(mem, frc); +} + ngtcp2_frame_chain *ngtcp2_frame_chain_list_copy(ngtcp2_frame_chain *frc, ngtcp2_mem *mem) { ngtcp2_frame_chain *nfrc = NULL, **pfrc = &nfrc; @@ -230,8 +249,9 @@ static int call_acked_stream_offset(ngtcp2_rtb_entry *ent, ngtcp2_conn *conn) { } prev_stream_offset = ngtcp2_gaptr_first_gap_offset(&strm->acked_tx_offset); - rv = ngtcp2_gaptr_push(&strm->acked_tx_offset, frc->fr.stream.offset, - frc->fr.stream.datalen); + rv = ngtcp2_gaptr_push( + &strm->acked_tx_offset, frc->fr.stream.offset, + ngtcp2_vec_len(frc->fr.stream.data, frc->fr.stream.datacnt)); if (rv != 0) { return rv; } @@ -313,7 +333,7 @@ static int rtb_on_retransmission_timeout_verified(ngtcp2_rtb *rtb, for (; !ngtcp2_ksl_it_end(&it);) { ent = ngtcp2_ksl_it_get(&it); - rv = ngtcp2_ksl_remove(&rtb->ents, &it, ngtcp2_ksl_it_key(&it)); + rv = ngtcp2_ksl_remove(&rtb->ents, &it, (int64_t)ent->hd.pkt_num); if (rv != 0) { return rv; } @@ -529,7 +549,7 @@ int ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, for (; !ngtcp2_ksl_it_end(&it);) { ent = ngtcp2_ksl_it_get(&it); - rv = ngtcp2_ksl_remove(&rtb->ents, &it, ngtcp2_ksl_it_key(&it)); + rv = ngtcp2_ksl_remove(&rtb->ents, &it, (int64_t)ent->hd.pkt_num); if (rv != 0) { return rv; } @@ -559,7 +579,7 @@ int ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc) { ngtcp2_log_pkt_lost(rtb->log, &ent->hd, ent->ts); rtb_on_remove(rtb, ent); - rv = ngtcp2_ksl_remove(&rtb->ents, &it, ngtcp2_ksl_it_key(&it)); + rv = ngtcp2_ksl_remove(&rtb->ents, &it, (int64_t)ent->hd.pkt_num); if (rv != 0) { return rv; } diff --git a/lib/ngtcp2_rtb.h b/lib/ngtcp2_rtb.h index bb5f2740a8d363413cdc6a624d0e8c42facf0561..0a969adee3663c5f8f02aa24f253766b193bf524 100644 --- a/lib/ngtcp2_rtb.h +++ b/lib/ngtcp2_rtb.h @@ -32,6 +32,7 @@ #include <ngtcp2/ngtcp2.h> #include "ngtcp2_ksl.h" +#include "ngtcp2_pq.h" struct ngtcp2_cc_stat; typedef struct ngtcp2_cc_stat ngtcp2_cc_stat; @@ -53,6 +54,28 @@ struct ngtcp2_frame_chain { ngtcp2_frame fr; }; +/* NGTCP2_MAX_STREAM_DATACNT is the maximum number of ngtcp2_vec that + a ngtcp2_crypto can include. */ +#define NGTCP2_MAX_STREAM_DATACNT 8 + +struct ngtcp2_stream_frame_chain; +typedef struct ngtcp2_stream_frame_chain ngtcp2_stream_frame_chain; + +/* ngtcp2_stream_frame_chain is an extension to ngtcp2_frame_chain and + specific to ngtcp2_stream. It includes pe in order to push it to + ngtcp2_pq. */ +struct ngtcp2_stream_frame_chain { + union { + ngtcp2_frame_chain frc; + struct { + ngtcp2_frame_chain *next; + ngtcp2_stream fr; + ngtcp2_vec extra[NGTCP2_MAX_STREAM_DATACNT - 1]; + }; + }; + ngtcp2_pq_entry pe; +}; + /* * ngtcp2_frame_chain_new allocates ngtcp2_frame_chain object and * assigns its pointer to |*pfrc|. @@ -84,6 +107,12 @@ void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, ngtcp2_mem *mem); */ void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc); +int ngtcp2_stream_frame_chain_new(ngtcp2_stream_frame_chain **pfrc, + ngtcp2_mem *mem); + +void ngtcp2_stream_frame_chain_del(ngtcp2_stream_frame_chain *frc, + ngtcp2_mem *mem); + /* * ngtcp2_frame_chain_list_copy creates a copy of |frc| following next * field. It makes copy of each ngtcp2_frame_chain object pointed by diff --git a/lib/ngtcp2_str.c b/lib/ngtcp2_str.c index b301ff0f906122b2314b87a049d1fe5dd3a96670..bfceea904e1b5a4de1cb02700d438780c39c9246 100644 --- a/lib/ngtcp2_str.c +++ b/lib/ngtcp2_str.c @@ -25,6 +25,7 @@ #include "ngtcp2_str.h" #include <string.h> +#include <assert.h> uint8_t *ngtcp2_cpymem(uint8_t *dest, const uint8_t *src, size_t n) { memcpy(dest, src, n); diff --git a/lib/ngtcp2_strm.c b/lib/ngtcp2_strm.c index 45ef3e0e0c1098212d9b97be68b7bd75497266c4..780009c0ee9f3c06b7534bba4bde9fce8ea420c7 100644 --- a/lib/ngtcp2_strm.c +++ b/lib/ngtcp2_strm.c @@ -25,12 +25,28 @@ #include "ngtcp2_strm.h" #include <string.h> +#include <assert.h> + +#include "ngtcp2_rtb.h" +#include "ngtcp2_pkt.h" +#include "ngtcp2_vec.h" +#include "ngtcp2_macro.h" + +static int offset_less(const ngtcp2_pq_entry *lhs, const ngtcp2_pq_entry *rhs) { + ngtcp2_stream_frame_chain *lfrc = + ngtcp2_struct_of(lhs, ngtcp2_stream_frame_chain, pe); + ngtcp2_stream_frame_chain *rfrc = + ngtcp2_struct_of(rhs, ngtcp2_stream_frame_chain, pe); + + return lfrc->fr.offset < rfrc->fr.offset; +} int ngtcp2_strm_init(ngtcp2_strm *strm, uint64_t stream_id, uint32_t flags, uint64_t max_rx_offset, uint64_t max_tx_offset, void *stream_user_data, ngtcp2_mem *mem) { int rv; + strm->cycle = 0; strm->tx_offset = 0; strm->last_rx_offset = 0; strm->nbuffered = 0; @@ -41,9 +57,8 @@ int ngtcp2_strm_init(ngtcp2_strm *strm, uint64_t stream_id, uint32_t flags, strm->max_tx_offset = max_tx_offset; strm->me.key = stream_id; strm->me.next = NULL; + strm->pe.index = NGTCP2_PQ_BAD_INDEX; strm->mem = mem; - strm->fc_pprev = NULL; - strm->fc_next = NULL; /* Initializing to 0 is a bit controversial because application error code 0 is STOPPING. But STOPPING is only sent with RST_STREAM in response to STOP_SENDING, and it is not used to @@ -62,6 +77,8 @@ int ngtcp2_strm_init(ngtcp2_strm *strm, uint64_t stream_id, uint32_t flags, goto fail_rob_init; } + ngtcp2_pq_init(&strm->streamfrq, offset_less, mem); + return 0; fail_rob_init: @@ -71,10 +88,20 @@ fail_gaptr_init: } void ngtcp2_strm_free(ngtcp2_strm *strm) { + ngtcp2_stream_frame_chain *frc; + if (strm == NULL) { return; } + for (; !ngtcp2_pq_empty(&strm->streamfrq);) { + frc = ngtcp2_struct_of(ngtcp2_pq_top(&strm->streamfrq), + ngtcp2_stream_frame_chain, pe); + ngtcp2_pq_pop(&strm->streamfrq); + ngtcp2_stream_frame_chain_del(frc, strm->mem); + } + + ngtcp2_pq_free(&strm->streamfrq); ngtcp2_rob_free(&strm->rob); ngtcp2_gaptr_free(&strm->acked_tx_offset); } @@ -91,3 +118,139 @@ int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data, void ngtcp2_strm_shutdown(ngtcp2_strm *strm, uint32_t flags) { strm->flags |= flags & NGTCP2_STRM_FLAG_SHUT_RDWR; } + +int ngtcp2_strm_streamfrq_push(ngtcp2_strm *strm, + ngtcp2_stream_frame_chain *frc) { + ngtcp2_stream *fr = &frc->fr; + + assert(fr->type == NGTCP2_FRAME_STREAM); + assert(frc->next == NULL); + + return ngtcp2_pq_push(&strm->streamfrq, &frc->pe); +} + +int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, + ngtcp2_stream_frame_chain **pfrc, size_t left) { + ngtcp2_stream *fr, *nfr; + ngtcp2_stream_frame_chain *frc, *nfrc; + int rv; + size_t nmerged; + size_t datalen; + + if (ngtcp2_pq_empty(&strm->streamfrq)) { + *pfrc = NULL; + return 0; + } + + frc = ngtcp2_struct_of(ngtcp2_pq_top(&strm->streamfrq), + ngtcp2_stream_frame_chain, pe); + ngtcp2_pq_pop(&strm->streamfrq); + frc->pe.index = NGTCP2_PQ_BAD_INDEX; + + fr = &frc->fr; + + if (fr->datacnt == NGTCP2_MAX_STREAM_DATACNT) { + *pfrc = frc; + return 0; + } + + datalen = ngtcp2_vec_len(fr->data, fr->datacnt); + if (datalen > left) { + rv = ngtcp2_stream_frame_chain_new(&nfrc, strm->mem); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + ngtcp2_stream_frame_chain_del(frc, strm->mem); + return rv; + } + + nfr = &nfrc->fr; + nfr->type = NGTCP2_FRAME_STREAM; + nfr->flags = 0; + nfr->fin = fr->fin; + nfr->stream_id = fr->stream_id; + nfr->offset = fr->offset + left; + nfr->datacnt = 0; + + ngtcp2_vec_split(fr->data, &fr->datacnt, nfr->data, &nfr->datacnt, left); + + fr->fin = 0; + + rv = ngtcp2_pq_push(&strm->streamfrq, &nfrc->pe); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + ngtcp2_stream_frame_chain_del(nfrc, strm->mem); + ngtcp2_stream_frame_chain_del(frc, strm->mem); + return rv; + } + + *pfrc = frc; + + return 0; + } + + left -= datalen; + + for (; left && fr->datacnt < NGTCP2_MAX_STREAM_DATACNT && + !ngtcp2_pq_empty(&strm->streamfrq);) { + nfrc = ngtcp2_struct_of(ngtcp2_pq_top(&strm->streamfrq), + ngtcp2_stream_frame_chain, pe); + nfr = &nfrc->fr; + + if (nfr->offset != fr->offset + datalen) { + assert(fr->offset + datalen < nfr->offset); + break; + } + + if (nfr->fin && nfr->datacnt == 0) { + frc->fr.fin = 1; + ngtcp2_pq_pop(&strm->streamfrq); + ngtcp2_stream_frame_chain_del(nfrc, strm->mem); + break; + } + + nmerged = ngtcp2_vec_merge(fr->data, &fr->datacnt, nfr->data, &nfr->datacnt, + left, NGTCP2_MAX_STREAM_DATACNT); + if (nmerged == 0) { + break; + } + + ngtcp2_pq_pop(&strm->streamfrq); + + datalen += nmerged; + nfr->offset += nmerged; + left -= nmerged; + + if (nfr->datacnt == 0) { + frc->fr.fin = nfrc->fr.fin; + ngtcp2_stream_frame_chain_del(nfrc, strm->mem); + } else { + rv = ngtcp2_pq_push(&strm->streamfrq, &nfrc->pe); + if (rv != 0) { + ngtcp2_stream_frame_chain_del(nfrc, strm->mem); + ngtcp2_stream_frame_chain_del(frc, strm->mem); + return rv; + } + } + } + + *pfrc = frc; + return 0; +} + +int ngtcp2_strm_streamfrq_empty(ngtcp2_strm *strm) { + return ngtcp2_pq_empty(&strm->streamfrq); +} + +void ngtcp2_strm_streamfrq_clear(ngtcp2_strm *strm) { + ngtcp2_stream_frame_chain *frc; + for (; !ngtcp2_pq_empty(&strm->streamfrq);) { + frc = ngtcp2_struct_of(ngtcp2_pq_top(&strm->streamfrq), + ngtcp2_stream_frame_chain, pe); + ngtcp2_pq_pop(&strm->streamfrq); + ngtcp2_stream_frame_chain_del(frc, strm->mem); + } +} + +int ngtcp2_strm_is_tx_queued(ngtcp2_strm *strm) { + return strm->pe.index != NGTCP2_PQ_BAD_INDEX; +} diff --git a/lib/ngtcp2_strm.h b/lib/ngtcp2_strm.h index c81ed5d904559bc01a8251b58e27c0e096e7d13a..946105ef56f0409ad1f5fd2a59d8b71afd686f91 100644 --- a/lib/ngtcp2_strm.h +++ b/lib/ngtcp2_strm.h @@ -35,6 +35,11 @@ #include "ngtcp2_buf.h" #include "ngtcp2_map.h" #include "ngtcp2_gaptr.h" +#include "ngtcp2_ksl.h" +#include "ngtcp2_pq.h" + +struct ngtcp2_stream_frame_chain; +typedef struct ngtcp2_stream_frame_chain ngtcp2_stream_frame_chain; typedef enum { NGTCP2_STRM_FLAG_NONE = 0, @@ -60,11 +65,12 @@ typedef enum { } ngtcp2_strm_flags; struct ngtcp2_strm; - typedef struct ngtcp2_strm ngtcp2_strm; struct ngtcp2_strm { ngtcp2_map_entry me; + ngtcp2_pq_entry pe; + uint64_t cycle; uint64_t tx_offset; ngtcp2_gaptr acked_tx_offset; /* max_tx_offset is the maximum offset that local endpoint can send @@ -74,6 +80,8 @@ struct ngtcp2_strm { this stream. */ uint64_t last_rx_offset; ngtcp2_rob rob; + /* streamfrq contains STREAM frame for (re)transmission. */ + ngtcp2_pq streamfrq; /* max_rx_offset is the maximum offset that remote endpoint can send to this stream. */ uint64_t max_rx_offset; @@ -88,7 +96,6 @@ struct ngtcp2_strm { void *stream_user_data; /* flags is bit-wise OR of zero or more of ngtcp2_strm_flags. */ uint32_t flags; - ngtcp2_strm **fc_pprev, *fc_next; /* app_error_code is an error code the local endpoint sent in RST_STREAM or STOP_SENDING. */ uint16_t app_error_code; @@ -137,4 +144,36 @@ int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data, */ void ngtcp2_strm_shutdown(ngtcp2_strm *strm, uint32_t flags); +/* + * ngtcp2_strm_streamfrq_push pushes |frc| to streamfrq for + * retransmission. + */ +int ngtcp2_strm_streamfrq_push(ngtcp2_strm *strm, + ngtcp2_stream_frame_chain *frc); + +/* + * ngtcp2_strm_streamfrq_pop pops the first ngtcp2_stream_frame_chain + * and assigns it to |*pfrc|. This function splits into or merges + * several ngtcp2_stream_frame_chain objects so that the returned + * ngtcp2_stream_frame_chain has at most |left| data length. If there + * is no frames to send, this function returns 0 and |*pfrc| is NULL. + */ +int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, + ngtcp2_stream_frame_chain **pfrc, size_t left); + +/* + * ngtcp2_strm_streamfrq_empty returns nonzero if streamfrq is empty. + */ +int ngtcp2_strm_streamfrq_empty(ngtcp2_strm *strm); + +/* + * ngtcp2_strm_streamfrq_clear removes all frames from streamfrq. + */ +void ngtcp2_strm_streamfrq_clear(ngtcp2_strm *strm); + +/* + * ngtcp2_strm_is_tx_queued returns nonzero if |strm| is queued. + */ +int ngtcp2_strm_is_tx_queued(ngtcp2_strm *strm); + #endif /* NGTCP2_STRM_H */ diff --git a/lib/ngtcp2_vec.c b/lib/ngtcp2_vec.c new file mode 100644 index 0000000000000000000000000000000000000000..6a2fee3332dbca56d3a438234f338cc23eef84a4 --- /dev/null +++ b/lib/ngtcp2_vec.c @@ -0,0 +1,138 @@ +/* + * ngtcp2 + * + * Copyright (c) 2018 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "ngtcp2_vec.h" + +#include <string.h> +#include <assert.h> + +size_t ngtcp2_vec_len(const ngtcp2_vec *vec, size_t n) { + size_t i; + size_t res = 0; + + for (i = 0; i < n; ++i) { + res += vec[i].len; + } + + return res; +} + +void ngtcp2_vec_split(ngtcp2_vec *src, size_t *psrccnt, ngtcp2_vec *dst, + size_t *pdstcnt, size_t left) { + size_t i; + size_t srccnt = *psrccnt; + + *pdstcnt = 0; + + for (i = 0; i < srccnt; ++i) { + if (left >= src[i].len) { + left -= src[i].len; + continue; + } + if (left == 0) { + *psrccnt = i; + *pdstcnt = srccnt - i; + memcpy(dst, src + i, sizeof(ngtcp2_vec) * (*pdstcnt)); + return; + } + dst[0].len = src[i].len - left; + dst[0].base = src[i].base + left; + src[i].len = left; + ++i; + *psrccnt = i; + *pdstcnt = 1 + srccnt - i; + memcpy(dst + 1, src + i, sizeof(ngtcp2_vec) * (*pdstcnt - 1)); + + return; + } +} + +size_t ngtcp2_vec_merge(ngtcp2_vec *dst, size_t *pdstcnt, ngtcp2_vec *src, + size_t *psrccnt, size_t left, size_t maxcnt) { + size_t orig_left = left; + size_t i; + ngtcp2_vec *a, *b; + + assert(maxcnt); + + if (*pdstcnt == 0) { + if (*psrccnt == 0) { + return 0; + } + + a = &dst[0]; + b = &src[0]; + + if (left >= b->len) { + *a = *b; + ++*pdstcnt; + left -= b->len; + i = 1; + } else { + a->len = left; + a->base = b->base; + + b->len -= left; + b->base += left; + + return left; + } + } else { + i = 0; + } + + for (; left && *pdstcnt < maxcnt && i < *psrccnt; ++i) { + a = &dst[*pdstcnt - 1]; + b = &src[i]; + + if (left >= b->len) { + if (a->base + a->len == b->base) { + a->len += b->len; + } else { + dst[(*pdstcnt)++] = *b; + } + left -= b->len; + continue; + } + + if (a->base + a->len == b->base) { + a->len += left; + } else { + dst[*pdstcnt].len = left; + dst[*pdstcnt].base = b->base; + ++*pdstcnt; + } + + b->len -= left; + b->base += left; + left = 0; + + break; + } + + memmove(src, src + i, sizeof(ngtcp2_vec) * (*psrccnt - i)); + *psrccnt -= i; + + return orig_left - left; +} diff --git a/lib/ngtcp2_vec.h b/lib/ngtcp2_vec.h new file mode 100644 index 0000000000000000000000000000000000000000..3c52b39c364acb17114b76375574404d98b68b73 --- /dev/null +++ b/lib/ngtcp2_vec.h @@ -0,0 +1,42 @@ +/* + * ngtcp2 + * + * Copyright (c) 2018 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef NGTCP2_VEC_H +#define NGTCP2_VEC_H + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ + +#include <ngtcp2/ngtcp2.h> + +size_t ngtcp2_vec_len(const ngtcp2_vec *vec, size_t n); + +void ngtcp2_vec_split(ngtcp2_vec *src, size_t *psrccnt, ngtcp2_vec *dst, + size_t *pdstcnt, size_t left); + +size_t ngtcp2_vec_merge(ngtcp2_vec *dst, size_t *pdstcnt, ngtcp2_vec *src, + size_t *psrccnt, size_t left, size_t maxcnt); + +#endif /* NGTCP2_VEC_H */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ddcacddc2c4f3157d2899ca4cf053f5ce8d05cbd..6e9ce121059ab06b25eaef4764f802aa4e4e2d5c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -47,6 +47,8 @@ if(HAVE_CUNIT) ngtcp2_psl_test.c ngtcp2_ksl_test.c ngtcp2_gaptr_test.c + ngtcp2_vec_test.c + ngtcp2_strm_test.c ) add_executable(main EXCLUDE_FROM_ALL diff --git a/tests/Makefile.am b/tests/Makefile.am index 06ea62dc609bffb56a615541f14326e12bc670e9..7d4bf75bc10c787cf3bad06b0e94ac51c0e8c85f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -42,6 +42,8 @@ OBJECTS = \ ngtcp2_psl_test.c \ ngtcp2_ksl_test.c \ ngtcp2_gaptr_test.c \ + ngtcp2_vec_test.c \ + ngtcp2_strm_test.c \ ngtcp2_test_helper.c HFILES= \ ngtcp2_pkt_test.h \ @@ -58,6 +60,8 @@ HFILES= \ ngtcp2_psl_test.h \ ngtcp2_ksl_test.h \ ngtcp2_gaptr_test.h \ + ngtcp2_vec_test.h \ + ngtcp2_strm_test.h \ ngtcp2_test_helper.h main_SOURCES = $(HFILES) $(OBJECTS) diff --git a/tests/main.c b/tests/main.c index 0810ac781665635318378a8ec1df6aee799b19d2..29398e26875572af297e758a00a253ea4d59003f 100644 --- a/tests/main.c +++ b/tests/main.c @@ -45,6 +45,8 @@ #include "ngtcp2_ksl_test.h" #include "ngtcp2_map_test.h" #include "ngtcp2_gaptr_test.h" +#include "ngtcp2_vec_test.h" +#include "ngtcp2_strm_test.h" static int init_suite1(void) { return 0; } @@ -216,7 +218,11 @@ int main() { !CU_add_test(pSuite, "map_each_free", test_ngtcp2_map_each_free) || !CU_add_test(pSuite, "map_clear", test_ngtcp2_map_clear) || !CU_add_test(pSuite, "gaptr_push", test_ngtcp2_gaptr_push) || - !CU_add_test(pSuite, "gaptr_is_pushed", test_ngtcp2_gaptr_is_pushed)) { + !CU_add_test(pSuite, "gaptr_is_pushed", test_ngtcp2_gaptr_is_pushed) || + !CU_add_test(pSuite, "vec_split", test_ngtcp2_vec_split) || + !CU_add_test(pSuite, "vec_merge", test_ngtcp2_vec_merge) || + !CU_add_test(pSuite, "strm_streamfrq_pop", + test_ngtcp2_strm_streamfrq_pop)) { CU_cleanup_registry(); return (int)CU_get_error(); } diff --git a/tests/ngtcp2_conn_test.c b/tests/ngtcp2_conn_test.c index aa403ac6f24aa1a406117749fa4f3279182f7d94..adbe2e8806eb107585ea3c472493d50cc2ec83ba 100644 --- a/tests/ngtcp2_conn_test.c +++ b/tests/ngtcp2_conn_test.c @@ -126,7 +126,7 @@ typedef struct { recv_stream_data callback. */ struct { uint64_t stream_id; - uint8_t fin; + int fin; size_t datalen; } stream_data; } my_user_data; @@ -227,7 +227,7 @@ static int recv_crypto_data_server(ngtcp2_conn *conn, uint64_t offset, return 0; } -static int recv_stream_data(ngtcp2_conn *conn, uint64_t stream_id, uint8_t fin, +static int recv_stream_data(ngtcp2_conn *conn, uint64_t stream_id, int fin, uint64_t offset, const uint8_t *data, size_t datalen, void *user_data, void *stream_user_data) { @@ -539,8 +539,9 @@ void test_ngtcp2_conn_stream_open_close(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 17; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 17; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, 1, &fr); @@ -554,7 +555,7 @@ void test_ngtcp2_conn_stream_open_close(void) { fr.stream.fin = 1; fr.stream.offset = 17; - fr.stream.datalen = 0; + fr.stream.datacnt = 0; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, 2, &fr); @@ -580,8 +581,9 @@ void test_ngtcp2_conn_stream_open_close(void) { fr.stream.stream_id = 2; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 19; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 19; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, 3, &fr); @@ -592,8 +594,8 @@ void test_ngtcp2_conn_stream_open_close(void) { strm = ngtcp2_conn_find_stream(conn, 2); CU_ASSERT(NGTCP2_STRM_FLAG_SHUT_WR == strm->flags); - CU_ASSERT(fr.stream.datalen == strm->last_rx_offset); - CU_ASSERT(fr.stream.datalen == ngtcp2_strm_rx_offset(strm)); + CU_ASSERT(fr.stream.data[0].len == strm->last_rx_offset); + CU_ASSERT(fr.stream.data[0].len == ngtcp2_strm_rx_offset(strm)); /* Open a local unidirectional stream */ rv = ngtcp2_conn_open_uni_stream(conn, &stream_id, NULL); @@ -629,8 +631,9 @@ void test_ngtcp2_conn_stream_rx_flow_control(void) { fr.stream.stream_id = stream_id; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 1024; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 1024; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, i, &fr); @@ -643,31 +646,29 @@ void test_ngtcp2_conn_stream_rx_flow_control(void) { CU_ASSERT(NULL != strm); rv = ngtcp2_conn_extend_max_stream_offset(conn, stream_id, - fr.stream.datalen); + fr.stream.data[0].len); CU_ASSERT(0 == rv); } - strm = conn->fc_strms; + CU_ASSERT(3 == ngtcp2_pq_size(&conn->tx_strmq)); - CU_ASSERT(8 == strm->stream_id); + strm = ngtcp2_conn_find_stream(conn, 0); - strm = strm->fc_next; + CU_ASSERT(ngtcp2_strm_is_tx_queued(strm)); - CU_ASSERT(4 == strm->stream_id); - - strm = strm->fc_next; + strm = ngtcp2_conn_find_stream(conn, 4); - CU_ASSERT(0 == strm->stream_id); + CU_ASSERT(ngtcp2_strm_is_tx_queued(strm)); - strm = strm->fc_next; + strm = ngtcp2_conn_find_stream(conn, 8); - CU_ASSERT(NULL == strm); + CU_ASSERT(ngtcp2_strm_is_tx_queued(strm)); spktlen = ngtcp2_conn_write_pkt(conn, buf, sizeof(buf), 2); CU_ASSERT(spktlen > 0); - CU_ASSERT(NULL == conn->fc_strms); + CU_ASSERT(ngtcp2_pq_empty(&conn->tx_strmq)); for (i = 0; i < 3; ++i) { uint64_t stream_id = i * 4; @@ -695,8 +696,9 @@ void test_ngtcp2_conn_stream_rx_flow_control_error(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 1024; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 1024; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, 1, &fr); rv = ngtcp2_conn_recv(conn, buf, pktlen, 1); @@ -785,8 +787,9 @@ void test_ngtcp2_conn_rx_flow_control(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 1023; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 1023; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, 1, &fr); rv = ngtcp2_conn_recv(conn, buf, pktlen, 1); @@ -803,8 +806,9 @@ void test_ngtcp2_conn_rx_flow_control(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 1023; - fr.stream.datalen = 1; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 1; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, 2, &fr); rv = ngtcp2_conn_recv(conn, buf, pktlen, 2); @@ -842,8 +846,9 @@ void test_ngtcp2_conn_rx_flow_control_error(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 1025; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 1025; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, 1, &fr); rv = ngtcp2_conn_recv(conn, buf, pktlen, 1); @@ -997,8 +1002,9 @@ void test_ngtcp2_conn_recv_rst_stream(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 955; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 955; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, 1, &fr); rv = ngtcp2_conn_recv(conn, buf, pktlen, 1); @@ -1033,8 +1039,9 @@ void test_ngtcp2_conn_recv_rst_stream(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 955; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 955; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, 1, &fr); rv = ngtcp2_conn_recv(conn, buf, pktlen, 1); @@ -1067,8 +1074,9 @@ void test_ngtcp2_conn_recv_rst_stream(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 955; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 955; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, 1, &fr); rv = ngtcp2_conn_recv(conn, buf, pktlen, 1); @@ -1101,8 +1109,9 @@ void test_ngtcp2_conn_recv_rst_stream(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 955; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 955; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, 1, &fr); rv = ngtcp2_conn_recv(conn, buf, pktlen, 1); @@ -1143,8 +1152,9 @@ void test_ngtcp2_conn_recv_rst_stream(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 955; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 955; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, 1, &fr); rv = ngtcp2_conn_recv(conn, buf, pktlen, 1); @@ -1172,8 +1182,9 @@ void test_ngtcp2_conn_recv_rst_stream(void) { fr.stream.stream_id = 4; fr.stream.fin = 1; fr.stream.offset = 0; - fr.stream.datalen = 955; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 955; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, 1, &fr); rv = ngtcp2_conn_recv(conn, buf, pktlen, 1); @@ -1290,8 +1301,9 @@ void test_ngtcp2_conn_recv_rst_stream(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 955; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 955; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, 1, &fr); rv = ngtcp2_conn_recv(conn, buf, pktlen, 1); @@ -1321,8 +1333,9 @@ void test_ngtcp2_conn_recv_rst_stream(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 955; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 955; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, 1, &fr); rv = ngtcp2_conn_recv(conn, buf, pktlen, 1); @@ -1511,8 +1524,9 @@ void test_ngtcp2_conn_recv_conn_id_omitted(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 100; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 100; + fr.stream.data[0].base = null_data; /* Receiving packet which has no connection ID while SCID of server is not empty. */ @@ -2130,8 +2144,7 @@ void test_ngtcp2_conn_retransmit_protected(void) { t += 1000000000; it = ngtcp2_rtb_head(&conn->pktns.rtb); - ngtcp2_rtb_detect_lost_pkt(&conn->pktns.rtb, &conn->pktns.frq, &conn->rcs, - 1000000007, 1000000007, ++t); + ngtcp2_conn_detect_lost_pkt(conn, &conn->pktns, &conn->rcs, 1000000007, ++t); spktlen = ngtcp2_conn_write_pkt(conn, buf, sizeof(buf), ++t); CU_ASSERT(spktlen > 0); @@ -2161,8 +2174,7 @@ void test_ngtcp2_conn_retransmit_protected(void) { t += 1000000000; it = ngtcp2_rtb_head(&conn->pktns.rtb); - ngtcp2_rtb_detect_lost_pkt(&conn->pktns.rtb, &conn->pktns.frq, &conn->rcs, - 1000000007, 1000000007, ++t); + ngtcp2_conn_detect_lost_pkt(conn, &conn->pktns, &conn->rcs, 1000000007, ++t); spktlen = ngtcp2_conn_write_pkt(conn, buf, (size_t)(spktlen - 1), ++t); CU_ASSERT(spktlen > 0); @@ -2194,8 +2206,9 @@ void test_ngtcp2_conn_send_max_stream_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = datalen; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = datalen; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2210,7 +2223,7 @@ void test_ngtcp2_conn_send_max_stream_data(void) { strm = ngtcp2_conn_find_stream(conn, 4); - CU_ASSERT(NULL != strm->fc_pprev); + CU_ASSERT(ngtcp2_strm_is_tx_queued(strm)); ngtcp2_conn_del(conn); @@ -2222,8 +2235,9 @@ void test_ngtcp2_conn_send_max_stream_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 1; fr.stream.offset = 0; - fr.stream.datalen = datalen; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = datalen; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2238,7 +2252,7 @@ void test_ngtcp2_conn_send_max_stream_data(void) { strm = ngtcp2_conn_find_stream(conn, 4); - CU_ASSERT(NULL == strm->fc_pprev); + CU_ASSERT(!ngtcp2_strm_is_tx_queued(strm)); ngtcp2_conn_del(conn); @@ -2251,8 +2265,9 @@ void test_ngtcp2_conn_send_max_stream_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = datalen; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = datalen; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2271,7 +2286,7 @@ void test_ngtcp2_conn_send_max_stream_data(void) { strm = ngtcp2_conn_find_stream(conn, 4); - CU_ASSERT(NULL == strm->fc_pprev); + CU_ASSERT(!ngtcp2_strm_is_tx_queued(strm)); ngtcp2_conn_del(conn); @@ -2284,8 +2299,9 @@ void test_ngtcp2_conn_send_max_stream_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = datalen; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = datalen; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2309,7 +2325,7 @@ void test_ngtcp2_conn_send_max_stream_data(void) { rv = ngtcp2_conn_extend_max_stream_offset(conn, 4, datalen); CU_ASSERT(0 == rv); - CU_ASSERT(NULL == conn->fc_strms); + CU_ASSERT(ngtcp2_pq_empty(&conn->tx_strmq)); ngtcp2_conn_del(conn); } @@ -2334,8 +2350,9 @@ void test_ngtcp2_conn_recv_stream_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 111; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 111; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2352,8 +2369,9 @@ void test_ngtcp2_conn_recv_stream_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 1; fr.stream.offset = 111; - fr.stream.datalen = 99; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 99; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2378,8 +2396,9 @@ void test_ngtcp2_conn_recv_stream_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 111; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 111; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2396,8 +2415,7 @@ void test_ngtcp2_conn_recv_stream_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 1; fr.stream.offset = 111; - fr.stream.datalen = 0; - fr.stream.data = NULL; + fr.stream.datacnt = 0; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2422,8 +2440,7 @@ void test_ngtcp2_conn_recv_stream_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 1; fr.stream.offset = 599; - fr.stream.datalen = 0; - fr.stream.data = NULL; + fr.stream.datacnt = 0; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2438,8 +2455,9 @@ void test_ngtcp2_conn_recv_stream_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 599; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 599; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2465,8 +2483,7 @@ void test_ngtcp2_conn_recv_stream_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 1; fr.stream.offset = 599; - fr.stream.datalen = 0; - fr.stream.data = NULL; + fr.stream.datacnt = 0; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2481,8 +2498,9 @@ void test_ngtcp2_conn_recv_stream_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 1; fr.stream.offset = 0; - fr.stream.datalen = 599; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 599; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2506,8 +2524,9 @@ void test_ngtcp2_conn_recv_stream_data(void) { fr.stream.stream_id = 3; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 911; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 911; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2532,8 +2551,9 @@ void test_ngtcp2_conn_recv_stream_data(void) { fr.stream.stream_id = 2; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 911; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 911; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2557,8 +2577,9 @@ void test_ngtcp2_conn_recv_stream_data(void) { fr.stream.stream_id = stream_id; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 9; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 9; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2595,8 +2616,7 @@ void test_ngtcp2_conn_recv_stream_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 0; - fr.stream.data = null_data; + fr.stream.datacnt = 0; pktlen = write_single_frame_pkt(conn, buf, sizeof(buf), &conn->scid, ++pkt_num, &fr); @@ -2812,8 +2832,9 @@ void test_ngtcp2_conn_recv_early_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 1; fr.stream.offset = 0; - fr.stream.datalen = 911; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 911; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_handshake_pkt( conn, buf, sizeof(buf), NGTCP2_PKT_0RTT_PROTECTED, &rcid, &conn->dcid, @@ -2837,8 +2858,9 @@ void test_ngtcp2_conn_recv_early_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 1; fr.stream.offset = 0; - fr.stream.datalen = 119; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 119; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_handshake_pkt( conn, buf, sizeof(buf), NGTCP2_PKT_0RTT_PROTECTED, &rcid, &conn->dcid, @@ -2886,8 +2908,9 @@ void test_ngtcp2_conn_recv_early_data(void) { fr.stream.stream_id = 4; fr.stream.fin = 1; fr.stream.offset = 0; - fr.stream.datalen = 999; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 999; + fr.stream.data[0].base = null_data; pktlen += write_single_frame_handshake_pkt( conn, buf + pktlen, sizeof(buf) - pktlen, NGTCP2_PKT_0RTT_PROTECTED, @@ -2964,8 +2987,9 @@ void test_ngtcp2_conn_recv_compound_pkt(void) { fr.stream.stream_id = 4; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 426; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 426; + fr.stream.data[0].base = null_data; pktlen += write_single_frame_pkt(conn, buf + pktlen, sizeof(buf) - pktlen, &conn->scid, ++pkt_num, &fr); @@ -3004,8 +3028,9 @@ void test_ngtcp2_conn_pkt_payloadlen(void) { fr.stream.stream_id = 0; fr.stream.fin = 0; fr.stream.offset = 0; - fr.stream.datalen = 131; - fr.stream.data = null_data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = 131; + fr.stream.data[0].base = null_data; pktlen = write_single_frame_handshake_pkt( conn, buf, sizeof(buf), NGTCP2_PKT_INITIAL, &conn->scid, &conn->dcid, diff --git a/tests/ngtcp2_gaptr_test.c b/tests/ngtcp2_gaptr_test.c index 6ceb6d5389ce8b14bb055ef71b68b8b40e5a74a2..a4dadaff02bf03f4f6d9d9aa6cfbb94bae0740cb 100644 --- a/tests/ngtcp2_gaptr_test.c +++ b/tests/ngtcp2_gaptr_test.c @@ -34,43 +34,43 @@ void test_ngtcp2_gaptr_push(void) { ngtcp2_gaptr gaptr; ngtcp2_mem *mem = ngtcp2_mem_default(); ngtcp2_psl_it it; - const ngtcp2_range *key; + ngtcp2_range r; int rv; size_t i; ngtcp2_gaptr_init(&gaptr, mem); it = ngtcp2_psl_begin(&gaptr.gap); - key = ngtcp2_psl_it_range(&it); + r = ngtcp2_psl_it_range(&it); - CU_ASSERT(0 == key->begin); - CU_ASSERT(UINT64_MAX == key->end); + CU_ASSERT(0 == r.begin); + CU_ASSERT(UINT64_MAX == r.end); rv = ngtcp2_gaptr_push(&gaptr, 0, 1); CU_ASSERT(0 == rv); it = ngtcp2_psl_begin(&gaptr.gap); - key = ngtcp2_psl_it_range(&it); + r = ngtcp2_psl_it_range(&it); - CU_ASSERT(1 == key->begin); - CU_ASSERT(UINT64_MAX == key->end); + CU_ASSERT(1 == r.begin); + CU_ASSERT(UINT64_MAX == r.end); rv = ngtcp2_gaptr_push(&gaptr, 12389, 133); CU_ASSERT(0 == rv); it = ngtcp2_psl_begin(&gaptr.gap); - key = ngtcp2_psl_it_range(&it); + r = ngtcp2_psl_it_range(&it); - CU_ASSERT(1 == key->begin); - CU_ASSERT(12389 == key->end); + CU_ASSERT(1 == r.begin); + CU_ASSERT(12389 == r.end); ngtcp2_psl_it_next(&it); - key = ngtcp2_psl_it_range(&it); + r = ngtcp2_psl_it_range(&it); - CU_ASSERT(12389 + 133 == key->begin); - CU_ASSERT(UINT64_MAX == key->end); + CU_ASSERT(12389 + 133 == r.begin); + CU_ASSERT(UINT64_MAX == r.end); for (i = 0; i < 2; ++i) { rv = ngtcp2_gaptr_push(&gaptr, 1, 12389); @@ -78,10 +78,10 @@ void test_ngtcp2_gaptr_push(void) { CU_ASSERT(0 == rv); it = ngtcp2_psl_begin(&gaptr.gap); - key = ngtcp2_psl_it_range(&it); + r = ngtcp2_psl_it_range(&it); - CU_ASSERT(12389 + 133 == key->begin); - CU_ASSERT(UINT64_MAX == key->end); + CU_ASSERT(12389 + 133 == r.begin); + CU_ASSERT(UINT64_MAX == r.end); } rv = ngtcp2_gaptr_push(&gaptr, 12389 + 133 - 1, 2); @@ -89,10 +89,10 @@ void test_ngtcp2_gaptr_push(void) { CU_ASSERT(0 == rv); it = ngtcp2_psl_begin(&gaptr.gap); - key = ngtcp2_psl_it_range(&it); + r = ngtcp2_psl_it_range(&it); - CU_ASSERT(12389 + 133 + 1 == key->begin); - CU_ASSERT(UINT64_MAX == key->end); + CU_ASSERT(12389 + 133 + 1 == r.begin); + CU_ASSERT(UINT64_MAX == r.end); ngtcp2_gaptr_free(&gaptr); } diff --git a/tests/ngtcp2_idtr_test.c b/tests/ngtcp2_idtr_test.c index 8e1a795e478e9255b15063411d97ee149f5c63a8..646a44c3bdf617dc569dfa9ba60a1ca34b0831d5 100644 --- a/tests/ngtcp2_idtr_test.c +++ b/tests/ngtcp2_idtr_test.c @@ -37,7 +37,7 @@ void test_ngtcp2_idtr_open(void) { ngtcp2_idtr idtr; int rv; ngtcp2_psl_it it; - const ngtcp2_range *key; + ngtcp2_range key; rv = ngtcp2_idtr_init(&idtr, 0, mem); @@ -50,8 +50,8 @@ void test_ngtcp2_idtr_open(void) { it = ngtcp2_psl_begin(&idtr.gap.gap); key = ngtcp2_psl_it_range(&it); - CU_ASSERT(1 == key->begin); - CU_ASSERT(UINT64_MAX == key->end); + CU_ASSERT(1 == key.begin); + CU_ASSERT(UINT64_MAX == key.end); rv = ngtcp2_idtr_open(&idtr, stream_id_from_id(1000000007)); @@ -60,14 +60,14 @@ void test_ngtcp2_idtr_open(void) { it = ngtcp2_psl_begin(&idtr.gap.gap); key = ngtcp2_psl_it_range(&it); - CU_ASSERT(1 == key->begin); - CU_ASSERT(1000000007 == key->end); + CU_ASSERT(1 == key.begin); + CU_ASSERT(1000000007 == key.end); ngtcp2_psl_it_next(&it); key = ngtcp2_psl_it_range(&it); - CU_ASSERT(1000000008 == key->begin); - CU_ASSERT(UINT64_MAX == key->end); + CU_ASSERT(1000000008 == key.begin); + CU_ASSERT(UINT64_MAX == key.end); rv = ngtcp2_idtr_open(&idtr, stream_id_from_id(0)); diff --git a/tests/ngtcp2_pkt_test.c b/tests/ngtcp2_pkt_test.c index 290a9163fa5c42e5e5c76d6579566bee757e07b8..51b3000ba31153f7eb9b3aac34ebd9fabb73535c 100644 --- a/tests/ngtcp2_pkt_test.c +++ b/tests/ngtcp2_pkt_test.c @@ -229,7 +229,8 @@ void test_ngtcp2_pkt_decode_stream_frame(void) { CU_ASSERT(0 == fr.stream.fin); CU_ASSERT(0xf1f2f3f4u == fr.stream.stream_id); CU_ASSERT(0x31f2f3f4f5f6f7f8llu == fr.stream.offset); - CU_ASSERT(0x14 == fr.stream.datalen); + CU_ASSERT(1 == fr.stream.datacnt); + CU_ASSERT(0x14 == fr.stream.data[0].len); /* Cutting 1 bytes from the tail must cause invalid argument error */ @@ -253,7 +254,8 @@ void test_ngtcp2_pkt_decode_stream_frame(void) { CU_ASSERT(0 == fr.stream.fin); CU_ASSERT(0x31 == fr.stream.stream_id); CU_ASSERT(0x00 == fr.stream.offset); - CU_ASSERT(0x14 == fr.stream.datalen); + CU_ASSERT(1 == fr.stream.datacnt); + CU_ASSERT(0x14 == fr.stream.data[0].len); /* Cutting 1 bytes from the tail must cause invalid argument error */ @@ -277,7 +279,8 @@ void test_ngtcp2_pkt_decode_stream_frame(void) { CU_ASSERT(1 == fr.stream.fin); CU_ASSERT(0x31f2f3f4u == fr.stream.stream_id); CU_ASSERT(0x00 == fr.stream.offset); - CU_ASSERT(0x14 == fr.stream.datalen); + CU_ASSERT(1 == fr.stream.datacnt); + CU_ASSERT(0x14 == fr.stream.data[0].len); memset(&fr, 0, sizeof(fr)); } @@ -336,8 +339,9 @@ void test_ngtcp2_pkt_encode_stream_frame(void) { fr.stream.fin = 0; fr.stream.stream_id = 0xf1f2f3f4u; fr.stream.offset = 0x31f2f3f4f5f6f7f8llu; - fr.stream.datalen = strsize(data); - fr.stream.data = data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = strsize(data); + fr.stream.data[0].base = (uint8_t *)data; framelen = 1 + 8 + 8 + 1 + 17; @@ -354,8 +358,10 @@ void test_ngtcp2_pkt_encode_stream_frame(void) { CU_ASSERT(fr.stream.fin == nfr.stream.fin); CU_ASSERT(fr.stream.stream_id == nfr.stream.stream_id); CU_ASSERT(fr.stream.offset == nfr.stream.offset); - CU_ASSERT(fr.stream.datalen == nfr.stream.datalen); - CU_ASSERT(0 == memcmp(fr.stream.data, nfr.stream.data, fr.stream.datalen)); + CU_ASSERT(1 == nfr.stream.datacnt); + CU_ASSERT(fr.stream.data[0].len == nfr.stream.data[0].len); + CU_ASSERT(0 == memcmp(fr.stream.data[0].base, nfr.stream.data[0].base, + fr.stream.data[0].len)); memset(&nfr, 0, sizeof(nfr)); @@ -364,8 +370,9 @@ void test_ngtcp2_pkt_encode_stream_frame(void) { fr.stream.fin = 0; fr.stream.stream_id = 0x31; fr.stream.offset = 0; - fr.stream.datalen = strsize(data); - fr.stream.data = data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = strsize(data); + fr.stream.data[0].base = (uint8_t *)data; framelen = 1 + 1 + 1 + 17; @@ -381,8 +388,10 @@ void test_ngtcp2_pkt_encode_stream_frame(void) { CU_ASSERT(fr.stream.fin == nfr.stream.fin); CU_ASSERT(fr.stream.stream_id == nfr.stream.stream_id); CU_ASSERT(fr.stream.offset == nfr.stream.offset); - CU_ASSERT(fr.stream.datalen == nfr.stream.datalen); - CU_ASSERT(0 == memcmp(fr.stream.data, nfr.stream.data, fr.stream.datalen)); + CU_ASSERT(1 == nfr.stream.datacnt); + CU_ASSERT(fr.stream.data[0].len == nfr.stream.data[0].len); + CU_ASSERT(0 == memcmp(fr.stream.data[0].base, nfr.stream.data[0].base, + fr.stream.data[0].len)); memset(&nfr, 0, sizeof(nfr)); @@ -391,8 +400,9 @@ void test_ngtcp2_pkt_encode_stream_frame(void) { fr.stream.fin = 1; fr.stream.stream_id = 0xf1f2f3f4u; fr.stream.offset = 0x31f2f3f4f5f6f7f8llu; - fr.stream.datalen = strsize(data); - fr.stream.data = data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = strsize(data); + fr.stream.data[0].base = (uint8_t *)data; framelen = 1 + 8 + 8 + 1 + 17; @@ -409,8 +419,10 @@ void test_ngtcp2_pkt_encode_stream_frame(void) { CU_ASSERT(fr.stream.fin == nfr.stream.fin); CU_ASSERT(fr.stream.stream_id == nfr.stream.stream_id); CU_ASSERT(fr.stream.offset == nfr.stream.offset); - CU_ASSERT(fr.stream.datalen == nfr.stream.datalen); - CU_ASSERT(0 == memcmp(fr.stream.data, nfr.stream.data, fr.stream.datalen)); + CU_ASSERT(1 == nfr.stream.datacnt); + CU_ASSERT(fr.stream.data[0].len == nfr.stream.data[0].len); + CU_ASSERT(0 == memcmp(fr.stream.data[0].base, nfr.stream.data[0].base, + fr.stream.data[0].len)); /* Make sure that we check the length properly. */ for (i = 1; i < framelen; ++i) { @@ -426,8 +438,9 @@ void test_ngtcp2_pkt_encode_stream_frame(void) { fr.stream.fin = 1; fr.stream.stream_id = 0xf1f2f3f4u; fr.stream.offset = 0x31f2f3f4f5f6f7f8llu; - fr.stream.datalen = strsize(data); - fr.stream.data = data; + fr.stream.datacnt = 1; + fr.stream.data[0].len = strsize(data); + fr.stream.data[0].base = (uint8_t *)data; framelen = 1 + 8 + 8 + 1 + 17; diff --git a/tests/ngtcp2_psl_test.c b/tests/ngtcp2_psl_test.c index 93d277a9653cd5037c0c2254f89c41af3dca3cd8..862960ce1b2427cc2548d8736097f7c0d3e04676 100644 --- a/tests/ngtcp2_psl_test.c +++ b/tests/ngtcp2_psl_test.c @@ -37,7 +37,6 @@ void test_ngtcp2_psl_insert(void) { ngtcp2_psl psl; ngtcp2_mem *mem = ngtcp2_mem_default(); size_t i; - const ngtcp2_range *pr; ngtcp2_range r; ngtcp2_psl_it it; @@ -46,16 +45,16 @@ void test_ngtcp2_psl_insert(void) { for (i = 0; i < arraylen(keys); ++i) { ngtcp2_psl_insert(&psl, NULL, &keys[i], NULL); it = ngtcp2_psl_lower_bound(&psl, &keys[i]); - - CU_ASSERT(ngtcp2_range_eq(&keys[i], ngtcp2_psl_it_range(&it))); + r = ngtcp2_psl_it_range(&it); + CU_ASSERT(ngtcp2_range_eq(&keys[i], &r)); } for (i = 0; i < arraylen(keys); ++i) { ngtcp2_psl_remove(&psl, NULL, &keys[i]); it = ngtcp2_psl_lower_bound(&psl, &keys[i]); - pr = ngtcp2_psl_it_range(&it); + r = ngtcp2_psl_it_range(&it); - CU_ASSERT(keys[i].end <= pr->begin); + CU_ASSERT(keys[i].end <= r.begin); } ngtcp2_psl_free(&psl); @@ -71,21 +70,21 @@ void test_ngtcp2_psl_insert(void) { /* Removing [7, 8) requires relocation */ ngtcp2_range_init(&r, 7, 8); ngtcp2_psl_remove(&psl, &it, &r); - pr = ngtcp2_psl_it_range(&it); + r = ngtcp2_psl_it_range(&it); - CU_ASSERT(8 == pr->begin); - CU_ASSERT(9 == pr->end); + CU_ASSERT(8 == r.begin); + CU_ASSERT(9 == r.end); it = ngtcp2_psl_lower_bound(&psl, &r); - pr = ngtcp2_psl_it_range(&it); + r = ngtcp2_psl_it_range(&it); - CU_ASSERT(8 == pr->begin); - CU_ASSERT(9 == pr->end); + CU_ASSERT(8 == r.begin); + CU_ASSERT(9 == r.end); - pr = &psl.head->nodes[0].range; + r = psl.head->nodes[0].range; - CU_ASSERT(8 == pr->begin); - CU_ASSERT(9 == pr->end); + CU_ASSERT(8 == r.begin); + CU_ASSERT(9 == r.end); ngtcp2_psl_free(&psl); @@ -100,16 +99,16 @@ void test_ngtcp2_psl_insert(void) { ngtcp2_range_init(&r, 63, 64); ngtcp2_psl_remove(&psl, &it, &r); - pr = ngtcp2_psl_it_range(&it); + r = ngtcp2_psl_it_range(&it); - CU_ASSERT(64 == pr->begin); - CU_ASSERT(65 == pr->end); + CU_ASSERT(64 == r.begin); + CU_ASSERT(65 == r.end); it = ngtcp2_psl_lower_bound(&psl, &r); - pr = ngtcp2_psl_it_range(&it); + r = ngtcp2_psl_it_range(&it); - CU_ASSERT(64 == pr->begin); - CU_ASSERT(65 == pr->end); + CU_ASSERT(64 == r.begin); + CU_ASSERT(65 == r.end); ngtcp2_psl_free(&psl); diff --git a/tests/ngtcp2_strm_test.c b/tests/ngtcp2_strm_test.c new file mode 100644 index 0000000000000000000000000000000000000000..e3b913e95d55bcdcf026ac01e0efd65788f198b7 --- /dev/null +++ b/tests/ngtcp2_strm_test.c @@ -0,0 +1,253 @@ +/* + * ngtcp2 + * + * Copyright (c) 2018 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "ngtcp2_strm_test.h" + +#include <CUnit/CUnit.h> + +#include "ngtcp2_strm.h" +#include "ngtcp2_test_helper.h" + +static uint8_t nulldata[1024]; + +static void setup_strm_streamfrq_fixture(ngtcp2_strm *strm, ngtcp2_mem *mem) { + ngtcp2_stream_frame_chain *frc; + ngtcp2_vec *data; + + ngtcp2_strm_init(strm, 0, NGTCP2_STRM_FLAG_NONE, 0, 0, NULL, mem); + + ngtcp2_stream_frame_chain_new(&frc, mem); + frc->fr.type = NGTCP2_FRAME_STREAM; + frc->fr.fin = 0; + frc->fr.offset = 0; + frc->fr.datacnt = 2; + data = frc->fr.data; + data[0].len = 11; + data[0].base = nulldata; + data[1].len = 19; + data[1].base = nulldata + 11; + + ngtcp2_strm_streamfrq_push(strm, frc); + + ngtcp2_stream_frame_chain_new(&frc, mem); + frc->fr.type = NGTCP2_FRAME_STREAM; + frc->fr.fin = 0; + frc->fr.offset = 30; + frc->fr.datacnt = 2; + data = frc->fr.data; + data[0].len = 17; + data[0].base = nulldata + 30; + data[1].len = 29; + data[1].base = nulldata + 30 + 17; + + ngtcp2_strm_streamfrq_push(strm, frc); + + ngtcp2_stream_frame_chain_new(&frc, mem); + frc->fr.type = NGTCP2_FRAME_STREAM; + frc->fr.fin = 0; + frc->fr.offset = 76; + frc->fr.datacnt = 2; + data = frc->fr.data; + data[0].len = 31; + data[0].base = nulldata + 256; + data[1].len = 1; + data[1].base = nulldata + 512; + + ngtcp2_strm_streamfrq_push(strm, frc); +} + +void test_ngtcp2_strm_streamfrq_pop(void) { + ngtcp2_strm strm; + ngtcp2_stream_frame_chain *frc; + ngtcp2_mem *mem = ngtcp2_mem_default(); + int rv; + ngtcp2_vec *data; + + /* Get first chain */ + setup_strm_streamfrq_fixture(&strm, mem); + + frc = NULL; + rv = ngtcp2_strm_streamfrq_pop(&strm, &frc, 30); + + CU_ASSERT(0 == rv); + CU_ASSERT(2 == frc->fr.datacnt); + + data = frc->fr.data; + + CU_ASSERT(11 == data[0].len); + CU_ASSERT(19 == data[1].len); + CU_ASSERT(2 == ngtcp2_pq_size(&strm.streamfrq)); + + ngtcp2_stream_frame_chain_del(frc, mem); + ngtcp2_strm_free(&strm); + + /* Get merged chain */ + setup_strm_streamfrq_fixture(&strm, mem); + + frc = NULL; + rv = ngtcp2_strm_streamfrq_pop(&strm, &frc, 76); + + CU_ASSERT(0 == rv); + CU_ASSERT(2 == frc->fr.datacnt); + + data = frc->fr.data; + + CU_ASSERT(11 == data[0].len); + CU_ASSERT(19 + 46 == data[1].len); + CU_ASSERT(1 == ngtcp2_pq_size(&strm.streamfrq)); + + ngtcp2_stream_frame_chain_del(frc, mem); + ngtcp2_strm_free(&strm); + + /* Get merged chain partially */ + setup_strm_streamfrq_fixture(&strm, mem); + + frc = NULL; + rv = ngtcp2_strm_streamfrq_pop(&strm, &frc, 75); + + CU_ASSERT(0 == rv); + CU_ASSERT(2 == frc->fr.datacnt); + + data = frc->fr.data; + + CU_ASSERT(11 == data[0].len); + CU_ASSERT(19 + 45 == data[1].len); + CU_ASSERT(2 == ngtcp2_pq_size(&strm.streamfrq)); + + ngtcp2_stream_frame_chain_del(frc, mem); + + frc = NULL; + rv = ngtcp2_strm_streamfrq_pop(&strm, &frc, 1); + + CU_ASSERT(0 == rv); + CU_ASSERT(75 == frc->fr.offset); + CU_ASSERT(1 == frc->fr.datacnt); + CU_ASSERT(1 == frc->fr.data[0].len); + CU_ASSERT(nulldata + 30 + 17 + 28 == frc->fr.data[0].base); + + ngtcp2_stream_frame_chain_del(frc, mem); + ngtcp2_strm_free(&strm); + + /* Not continuous merge */ + setup_strm_streamfrq_fixture(&strm, mem); + + frc = NULL; + rv = ngtcp2_strm_streamfrq_pop(&strm, &frc, 77); + + CU_ASSERT(0 == rv); + CU_ASSERT(3 == frc->fr.datacnt); + + data = frc->fr.data; + + CU_ASSERT(11 == data[0].len); + CU_ASSERT(19 + 46 == data[1].len); + CU_ASSERT(1 == data[2].len); + CU_ASSERT(nulldata + 256 == data[2].base); + CU_ASSERT(1 == ngtcp2_pq_size(&strm.streamfrq)); + + ngtcp2_stream_frame_chain_del(frc, mem); + + frc = NULL; + rv = ngtcp2_strm_streamfrq_pop(&strm, &frc, 1024); + + CU_ASSERT(0 == rv); + CU_ASSERT(77 == frc->fr.offset); + CU_ASSERT(2 == frc->fr.datacnt); + + data = frc->fr.data; + + CU_ASSERT(30 == data[0].len); + CU_ASSERT(nulldata + 256 + 1 == data[0].base); + + ngtcp2_stream_frame_chain_del(frc, mem); + ngtcp2_strm_free(&strm); + + /* offset gap */ + ngtcp2_strm_init(&strm, 0, NGTCP2_STRM_FLAG_NONE, 0, 0, NULL, mem); + + ngtcp2_stream_frame_chain_new(&frc, mem); + frc->fr.type = NGTCP2_FRAME_STREAM; + frc->fr.fin = 0; + frc->fr.offset = 0; + frc->fr.datacnt = 1; + data = frc->fr.data; + data[0].len = 11; + data[0].base = nulldata; + + ngtcp2_strm_streamfrq_push(&strm, frc); + + ngtcp2_stream_frame_chain_new(&frc, mem); + frc->fr.type = NGTCP2_FRAME_STREAM; + frc->fr.fin = 0; + frc->fr.offset = 30; + frc->fr.datacnt = 1; + data = frc->fr.data; + data[0].len = 17; + data[0].base = nulldata + 30; + + ngtcp2_strm_streamfrq_push(&strm, frc); + + frc = NULL; + rv = ngtcp2_strm_streamfrq_pop(&strm, &frc, 1024); + + CU_ASSERT(0 == rv); + CU_ASSERT(1 == frc->fr.datacnt); + CU_ASSERT(11 == frc->fr.data[0].len); + CU_ASSERT(1 == ngtcp2_pq_size(&strm.streamfrq)); + + ngtcp2_stream_frame_chain_del(frc, mem); + ngtcp2_strm_free(&strm); + + /* fin */ + ngtcp2_strm_init(&strm, 0, NGTCP2_STRM_FLAG_NONE, 0, 0, NULL, mem); + + ngtcp2_stream_frame_chain_new(&frc, mem); + frc->fr.type = NGTCP2_FRAME_STREAM; + frc->fr.fin = 0; + frc->fr.offset = 0; + frc->fr.datacnt = 1; + data = frc->fr.data; + data[0].len = 11; + data[0].base = nulldata; + + ngtcp2_strm_streamfrq_push(&strm, frc); + + ngtcp2_stream_frame_chain_new(&frc, mem); + frc->fr.type = NGTCP2_FRAME_STREAM; + frc->fr.fin = 1; + frc->fr.offset = 11; + frc->fr.datacnt = 0; + + ngtcp2_strm_streamfrq_push(&strm, frc); + + frc = NULL; + rv = ngtcp2_strm_streamfrq_pop(&strm, &frc, 1024); + + CU_ASSERT(0 == rv); + CU_ASSERT(1 == frc->fr.fin); + CU_ASSERT(1 == frc->fr.datacnt); + + ngtcp2_stream_frame_chain_del(frc, mem); + ngtcp2_strm_free(&strm); +} diff --git a/tests/ngtcp2_strm_test.h b/tests/ngtcp2_strm_test.h new file mode 100644 index 0000000000000000000000000000000000000000..687e265f87582de507c9891573c0eda5e7db4c33 --- /dev/null +++ b/tests/ngtcp2_strm_test.h @@ -0,0 +1,34 @@ +/* + * ngtcp2 + * + * Copyright (c) 2018 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef NGTCP2_STRM_TEST_H +#define NGTCP2_STRM_TEST_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +void test_ngtcp2_strm_streamfrq_pop(void); + +#endif /* NGTCP2_STRM_TEST_H */ diff --git a/tests/ngtcp2_vec_test.c b/tests/ngtcp2_vec_test.c new file mode 100644 index 0000000000000000000000000000000000000000..9ca0760421c4c76225f3217aa9e59643d9f7147e --- /dev/null +++ b/tests/ngtcp2_vec_test.c @@ -0,0 +1,224 @@ +/* + * ngtcp2 + * + * Copyright (c) 2018 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "ngtcp2_vec_test.h" + +#include <CUnit/CUnit.h> + +#include "ngtcp2_vec.h" +#include "ngtcp2_test_helper.h" + +void test_ngtcp2_vec_split(void) { + uint8_t nulldata[1024]; + ngtcp2_vec a[16], b[16]; + size_t acnt, bcnt; + + /* No split occurs */ + acnt = 1; + a[0].len = 135; + a[0].base = nulldata; + + bcnt = 0; + b[0].len = 0; + b[0].base = NULL; + + ngtcp2_vec_split(a, &acnt, b, &bcnt, 135); + + CU_ASSERT(1 == acnt); + CU_ASSERT(135 == a[0].len); + CU_ASSERT(nulldata == a[0].base); + CU_ASSERT(0 == bcnt); + CU_ASSERT(0 == b[0].len); + CU_ASSERT(NULL == b[0].base); + + /* Split once */ + acnt = 1; + a[0].len = 135; + a[0].base = nulldata; + + bcnt = 0; + b[0].len = 0; + b[0].base = NULL; + + ngtcp2_vec_split(a, &acnt, b, &bcnt, 87); + + CU_ASSERT(1 == acnt); + CU_ASSERT(87 == a[0].len); + CU_ASSERT(nulldata == a[0].base); + CU_ASSERT(1 == bcnt); + CU_ASSERT(48 == b[0].len); + CU_ASSERT(nulldata + 87 == b[0].base); + + /* Multiple a vector; split at ngtcp2_vec boundary */ + acnt = 2; + a[0].len = 33; + a[0].base = nulldata; + a[1].len = 89; + a[1].base = nulldata + 33; + + bcnt = 0; + b[0].len = 0; + b[0].base = NULL; + + ngtcp2_vec_split(a, &acnt, b, &bcnt, 33); + + CU_ASSERT(1 == acnt); + CU_ASSERT(33 == a[0].len); + CU_ASSERT(nulldata == a[0].base); + CU_ASSERT(1 == bcnt); + CU_ASSERT(89 == b[0].len); + CU_ASSERT(nulldata + 33 == b[0].base); + + /* Multiple a vector; not split at ngtcp2_vec boundary */ + acnt = 3; + a[0].len = 33; + a[0].base = nulldata; + a[1].len = 89; + a[1].base = nulldata + 33; + a[2].len = 211; + a[2].base = nulldata + 33 + 89; + + bcnt = 0; + b[0].len = 0; + b[0].base = NULL; + + ngtcp2_vec_split(a, &acnt, b, &bcnt, 34); + + CU_ASSERT(2 == acnt); + CU_ASSERT(33 == a[0].len); + CU_ASSERT(nulldata == a[0].base); + CU_ASSERT(1 == a[1].len); + CU_ASSERT(nulldata + 33 == a[1].base); + CU_ASSERT(2 == bcnt); + CU_ASSERT(88 == b[0].len); + CU_ASSERT(nulldata + 34 == b[0].base); + CU_ASSERT(211 == b[1].len); + CU_ASSERT(nulldata + 34 + 88 == b[1].base); +} + +void test_ngtcp2_vec_merge(void) { + uint8_t nulldata[1024]; + ngtcp2_vec a[16], b[16]; + size_t acnt, bcnt; + size_t nmerged; + + /* Merge one ngtcp2_vec completely */ + acnt = 1; + a[0].len = 33; + a[0].base = nulldata; + + bcnt = 1; + b[0].len = 11; + b[0].base = nulldata + 33; + + nmerged = ngtcp2_vec_merge(a, &acnt, b, &bcnt, 11, 16); + + CU_ASSERT(11 == nmerged); + CU_ASSERT(1 == acnt); + CU_ASSERT(44 == a[0].len); + CU_ASSERT(nulldata == a[0].base); + CU_ASSERT(0 == bcnt); + + /* Merge ngtcp2_vec partially */ + acnt = 1; + a[0].len = 33; + a[0].base = nulldata; + + bcnt = 1; + b[0].len = 11; + b[0].base = nulldata + 33; + + nmerged = ngtcp2_vec_merge(a, &acnt, b, &bcnt, 10, 16); + + CU_ASSERT(10 == nmerged); + CU_ASSERT(1 == acnt); + CU_ASSERT(43 == a[0].len); + CU_ASSERT(nulldata == a[0].base); + CU_ASSERT(1 == bcnt); + CU_ASSERT(1 == b[0].len); + CU_ASSERT(nulldata + 33 + 10 == b[0].base); + + /* Merge one ngtcp2_vec completely; data is not continuous */ + acnt = 1; + a[0].len = 33; + a[0].base = nulldata; + + bcnt = 1; + b[0].len = 11; + b[0].base = nulldata + 256; + + nmerged = ngtcp2_vec_merge(a, &acnt, b, &bcnt, 11, 16); + + CU_ASSERT(11 == nmerged); + CU_ASSERT(2 == acnt); + CU_ASSERT(33 == a[0].len); + CU_ASSERT(nulldata == a[0].base); + CU_ASSERT(11 == a[1].len); + CU_ASSERT(nulldata + 256 == a[1].base); + CU_ASSERT(0 == bcnt); + + /* Merge ngtcp2_vec partially; data is not continuous */ + acnt = 1; + a[0].len = 33; + a[0].base = nulldata; + + bcnt = 1; + b[0].len = 11; + b[0].base = nulldata + 256; + + nmerged = ngtcp2_vec_merge(a, &acnt, b, &bcnt, 10, 16); + + CU_ASSERT(10 == nmerged); + CU_ASSERT(2 == acnt); + CU_ASSERT(33 == a[0].len); + CU_ASSERT(nulldata == a[0].base); + CU_ASSERT(10 == a[1].len); + CU_ASSERT(nulldata + 256 == a[1].base); + CU_ASSERT(1 == bcnt); + CU_ASSERT(1 == b[0].len); + CU_ASSERT(nulldata + 256 + 10 == b[0].base); + + /* Merge ends at the ngtcp2_vec boundary */ + acnt = 1; + a[0].len = 33; + a[0].base = nulldata; + + bcnt = 2; + b[0].len = 11; + b[0].base = nulldata + 256; + b[1].len = 19; + b[1].base = nulldata + 256 + 11; + + nmerged = ngtcp2_vec_merge(a, &acnt, b, &bcnt, 11, 16); + + CU_ASSERT(11 == nmerged); + CU_ASSERT(2 == acnt); + CU_ASSERT(33 == a[0].len); + CU_ASSERT(nulldata == a[0].base); + CU_ASSERT(11 == a[1].len); + CU_ASSERT(nulldata + 256 == a[1].base); + CU_ASSERT(1 == bcnt); + CU_ASSERT(19 == b[0].len); + CU_ASSERT(nulldata + 256 + 11 == b[0].base); +} diff --git a/tests/ngtcp2_vec_test.h b/tests/ngtcp2_vec_test.h new file mode 100644 index 0000000000000000000000000000000000000000..c860778873a32fecbaf6b4e605764c19943746f9 --- /dev/null +++ b/tests/ngtcp2_vec_test.h @@ -0,0 +1,35 @@ +/* + * ngtcp2 + * + * Copyright (c) 2018 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef NGTCP2_VEC_TEST_H +#define NGTCP2_VEC_TEST_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +void test_ngtcp2_vec_split(void); +void test_ngtcp2_vec_merge(void); + +#endif /* NGTCP2_VEC_TEST_H */