Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions include/quicly.h
Original file line number Diff line number Diff line change
Expand Up @@ -1052,11 +1052,12 @@ static int quicly_stream_has_receive_side(int is_client, quicly_stream_id_t stre
*/
static int quicly_stream_is_self_initiated(quicly_stream_t *stream);
/**
* Registers a datagram frame payload to be sent. When the applications calls `quicly_send` the first time after registering the
* datagram frame payload, the payload is either sent or the reference is discarded. Until then, it is the caller's responsibility
* to retain the memory pointed to by `payload`. At the moment, DATAFRAM frames are not congestion controlled.
* Sends QUIC DATAGRAM frames. Some of the frames being provided may get dropped.
* Notes:
* * At the moment, emission of QUIC packets carrying DATAGRAM frames is not congestion controlled.
* * While the API is designed to look like synchronous, application still has to call `quicly_send` for the time being.
*/
void quicly_set_datagram_frame(quicly_conn_t *conn, ptls_iovec_t payload);
void quicly_send_datagram_frames(quicly_conn_t *conn, ptls_iovec_t *datagrams, size_t num_datagrams);
/**
*
*/
Expand Down
58 changes: 41 additions & 17 deletions lib/quicly.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,9 +337,12 @@ struct st_quicly_conn_t {
*/
quicly_retire_cid_set_t retire_cid;
/**
* DATAGRAM frame payload to be sent
* payload of DATAGRAM frames to be sent
*/
ptls_iovec_t datagram_frame_payload;
struct {
ptls_iovec_t payloads[10];
size_t count;
} datagram_frame_payloads;
} egress;
/**
* crypto data
Expand Down Expand Up @@ -552,6 +555,15 @@ static void dispose_cipher(struct st_quicly_cipher_context_t *ctx)
ptls_cipher_free(ctx->header_protection);
}

static void clear_datagram_frame_payloads(quicly_conn_t *conn)
{
for (size_t i = 0; i != conn->egress.datagram_frame_payloads.count; ++i) {
free(conn->egress.datagram_frame_payloads.payloads[i].base);
conn->egress.datagram_frame_payloads.payloads[i] = ptls_iovec_init(NULL, 0);
}
conn->egress.datagram_frame_payloads.count = 0;
}

static int is_retry(quicly_conn_t *conn)
{
return conn->retry_scid.len != UINT8_MAX;
Expand Down Expand Up @@ -1495,6 +1507,7 @@ void quicly_free(quicly_conn_t *conn)
#endif

destroy_all_streams(conn, 0, 1);
clear_datagram_frame_payloads(conn);

quicly_maxsender_dispose(&conn->ingress.max_data.sender);
quicly_maxsender_dispose(&conn->ingress.max_streams.uni);
Expand Down Expand Up @@ -2758,14 +2771,12 @@ static int on_ack_retire_connection_id(quicly_sentmap_t *map, const quicly_sent_

static int should_send_datagram_frame(quicly_conn_t *conn)
{
if (conn->egress.datagram_frame_payload.base == NULL)
if (conn->egress.datagram_frame_payloads.count == 0)
return 0;
if (conn->application == NULL)
return 0;
if (conn->application->cipher.egress.key.aead == NULL)
return 0;
if (conn->super.remote.transport_params.max_datagram_frame_size < conn->egress.datagram_frame_payload.len)
return 0;
return 1;
}

Expand Down Expand Up @@ -4193,15 +4204,19 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s)
* This is because we do not have a way to retract the generation of a QUIC packet.
* * Does not notify the application that the frame was dropped internally. */
if (should_send_datagram_frame(conn)) {
size_t required_space = quicly_datagram_frame_capacity(conn->egress.datagram_frame_payload);
if ((ret = _do_allocate_frame(conn, s, required_space, 1)) != 0)
goto Exit;
if (s->dst_end - s->dst >= required_space) {
s->dst = quicly_encode_datagram_frame(s->dst, conn->egress.datagram_frame_payload);
QUICLY_PROBE(DATAGRAM_SEND, conn, conn->stash.now, conn->egress.datagram_frame_payload.base,
conn->egress.datagram_frame_payload.len);
conn->egress.datagram_frame_payload = ptls_iovec_init(NULL, 0);
++conn->super.stats.num_frames_sent.datagram;
for (size_t i = 0; i != conn->egress.datagram_frame_payloads.count; ++i) {
ptls_iovec_t *payload = conn->egress.datagram_frame_payloads.payloads + i;
size_t required_space = quicly_datagram_frame_capacity(*payload);
if ((ret = _do_allocate_frame(conn, s, required_space, 1)) != 0)
goto Exit;
if (s->dst_end - s->dst >= required_space) {
s->dst = quicly_encode_datagram_frame(s->dst, *payload);
QUICLY_PROBE(DATAGRAM_SEND, conn, conn->stash.now, payload->base, payload->len);
} else {
/* FIXME: At the moment, we add a padding because we do not have a way to reclaim allocated space, and because
* it is forbidden to send an empty QUIC packet. */
*s->dst++ = QUICLY_FRAME_TYPE_PADDING;
}
}
}
if (!ack_only) {
Expand Down Expand Up @@ -4332,9 +4347,18 @@ static int do_send(quicly_conn_t *conn, quicly_send_context_t *s)
return ret;
}

void quicly_set_datagram_frame(quicly_conn_t *conn, ptls_iovec_t payload)
void quicly_send_datagram_frames(quicly_conn_t *conn, ptls_iovec_t *datagrams, size_t num_datagrams)
{
conn->egress.datagram_frame_payload = payload;
for (size_t i = 0; i != num_datagrams; ++i) {
if (conn->egress.datagram_frame_payloads.count == PTLS_ELEMENTSOF(conn->egress.datagram_frame_payloads.payloads))
break;
void *copied;
if ((copied = malloc(datagrams[i].len)) == NULL)
break;
memcpy(copied, datagrams[i].base, datagrams[i].len);
conn->egress.datagram_frame_payloads.payloads[conn->egress.datagram_frame_payloads.count++] =
ptls_iovec_init(copied, datagrams[i].len);
}
}

int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *src, struct iovec *datagrams, size_t *num_datagrams,
Expand Down Expand Up @@ -4392,7 +4416,7 @@ int quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *s
assert_consistency(conn, 1);

Exit:
conn->egress.datagram_frame_payload = ptls_iovec_init(NULL, 0);
clear_datagram_frame_payloads(conn);
if (s.num_datagrams != 0) {
*dest = conn->super.remote.address;
*src = conn->super.local.address;
Expand Down
25 changes: 3 additions & 22 deletions src/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ FILE *quicly_trace_fp = NULL;
static unsigned verbosity = 0;
static int suppress_output = 0, send_datagram_frame = 0;
static int64_t enqueue_requests_at = 0, request_interval = 0;
static void *datagram_frame_payload_buf;

static void hexdump(const char *title, const uint8_t *p, size_t l)
{
Expand Down Expand Up @@ -489,34 +488,15 @@ static int send_pending(int fd, quicly_conn_t *conn)
if ((ret = quicly_send(conn, &dest, &src, packets, &num_packets, buf, sizeof(buf))) == 0 && num_packets != 0)
send_packets(fd, &dest.sa, packets, num_packets);

if (datagram_frame_payload_buf != NULL) {
free(datagram_frame_payload_buf);
datagram_frame_payload_buf = NULL;
}

return ret;
}

static void set_datagram_frame(quicly_conn_t *conn, ptls_iovec_t payload)
{
if (datagram_frame_payload_buf != NULL)
free(datagram_frame_payload_buf);

/* replace payload.base with an allocated buffer */
datagram_frame_payload_buf = malloc(payload.len);
memcpy(datagram_frame_payload_buf, payload.base, payload.len);
payload.base = datagram_frame_payload_buf;

/* set data to be sent. The buffer is being freed in `send_pending` after `quicly_send` is being called. */
quicly_set_datagram_frame(conn, payload);
}

static void on_receive_datagram_frame(quicly_receive_datagram_frame_t *self, quicly_conn_t *conn, ptls_iovec_t payload)
{
printf("DATAGRAM: %.*s\n", (int)payload.len, payload.base);
/* send responds with a datagram frame */
if (!quicly_is_client(conn))
set_datagram_frame(conn, payload);
quicly_send_datagram_frames(conn, &payload, 1);
}

static void enqueue_requests(quicly_conn_t *conn)
Expand Down Expand Up @@ -618,7 +598,8 @@ static int run_client(int fd, struct sockaddr *sa, const char *host)
quicly_receive(conn, NULL, &sa, &packet);
if (send_datagram_frame && quicly_connection_is_ready(conn)) {
const char *message = "hello datagram!";
set_datagram_frame(conn, ptls_iovec_init(message, strlen(message)));
ptls_iovec_t datagram = ptls_iovec_init(message, strlen(message));
quicly_send_datagram_frames(conn, &datagram, 1);
send_datagram_frame = 0;
}
}
Expand Down