Packages
hackney
3.0.0
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Retired package: Release invalid - Use 3.0.1 instead
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/lsquic/src/liblsquic/lsquic_chsk_stream.c
/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */
/*
* Stream/crypto handshake adapter for the client side.
*
* The client composes CHLO, writes it to the stream, and wait for the
* server response, which it processes.
*/
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>
#include "lsquic_int_types.h"
#include "lsquic.h"
#include "lsquic_str.h"
#include "lsquic_enc_sess.h"
#include "lsquic_chsk_stream.h"
#include "lsquic_ver_neg.h"
#include "lsquic_hash.h"
#include "lsquic_conn.h"
#include "lsquic_mm.h"
#include "lsquic_sizes.h"
#include "lsquic_full_conn.h"
#define LSQUIC_LOGGER_MODULE LSQLM_HSK_ADAPTER
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(c_hsk->lconn)
#include "lsquic_logger.h"
static lsquic_stream_ctx_t *
hsk_client_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
{
struct client_hsk_ctx *const c_hsk = stream_if_ctx;
LSQ_DEBUG("stream created");
lsquic_stream_wantwrite(stream, 1);
return (void *) c_hsk;
}
static void
hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
{
struct client_hsk_ctx *const c_hsk = (struct client_hsk_ctx *) sh;
ssize_t nread;
int s;
enum lsquic_hsk_status status;
if (!c_hsk->buf_in)
{
c_hsk->buf_in = lsquic_mm_get_16k(c_hsk->mm);
if (!c_hsk->buf_in)
{
LSQ_WARN("could not get buffer: %s", strerror(errno));
lsquic_stream_wantread(stream, 0);
lsquic_conn_close(c_hsk->lconn);
return;
}
c_hsk->buf_sz = 16 * 1024;
c_hsk->buf_off = 0;
}
nread = lsquic_stream_read(stream, c_hsk->buf_in + c_hsk->buf_off,
c_hsk->buf_sz - c_hsk->buf_off);
if (nread <= 0)
{
if (nread < 0)
LSQ_INFO("Could not read from handshake stream: %s",
strerror(errno));
else
LSQ_INFO("Handshake stream closed (odd)");
lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
c_hsk->buf_in = NULL;
lsquic_stream_wantread(stream, 0);
lsquic_conn_close(c_hsk->lconn);
return;
}
c_hsk->buf_off += nread;
s = c_hsk->lconn->cn_esf.g->esf_handle_chlo_reply(c_hsk->lconn->cn_enc_session,
c_hsk->buf_in, c_hsk->buf_off);
LSQ_DEBUG("lsquic_enc_session_handle_chlo_reply returned %d", s);
switch (s)
{
case DATA_NOT_ENOUGH:
if (c_hsk->buf_off < c_hsk->buf_sz)
LSQ_INFO("not enough server response has arrived, continue "
"buffering");
else
{
LSQ_INFO("read in %u bytes of server response, and it is still "
"not enough: giving up", c_hsk->buf_off);
lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
c_hsk->buf_in = NULL;
lsquic_stream_wantread(stream, 0);
c_hsk->lconn->cn_if->ci_hsk_done(c_hsk->lconn, LSQ_HSK_FAIL);
lsquic_conn_close(c_hsk->lconn);
}
break;
case DATA_NO_ERROR:
lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
c_hsk->buf_in = NULL;
lsquic_stream_wantread(stream, 0);
if (c_hsk->lconn->cn_esf.g->esf_is_hsk_done(c_hsk->lconn->cn_enc_session))
{
LSQ_DEBUG("handshake is successful, inform connection");
status = (c_hsk->lconn->cn_esf_c->esf_did_sess_resume_succeed(
c_hsk->lconn->cn_enc_session)) ? LSQ_HSK_RESUMED_OK : LSQ_HSK_OK;
c_hsk->lconn->cn_if->ci_hsk_done(c_hsk->lconn, status);
}
else
{
LSQ_DEBUG("handshake not yet complete, will generate another "
"message");
lsquic_stream_wantwrite(stream, 1);
}
break;
case HS_SREJ:
LSQ_DEBUG("got HS_SREJ");
c_hsk->buf_off = 0;
lsquic_stream_wantread(stream, 0);
if (0 == lsquic_gquic_full_conn_srej(c_hsk->lconn))
lsquic_stream_wantwrite(stream, 1);
break;
default:
LSQ_WARN("lsquic_enc_session_handle_chlo_reply returned unknown value %d", s);
/* fallthru */
case DATA_FORMAT_ERROR:
LSQ_INFO("lsquic_enc_session_handle_chlo_reply returned an error");
lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
c_hsk->buf_in = NULL;
lsquic_stream_wantread(stream, 0);
c_hsk->lconn->cn_if->ci_hsk_done(c_hsk->lconn, LSQ_HSK_FAIL);
lsquic_conn_close(c_hsk->lconn);
break;
}
}
/* In this function, we assume that we can write the whole message in one
* shot. Otherwise, this is an error.
*/
static void
hsk_client_on_write (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
{
struct client_hsk_ctx *const c_hsk = (struct client_hsk_ctx *) sh;
unsigned char *buf;
size_t len;
ssize_t nw;
lsquic_stream_wantwrite(stream, 0);
buf = lsquic_mm_get_4k(c_hsk->mm);
if (!buf)
{
LSQ_WARN("cannot allocate buffer: %s", strerror(errno));
lsquic_conn_close(c_hsk->lconn);
return;
}
len = 4 * 1024;
if (0 != c_hsk->lconn->cn_esf.g->esf_gen_chlo(c_hsk->lconn->cn_enc_session,
c_hsk->ver_neg->vn_ver, buf, &len))
{
LSQ_WARN("cannot create CHLO message");
lsquic_mm_put_4k(c_hsk->mm, buf);
lsquic_conn_close(c_hsk->lconn);
return;
}
nw = lsquic_stream_write(stream, buf, len);
lsquic_mm_put_4k(c_hsk->mm, buf);
if (nw < 0)
LSQ_INFO("error writing to stream: %s", strerror(errno));
else if ((size_t) nw == len)
{
LSQ_INFO("wrote %zd bytes of CHLO to stream", nw);
lsquic_stream_flush(stream);
lsquic_stream_wantread(stream, 1);
}
else
LSQ_INFO("could only write %zd bytes to stream instead of %zd",
nw, len);
}
static void
hsk_client_on_close (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
{
struct client_hsk_ctx *const c_hsk = (struct client_hsk_ctx *) sh;
if (c_hsk->buf_in)
lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
LSQ_DEBUG("stream closed");
}
const struct lsquic_stream_if lsquic_client_hsk_stream_if =
{
.on_new_stream = hsk_client_on_new_stream,
.on_read = hsk_client_on_read,
.on_write = hsk_client_on_write,
.on_close = hsk_client_on_close,
};