Skip to content

Commit

Permalink
Merge pull request #1757 from private-octopus/datagram-capsule
Browse files Browse the repository at this point in the history
Datagram capsule and other picowt work
  • Loading branch information
huitema authored Sep 27, 2024
2 parents 25e0e48 + b74332f commit 401781f
Show file tree
Hide file tree
Showing 12 changed files with 179 additions and 103 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ else()
endif()

project(picoquic
VERSION 1.1.25.0
VERSION 1.1.25.1
DESCRIPTION "picoquic library"
LANGUAGES C CXX)

Expand Down
1 change: 1 addition & 0 deletions baton_app/baton_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ int wt_baton_client(char const * server_name, int server_port, char const * path
wt_baton_ctx_init(&baton_ctx, h3_ctx, NULL, NULL);
baton_ctx.cnx = cnx;
baton_ctx.is_client = 1;
baton_ctx.authority = server_name;
baton_ctx.server_path = path;

/* Create a stream context for the connect call. */
Expand Down
8 changes: 6 additions & 2 deletions picohttp/h3zero.c
Original file line number Diff line number Diff line change
Expand Up @@ -817,8 +817,8 @@ uint8_t * h3zero_encode_content_type(uint8_t * bytes, uint8_t * bytes_max, h3zer
}

uint8_t* h3zero_create_connect_header_frame(uint8_t* bytes, uint8_t* bytes_max,
uint8_t const* path, size_t path_length, char const* protocol, char const * origin,
char const* ua_string)
char const * authority, uint8_t const* path, size_t path_length, char const* protocol,
char const * origin, char const* ua_string)
{
if (bytes == NULL || bytes + 2 > bytes_max) {
return NULL;
Expand All @@ -836,6 +836,10 @@ uint8_t* h3zero_create_connect_header_frame(uint8_t* bytes, uint8_t* bytes_max,
if (protocol != NULL) {
bytes = h3zero_qpack_literal_plus_name_encode(bytes, bytes_max, (uint8_t*)":protocol", 9, (uint8_t*)protocol, strlen(protocol));
}
/* Authority. Use literal plus reference format */
if (authority != NULL) {
bytes = h3zero_qpack_literal_plus_ref_encode(bytes, bytes_max, H3ZERO_QPACK_AUTHORITY, (uint8_t const*)authority, strlen(authority));
}
/* Origin. Use literal plus ref format */
if (origin != NULL) {
bytes = h3zero_qpack_literal_plus_ref_encode(bytes, bytes_max, H3ZERO_QPACK_ORIGIN, (uint8_t*)origin, strlen(origin));
Expand Down
11 changes: 8 additions & 3 deletions picohttp/h3zero.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ extern "C" {
#define H3ZERO_USER_AGENT_STRING "H3Zero/1.0"

#define H3ZERO_CAPSULE_CLOSE_WEBTRANSPORT_SESSION 0x2843
#define H3ZERO_CAPSULE_DRAIN_WEBTRANSPORT_SESSION 0x78ae

typedef enum {
h3zero_frame_data = 0,
Expand Down Expand Up @@ -193,7 +194,11 @@ typedef struct st_h3zero_header_parts_t {
unsigned int path_is_huffman : 1;
} h3zero_header_parts_t;

/* Setting codes. */
/* Setting codes.
* This list includes the "extension" settings for datagrams and web
* transport, because we want to have common functions for coding and
* decoding setting values.
*/
#define h3zero_setting_reserved = 0x0
#define h3zero_setting_header_table_size 0x1
#define h3zero_setting_max_header_list_size 0x6
Expand Down Expand Up @@ -237,8 +242,8 @@ uint8_t* h3zero_create_request_header_frame_ex(uint8_t* bytes, uint8_t* bytes_ma
uint8_t const* path, size_t path_length, uint8_t const* range, size_t range_length,
char const* host, char const* ua_string);
uint8_t* h3zero_create_connect_header_frame(uint8_t* bytes, uint8_t* bytes_max,
uint8_t const* path, size_t path_length, char const* protocol, char const* origin,
char const* ua_string);
char const* authority, uint8_t const* path, size_t path_length, char const* protocol,
char const* origin, char const* ua_string);
uint8_t* h3zero_create_post_header_frame_ex(uint8_t* bytes, uint8_t* bytes_max,
uint8_t const* path, size_t path_length, uint8_t const* range, size_t range_length,
char const* host, h3zero_content_type_enum content_type, char const* ua_string);
Expand Down
76 changes: 53 additions & 23 deletions picohttp/h3zero_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,13 @@ int h3zero_protocol_init(picoquic_cnx_t* cnx)
int ret = 0;

settings.enable_connect_protocol = 1;

/* Web transport is only enabled if h3 datagrams are supported.
*/
if (cnx->local_parameters.max_datagram_frame_size > 0) {
settings.h3_datagram = 1;
settings.webtransport_max_sessions = 1;
}
settings.webtransport_max_sessions = 1;

settings_buffer[0] = (uint8_t)h3zero_stream_type_control;
if ((settings_last = h3zero_settings_encode(settings_buffer + 1, settings_buffer + sizeof(settings_buffer), &settings)) == NULL) {
Expand Down Expand Up @@ -871,10 +874,12 @@ int h3zero_process_remote_stream(picoquic_cnx_t* cnx,
void h3zero_forget_stream(picoquic_cnx_t* cnx,
h3zero_stream_ctx_t* stream_ctx)
{
if (stream_ctx != NULL && !stream_ctx->ps.stream_state.is_fin_sent) {
stream_ctx->ps.stream_state.is_fin_sent = 1;
picoquic_reset_stream(cnx, stream_ctx->stream_id, 0);
picoquic_set_app_stream_ctx(cnx, stream_ctx->stream_id, NULL);
if (stream_ctx != NULL){
if (!stream_ctx->ps.stream_state.is_fin_sent) {
stream_ctx->ps.stream_state.is_fin_sent = 1;
picoquic_reset_stream(cnx, stream_ctx->stream_id, 0);
}
picoquic_unlink_app_stream_ctx(cnx, stream_ctx->stream_id);
}
}

Expand Down Expand Up @@ -1386,18 +1391,25 @@ int h3zero_callback_data(picoquic_cnx_t* cnx,
stream_ctx = h3zero_find_or_create_stream(cnx, stream_id, ctx, 1, 1);
}
if (stream_ctx == NULL) {
ret = picoquic_stop_sending(cnx, stream_id, H3ZERO_INTERNAL_ERROR);
if (fin_or_event == picoquic_callback_stream_fin) {
if (length > 0) {
DBG_PRINTF("Received %zu bytes & FIN after stream %" PRIu64 " was discarded\n", length, stream_id);
}
}
else {
ret = picoquic_stop_sending(cnx, stream_id, H3ZERO_INTERNAL_ERROR);

if (ret == 0 && IS_BIDIR_STREAM_ID(stream_id)) {
ret = picoquic_reset_stream(cnx, stream_id, H3ZERO_INTERNAL_ERROR);
if (ret == 0 && IS_BIDIR_STREAM_ID(stream_id)) {
ret = picoquic_reset_stream(cnx, stream_id, H3ZERO_INTERNAL_ERROR);
}
ret = -1;
}
ret = -1;
}
else {
picoquic_set_app_stream_ctx(cnx, stream_id, stream_ctx);
}
}
if (ret == 0) {
if (ret == 0 && stream_ctx != NULL) {
if (stream_ctx->is_upgraded) {
ret = h3zero_post_data_or_fin(cnx, bytes, length, fin_or_event, stream_ctx);
}
Expand Down Expand Up @@ -1577,7 +1589,7 @@ int h3zero_callback_datagram(picoquic_cnx_t* cnx, uint8_t* bytes, size_t length,
/* find the control stream context, using the full stream ID */
h3zero_stream_prefix_t* prefix_ctx = h3zero_find_stream_prefix(h3_ctx, quarter_stream_id*4);

if (prefix_ctx->function_call == NULL) {
if (prefix_ctx == NULL || prefix_ctx->function_call == NULL) {
/* Should signal the error HTTP_DATAGRAM_ERROR */
} else {
h3zero_stream_ctx_t* stream_ctx = h3zero_find_stream(h3_ctx, prefix_ctx->prefix);
Expand All @@ -1591,6 +1603,23 @@ int h3zero_callback_datagram(picoquic_cnx_t* cnx, uint8_t* bytes, size_t length,
return ret;
}

/* Arrival of a datagram capsule */
void h3zero_receive_datagram_capsule(picoquic_cnx_t* cnx, h3zero_stream_ctx_t* stream_ctx, h3zero_capsule_t* capsule, h3zero_callback_ctx_t* h3_ctx)
{
if (stream_ctx == NULL) {
/* Application is not yet ready -- just ignore the datagram */
}
else {
h3zero_stream_prefix_t* prefix_ctx = h3zero_find_stream_prefix(h3_ctx, stream_ctx->stream_id);
if ( prefix_ctx == NULL || prefix_ctx->function_call == NULL) {
/* Should signal the error HTTP_DATAGRAM_ERROR */
}
else {
prefix_ctx->function_call(cnx, capsule->capsule_buffer, capsule->capsule_length, picohttp_callback_post_datagram, stream_ctx, prefix_ctx->function_ctx);
}
}
}

typedef struct st_h3zero_prepare_datagram_ctx_t {
void* picoquic_context;
size_t picoquic_space;
Expand Down Expand Up @@ -1762,13 +1791,14 @@ int h3zero_callback(picoquic_cnx_t* cnx,
stream_ctx = h3zero_find_stream(ctx, stream_id);
}
if (stream_ctx != NULL) {
/* reset post callback. */
if (stream_ctx->path_callback != NULL) {
/* reset post callback. */
ret = stream_ctx->path_callback(cnx, NULL, 0, picohttp_callback_reset, stream_ctx, stream_ctx->path_callback_ctx);
}

/* If a file is open on a client, close and do the accounting. */
ret = h3zero_client_close_stream(cnx, ctx, stream_ctx);
else {
/* If a file is open on a client, close and do the accounting. */
ret = h3zero_client_close_stream(cnx, ctx, stream_ctx);
}
}
if (IS_BIDIR_STREAM_ID(stream_id)) {
picoquic_reset_stream(cnx, stream_id, 0);
Expand Down Expand Up @@ -1952,8 +1982,8 @@ const uint8_t* h3zero_settings_decode(const uint8_t* bytes, const uint8_t* bytes

void h3zero_release_capsule(h3zero_capsule_t* capsule)
{
if (capsule->capsule != NULL) {
free(capsule->capsule);
if (capsule->capsule_buffer != NULL) {
free(capsule->capsule_buffer);
}
memset(capsule, 0, sizeof(h3zero_capsule_t));
}
Expand Down Expand Up @@ -2020,15 +2050,15 @@ const uint8_t* h3zero_accumulate_capsule(const uint8_t* bytes, const uint8_t* by
if (capsule->capsule_buffer_size < capsule->capsule_length) {
uint8_t* capsule_buffer = (uint8_t*)malloc(capsule->capsule_length);
if (capsule_buffer != NULL && capsule->value_read > 0) {
memcpy(capsule_buffer, capsule->capsule, capsule->value_read);
memcpy(capsule_buffer, capsule->capsule_buffer, capsule->value_read);
}
if (capsule->capsule != NULL) {
free(capsule->capsule);
if (capsule->capsule_buffer != NULL) {
free(capsule->capsule_buffer);
}
capsule->capsule = capsule_buffer;
capsule->capsule_buffer = capsule_buffer;
capsule->capsule_buffer_size = capsule->capsule_length;
}
if (capsule->capsule == NULL) {
if (capsule->capsule_buffer == NULL) {
capsule->value_read = 0;
capsule->capsule_buffer_size = 0;
bytes = NULL;
Expand All @@ -2037,7 +2067,7 @@ const uint8_t* h3zero_accumulate_capsule(const uint8_t* bytes, const uint8_t* by
if (capsule->value_read + available > capsule->capsule_length) {
available = capsule->capsule_length - capsule->value_read;
}
memcpy(capsule->capsule + capsule->value_read, bytes, available);
memcpy(capsule->capsule_buffer + capsule->value_read, bytes, available);
bytes += available;
capsule->value_read += available;
if (capsule->value_read >= capsule->capsule_length) {
Expand Down
5 changes: 4 additions & 1 deletion picohttp/h3zero_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ extern "C" {
void h3zero_init_stream_tree(picosplay_tree_t* h3_stream_tree);

/* Handling of capsules */
#define h3zero_capsule_type_datagram 0x00

#define H3ZERO_CAPSULE_HEADER_SIZE_MAX 16
typedef struct st_h3zero_capsule_t {
uint8_t header_buffer[H3ZERO_CAPSULE_HEADER_SIZE_MAX];
Expand All @@ -148,7 +150,7 @@ extern "C" {
size_t capsule_buffer_size;
uint64_t capsule_type;
size_t capsule_length;
uint8_t* capsule;
uint8_t* capsule_buffer;
unsigned int is_length_known:1;
unsigned int is_stored;
} h3zero_capsule_t;
Expand Down Expand Up @@ -240,6 +242,7 @@ extern "C" {
h3zero_content_type_enum h3zero_get_content_type_by_path(const char *path);

int h3zero_set_datagram_ready(picoquic_cnx_t* cnx, uint64_t stream_id);
void h3zero_receive_datagram_capsule(picoquic_cnx_t* cnx, h3zero_stream_ctx_t* stream_ctx, h3zero_capsule_t* capsule, h3zero_callback_ctx_t* h3_ctx);
uint8_t* h3zero_provide_datagram_buffer(void* context, size_t length, int ready_to_send);

int h3zero_callback(picoquic_cnx_t* cnx,
Expand Down
6 changes: 4 additions & 2 deletions picohttp/pico_webtransport.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ extern "C" {
* this is defined in h3zero_common.h
* wt_ctx: application level context for that connection.
*/
int picowt_connect(picoquic_cnx_t* cnx, h3zero_callback_ctx_t* ctx, h3zero_stream_ctx_t* stream_ctx, const char* path, picohttp_post_data_cb_fn wt_callback, void* wt_ctx);
int picowt_connect(picoquic_cnx_t* cnx, h3zero_callback_ctx_t* ctx, h3zero_stream_ctx_t* stream_ctx, const char* authority, const char* path, picohttp_post_data_cb_fn wt_callback, void* wt_ctx);
/* Send capsule to close web transport session,
* and close web transport control stream.
*/
Expand All @@ -62,9 +62,11 @@ extern "C" {
size_t error_msg_len;
} picowt_capsule_t;

int picowt_receive_capsule(picoquic_cnx_t *cnx, const uint8_t* bytes, const uint8_t* bytes_max, picowt_capsule_t* capsule);
int picowt_receive_capsule(picoquic_cnx_t* cnx, h3zero_stream_ctx_t* stream_ctx, const uint8_t* bytes, const uint8_t* bytes_max, picowt_capsule_t* capsule, h3zero_callback_ctx_t* h3_ctx);
void picowt_release_capsule(picowt_capsule_t* capsule);

void picowt_deregister(picoquic_cnx_t* cnx, h3zero_callback_ctx_t* h3_ctx, h3zero_stream_ctx_t* control_stream_ctx);

/**
* Create local stream: when a stream is created locally.
* Send the stream header. Associate the stream with a per_stream
Expand Down
Loading

0 comments on commit 401781f

Please sign in to comment.