diff --git a/examples/debug.cc b/examples/debug.cc index 57d2605a9ddcb09a28659023a556e58fed63ff77..0678213bb522984b58fbda6141317fbaef7f98be 100644 --- a/examples/debug.cc +++ b/examples/debug.cc @@ -137,6 +137,8 @@ std::string strframetype(uint8_t type) { return "STREAM_ID_NEEDED"; case NGTCP2_FRAME_NEW_CONNECTION_ID: return "NEW_CONNECTION_ID"; + case NGTCP2_FRAME_STOP_SENDING: + return "STOP_SENDING"; case NGTCP2_FRAME_ACK: return "ACK"; case NGTCP2_FRAME_STREAM: @@ -282,6 +284,11 @@ void print_frame(ngtcp2_dir dir, const ngtcp2_frame *fr) { fprintf(outfile, "seq=%u conn_id=%016" PRIx64 "\n", fr->new_connection_id.seq, fr->new_connection_id.conn_id); break; + case NGTCP2_FRAME_STOP_SENDING: + print_indent(); + fprintf(outfile, "stream_id=%08x error_code=%08x\n", + fr->stop_sending.stream_id, fr->stop_sending.error_code); + break; } } } // namespace diff --git a/lib/includes/ngtcp2/ngtcp2.h b/lib/includes/ngtcp2/ngtcp2.h index 0b41fef4c18cbfe8d96f28e5138cb89a10a6b270..c5887bb7dbe930f24189ffa4e12e7d90719aaf87 100644 --- a/lib/includes/ngtcp2/ngtcp2.h +++ b/lib/includes/ngtcp2/ngtcp2.h @@ -223,6 +223,7 @@ typedef enum { NGTCP2_FRAME_STREAM_BLOCKED = 0x09, NGTCP2_FRAME_STREAM_ID_NEEDED = 0x0a, NGTCP2_FRAME_NEW_CONNECTION_ID = 0x0b, + NGTCP2_FRAME_STOP_SENDING = 0x0c, NGTCP2_FRAME_ACK = 0xa0, NGTCP2_FRAME_STREAM = 0xc0 } ngtcp2_frame_type; @@ -347,6 +348,12 @@ typedef struct { uint64_t conn_id; } ngtcp2_new_connection_id; +typedef struct { + uint8_t type; + uint32_t stream_id; + uint32_t error_code; +} ngtcp2_stop_sending; + typedef union { uint8_t type; ngtcp2_stream stream; @@ -362,6 +369,7 @@ typedef union { ngtcp2_stream_blocked stream_blocked; ngtcp2_stream_id_needed stream_id_needed; ngtcp2_new_connection_id new_connection_id; + ngtcp2_stop_sending stop_sending; } ngtcp2_frame; typedef enum { diff --git a/lib/ngtcp2_pkt.c b/lib/ngtcp2_pkt.c index 241135152eaa4504ca07521dd9b2e01b1f9f2803..6e3c866301faa34c37c4192622e5048930d96e50 100644 --- a/lib/ngtcp2_pkt.c +++ b/lib/ngtcp2_pkt.c @@ -291,6 +291,9 @@ ssize_t ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload, case NGTCP2_FRAME_NEW_CONNECTION_ID: return ngtcp2_pkt_decode_new_connection_id_frame(&dest->new_connection_id, payload, payloadlen); + case NGTCP2_FRAME_STOP_SENDING: + return ngtcp2_pkt_decode_stop_sending_frame(&dest->stop_sending, payload, + payloadlen); default: return NGTCP2_ERR_INVALID_ARGUMENT; } @@ -739,6 +742,29 @@ ssize_t ngtcp2_pkt_decode_new_connection_id_frame( return (ssize_t)len; } +ssize_t ngtcp2_pkt_decode_stop_sending_frame(ngtcp2_stop_sending *dest, + const uint8_t *payload, + size_t payloadlen) { + size_t len = 1 + 4 + 4; + const uint8_t *p; + + if (payloadlen < len) { + return NGTCP2_ERR_INVALID_ARGUMENT; + } + + p = payload + 1; + + dest->type = NGTCP2_FRAME_STOP_SENDING; + dest->stream_id = ngtcp2_get_uint32(p); + p += 4; + dest->error_code = ngtcp2_get_uint32(p); + p += 4; + + assert((size_t)(p - payload) == len); + + return (ssize_t)len; +} + ssize_t ngtcp2_pkt_encode_frame(uint8_t *out, size_t outlen, const ngtcp2_frame *fr) { switch (fr->type) { @@ -774,6 +800,8 @@ ssize_t ngtcp2_pkt_encode_frame(uint8_t *out, size_t outlen, case NGTCP2_FRAME_NEW_CONNECTION_ID: return ngtcp2_pkt_encode_new_connection_id_frame(out, outlen, &fr->new_connection_id); + case NGTCP2_FRAME_STOP_SENDING: + return ngtcp2_pkt_encode_stop_sending_frame(out, outlen, &fr->stop_sending); default: return NGTCP2_ERR_INVALID_ARGUMENT; } @@ -1139,6 +1167,26 @@ ngtcp2_pkt_encode_new_connection_id_frame(uint8_t *out, size_t outlen, return (ssize_t)len; } +ssize_t ngtcp2_pkt_encode_stop_sending_frame(uint8_t *out, size_t outlen, + const ngtcp2_stop_sending *fr) { + size_t len = 1 + 4 + 4; + uint8_t *p; + + if (outlen < len) { + return NGTCP2_ERR_NOBUF; + } + + p = out; + + *p++ = NGTCP2_FRAME_STOP_SENDING; + p = ngtcp2_put_uint32be(p, fr->stream_id); + p = ngtcp2_put_uint32be(p, fr->error_code); + + assert((size_t)(p - out) == len); + + return (ssize_t)len; +} + int ngtcp2_pkt_verify(const uint8_t *pkt, size_t pktlen) { uint64_t a, b; diff --git a/lib/ngtcp2_pkt.h b/lib/ngtcp2_pkt.h index 847ae0bf0bbcc1c99a68f24bed46c8dca6953922..c22587858f841c4c168976bda0cf1f6ed8e02a52 100644 --- a/lib/ngtcp2_pkt.h +++ b/lib/ngtcp2_pkt.h @@ -348,6 +348,21 @@ ssize_t ngtcp2_pkt_decode_stream_id_needed_frame(ngtcp2_stream_id_needed *dest, ssize_t ngtcp2_pkt_decode_new_connection_id_frame( ngtcp2_new_connection_id *dest, const uint8_t *payload, size_t payloadlen); +/* + * ngtcp2_pkt_decode_stop_sending_frame decodes STOP_SENDING frame + * from |payload| of length |payloadlen|. The result is stored in the + * object pointed by |dest|. STOP_SENDING frame must start at + * `payload[0]`. This function finishes when it decodes one + * STOP_SENDING frame, and returns the exact number of bytes read to + * decode a frame if it succeeds, or one of the following negative + * error codes: + * + * NGTCP2_ERR_INVALID_ARGUMENT + * Payload is too short to include STOP_SENDING frame. + */ +ssize_t ngtcp2_pkt_decode_stop_sending_frame(ngtcp2_stop_sending *dest, + const uint8_t *payload, + size_t payloadlen); /* * ngtcp2_pkt_encode_stream_frame encodes STREAM frame |fr| into the * buffer pointed by |out| of length |outlen|. @@ -526,6 +541,19 @@ ssize_t ngtcp2_pkt_encode_new_connection_id_frame(uint8_t *out, size_t outlen, const ngtcp2_new_connection_id *fr); +/* + * ngtcp2_pkt_encode_stop_sending_frame encodes STOP_SENDING frame + * |fr| into the buffer pointed by |out| of length |outlen|. + * + * This function returns the number of bytes written if it succeeds, + * or one of the following negative error codes: + * + * NGTCP2_ERR_NOBUF + * Buffer does not have enough capacity to write a frame. + */ +ssize_t ngtcp2_pkt_encode_stop_sending_frame(uint8_t *out, size_t outlen, + const ngtcp2_stop_sending *fr); + /* * ngtcp2_pkt_adjust_pkt_num find the full 64 bits packet number for * |pkt_num|, which is expected to be least significant |n| bits. The diff --git a/tests/main.c b/tests/main.c index c2550f92c721a83e88e724b96658706cd6993326..6d218fd7beec2b0e3271a544950e9ea8581919b6 100644 --- a/tests/main.c +++ b/tests/main.c @@ -95,6 +95,8 @@ int main() { test_ngtcp2_pkt_encode_stream_id_needed_frame) || !CU_add_test(pSuite, "pkt_encode_new_connection_id_frame", test_ngtcp2_pkt_encode_new_connection_id_frame) || + !CU_add_test(pSuite, "pkt_encode_stop_sending_frame", + test_ngtcp2_pkt_encode_stop_sending_frame) || !CU_add_test(pSuite, "pkt_adjust_pkt_num", test_ngtcp2_pkt_adjust_pkt_num) || !CU_add_test(pSuite, "pkt_validate_ack", test_ngtcp2_pkt_validate_ack) || diff --git a/tests/ngtcp2_pkt_test.c b/tests/ngtcp2_pkt_test.c index 3ad44790bb4f4f9ae4282a1325bf464378c6ff8d..7cb0271f1524ae5719245dad0788010ade7d08d0 100644 --- a/tests/ngtcp2_pkt_test.c +++ b/tests/ngtcp2_pkt_test.c @@ -794,6 +794,28 @@ void test_ngtcp2_pkt_encode_new_connection_id_frame(void) { CU_ASSERT(fr.conn_id == nfr.conn_id); } +void test_ngtcp2_pkt_encode_stop_sending_frame(void) { + uint8_t buf[16]; + ngtcp2_stop_sending fr, nfr; + ssize_t rv; + size_t framelen = 1 + 4 + 4; + + fr.type = NGTCP2_FRAME_STOP_SENDING; + fr.stream_id = 0xf1f2f3f4u; + fr.error_code = 0xe1e2e3e4u; + + rv = ngtcp2_pkt_encode_stop_sending_frame(buf, sizeof(buf), &fr); + + CU_ASSERT((ssize_t)framelen == rv); + + rv = ngtcp2_pkt_decode_stop_sending_frame(&nfr, buf, framelen); + + CU_ASSERT((ssize_t)framelen == rv); + CU_ASSERT(fr.type == nfr.type); + CU_ASSERT(fr.stream_id == nfr.stream_id); + CU_ASSERT(fr.error_code == nfr.error_code); +} + void test_ngtcp2_pkt_adjust_pkt_num(void) { CU_ASSERT(0xaa831f94llu == ngtcp2_pkt_adjust_pkt_num(0xaa82f30ellu, 0x1f94, 16)); diff --git a/tests/ngtcp2_pkt_test.h b/tests/ngtcp2_pkt_test.h index 28318238a821b4402ddc77c4bd05796dbf52dd82..4ac809426111400e4cc9a4b8f112f062f5670d0c 100644 --- a/tests/ngtcp2_pkt_test.h +++ b/tests/ngtcp2_pkt_test.h @@ -46,6 +46,7 @@ void test_ngtcp2_pkt_encode_blocked_frame(void); void test_ngtcp2_pkt_encode_stream_blocked_frame(void); void test_ngtcp2_pkt_encode_stream_id_needed_frame(void); void test_ngtcp2_pkt_encode_new_connection_id_frame(void); +void test_ngtcp2_pkt_encode_stop_sending_frame(void); void test_ngtcp2_pkt_adjust_pkt_num(void); void test_ngtcp2_pkt_validate_ack(void);