* ossl_quic_tserver_has_read_ended() to identify this condition.
*/
int ossl_quic_tserver_read(QUIC_TSERVER *srv,
+ uint64_t stream_id,
unsigned char *buf,
size_t buf_len,
size_t *bytes_read);
/*
* Returns 1 if the read part of the stream has ended normally.
*/
-int ossl_quic_tserver_has_read_ended(QUIC_TSERVER *srv);
+int ossl_quic_tserver_has_read_ended(QUIC_TSERVER *srv, uint64_t stream_id);
/*
* Attempts to write to stream 0. Writes the number of bytes consumed to
* Returns 0 if connection is not currently active.
*/
int ossl_quic_tserver_write(QUIC_TSERVER *srv,
+ uint64_t stream_id,
const unsigned char *buf,
size_t buf_len,
size_t *bytes_written);
/*
* Signals normal end of the stream.
*/
-int ossl_quic_tserver_conclude(QUIC_TSERVER *srv);
+int ossl_quic_tserver_conclude(QUIC_TSERVER *srv, uint64_t stream_id);
+
+/*
+ * Create a server-initiated stream. The stream ID of the newly
+ * created stream is written to *stream_id.
+ */
+int ossl_quic_tserver_stream_new(QUIC_TSERVER *srv,
+ int is_uni,
+ uint64_t *stream_id);
BIO *ossl_quic_tserver_get0_rbio(QUIC_TSERVER *srv);
/* SSL for the underlying TLS connection */
SSL *tls;
- /* Our single bidirectional application data stream. */
- QUIC_STREAM *stream0;
-
/* The current peer L4 address. AF_UNSPEC if we do not have a peer yet. */
BIO_ADDR cur_peer_addr;
|| !ossl_quic_channel_set_net_wbio(srv->ch, srv->args.net_wbio))
goto err;
- srv->stream0 = ossl_quic_channel_get_stream_by_id(srv->ch, 0);
- if (srv->stream0 == NULL)
- goto err;
-
return srv;
err:
}
int ossl_quic_tserver_read(QUIC_TSERVER *srv,
+ uint64_t stream_id,
unsigned char *buf,
size_t buf_len,
size_t *bytes_read)
{
int is_fin = 0;
+ QUIC_STREAM *qs;
if (!ossl_quic_channel_is_active(srv->ch))
return 0;
- if (srv->stream0->recv_fin_retired)
+ qs = ossl_quic_stream_map_get_by_id(ossl_quic_channel_get_qsm(srv->ch),
+ stream_id);
+ if (qs == NULL) {
+ int is_client_init
+ = ((stream_id & QUIC_STREAM_INITIATOR_MASK)
+ == QUIC_STREAM_INITIATOR_CLIENT);
+
+ /*
+ * A client-initiated stream might spontaneously come into existence, so
+ * allow trying to read on a client-initiated stream before it exists.
+ * Otherwise, fail.
+ */
+ if (!is_client_init)
+ return 0;
+
+ *bytes_read = 0;
+ return 1;
+ }
+
+ if (qs->recv_fin_retired || qs->rstream == NULL)
return 0;
- if (!ossl_quic_rstream_read(srv->stream0->rstream, buf, buf_len,
+ if (!ossl_quic_rstream_read(qs->rstream, buf, buf_len,
bytes_read, &is_fin))
return 0;
ossl_statm_get_rtt_info(ossl_quic_channel_get_statm(srv->ch), &rtt_info);
- if (!ossl_quic_rxfc_on_retire(&srv->stream0->rxfc, *bytes_read,
+ if (!ossl_quic_rxfc_on_retire(&qs->rxfc, *bytes_read,
rtt_info.smoothed_rtt))
return 0;
}
if (is_fin)
- srv->stream0->recv_fin_retired = 1;
+ qs->recv_fin_retired = 1;
if (*bytes_read > 0)
- ossl_quic_stream_map_update_state(ossl_quic_channel_get_qsm(srv->ch),
- srv->stream0);
+ ossl_quic_stream_map_update_state(ossl_quic_channel_get_qsm(srv->ch), qs);
return 1;
}
-int ossl_quic_tserver_has_read_ended(QUIC_TSERVER *srv)
+int ossl_quic_tserver_has_read_ended(QUIC_TSERVER *srv, uint64_t stream_id)
{
- return srv->stream0->recv_fin_retired;
+ QUIC_STREAM *qs;
+
+ qs = ossl_quic_stream_map_get_by_id(ossl_quic_channel_get_qsm(srv->ch),
+ stream_id);
+
+ return qs != NULL && qs->recv_fin_retired;
}
int ossl_quic_tserver_write(QUIC_TSERVER *srv,
+ uint64_t stream_id,
const unsigned char *buf,
size_t buf_len,
size_t *bytes_written)
{
+ QUIC_STREAM *qs;
+
if (!ossl_quic_channel_is_active(srv->ch))
return 0;
- if (!ossl_quic_sstream_append(srv->stream0->sstream,
+ qs = ossl_quic_stream_map_get_by_id(ossl_quic_channel_get_qsm(srv->ch),
+ stream_id);
+ if (qs == NULL || qs->sstream == NULL)
+ return 0;
+
+ if (!ossl_quic_sstream_append(qs->sstream,
buf, buf_len, bytes_written))
return 0;
* We have appended at least one byte to the stream. Potentially mark
* the stream as active, depending on FC.
*/
- ossl_quic_stream_map_update_state(ossl_quic_channel_get_qsm(srv->ch),
- srv->stream0);
+ ossl_quic_stream_map_update_state(ossl_quic_channel_get_qsm(srv->ch), qs);
/* Try and send. */
ossl_quic_tserver_tick(srv);
return 1;
}
-int ossl_quic_tserver_conclude(QUIC_TSERVER *srv)
+int ossl_quic_tserver_conclude(QUIC_TSERVER *srv, uint64_t stream_id)
{
+ QUIC_STREAM *qs;
+
if (!ossl_quic_channel_is_active(srv->ch))
return 0;
- if (!ossl_quic_sstream_get_final_size(srv->stream0->sstream, NULL)) {
- ossl_quic_sstream_fin(srv->stream0->sstream);
- ossl_quic_stream_map_update_state(ossl_quic_channel_get_qsm(srv->ch),
- srv->stream0);
+ qs = ossl_quic_stream_map_get_by_id(ossl_quic_channel_get_qsm(srv->ch),
+ stream_id);
+ if (qs == NULL || qs->sstream == NULL)
+ return 0;
+
+ if (!ossl_quic_sstream_get_final_size(qs->sstream, NULL)) {
+ ossl_quic_sstream_fin(qs->sstream);
+ ossl_quic_stream_map_update_state(ossl_quic_channel_get_qsm(srv->ch), qs);
}
ossl_quic_tserver_tick(srv);
return 1;
}
+int ossl_quic_tserver_stream_new(QUIC_TSERVER *srv,
+ int is_uni,
+ uint64_t *stream_id)
+{
+ QUIC_STREAM *qs;
+
+ if (!ossl_quic_channel_is_active(srv->ch))
+ return 0;
+
+ if ((qs = ossl_quic_channel_new_stream_local(srv->ch, is_uni)) == NULL)
+ return 0;
+
+ *stream_id = qs->id;
+ return 1;
+}
+
BIO *ossl_quic_tserver_get0_rbio(QUIC_TSERVER *srv)
{
return srv->args.net_rbio;
}
if (c_connected && c_write_done && !s_read_done) {
- if (!ossl_quic_tserver_read(tserver,
+ if (!ossl_quic_tserver_read(tserver, 0,
(unsigned char *)msg2 + s_total_read,
sizeof(msg2) - s_total_read, &l)) {
- if (!TEST_true(ossl_quic_tserver_has_read_ended(tserver)))
+ if (!TEST_true(ossl_quic_tserver_has_read_ended(tserver, 0)))
goto err;
if (!TEST_mem_eq(msg1, sizeof(msg1) - 1, msg2, s_total_read))
goto err;
s_begin_write = 1;
+ s_read_done = 1;
} else {
s_total_read += l;
if (!TEST_size_t_le(s_total_read, sizeof(msg1) - 1))
}
if (s_begin_write && s_total_written < sizeof(msg1) - 1) {
- if (!TEST_true(ossl_quic_tserver_write(tserver,
+ if (!TEST_true(ossl_quic_tserver_write(tserver, 0,
(unsigned char *)msg2 + s_total_written,
sizeof(msg1) - 1 - s_total_written, &l)))
goto err;
s_total_written += l;
if (s_total_written == sizeof(msg1) - 1) {
- ossl_quic_tserver_conclude(tserver);
+ ossl_quic_tserver_conclude(tserver, 0);
c_begin_read = 1;
}
}
size_t msglen = strlen(msg);
size_t numbytes = 0;
int ssock = 0, csock = 0;
+ uint64_t sid = UINT64_MAX;
if (idx == 1 && !qtest_supports_blocking())
return TEST_skip("Blocking tests not supported in this build");
goto end;
}
+ if (!TEST_true(ossl_quic_tserver_stream_new(qtserv, /*is_uni=*/0, &sid))
+ || !TEST_uint64_t_eq(sid, 1)) /* server-initiated, so first SID is 1 */
+ goto end;
+
for (j = 0; j < 2; j++) {
/* Check that sending and receiving app data is ok */
if (!TEST_true(SSL_write_ex(clientquic, msg, msglen, &numbytes)))
ossl_quic_tserver_tick(qtserv);
- if (!TEST_true(ossl_quic_tserver_read(qtserv, buf, sizeof(buf),
+ if (!TEST_true(ossl_quic_tserver_read(qtserv, sid, buf, sizeof(buf),
&numbytes)))
goto end;
} while (numbytes == 0);
goto end;
}
- if (!TEST_true(ossl_quic_tserver_write(qtserv, (unsigned char *)msg,
+ if (!TEST_true(ossl_quic_tserver_write(qtserv, sid, (unsigned char *)msg,
msglen, &numbytes)))
goto end;
ossl_quic_tserver_tick(qtserv);
goto err;
ossl_quic_tserver_tick(qtserv);
- if (!TEST_true(ossl_quic_tserver_read(qtserv, buf, sizeof(buf), &bytesread)))
+ if (!TEST_true(ossl_quic_tserver_read(qtserv, 0, buf, sizeof(buf), &bytesread)))
goto err;
/*
NULL)))
goto err;
- if (!TEST_true(ossl_quic_tserver_write(qtserv, (unsigned char *)msg, msglen,
+ if (!TEST_true(ossl_quic_tserver_write(qtserv, 0, (unsigned char *)msg, msglen,
&byteswritten)))
goto err;
* Send first 5 bytes of message. This will get corrupted and is treated as
* "lost"
*/
- if (!TEST_true(ossl_quic_tserver_write(qtserv, (unsigned char *)msg, 5,
+ if (!TEST_true(ossl_quic_tserver_write(qtserv, 0, (unsigned char *)msg, 5,
&byteswritten)))
goto err;
OSSL_sleep(100);
/* Send rest of message */
- if (!TEST_true(ossl_quic_tserver_write(qtserv, (unsigned char *)msg + 5,
+ if (!TEST_true(ossl_quic_tserver_write(qtserv, 0, (unsigned char *)msg + 5,
msglen - 5, &byteswritten)))
goto err;