lsquic_chsk_stream.c revision 5392f7a3
1/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * Stream/crypto handshake adapter for the client side.
4 *
5 * The client composes CHLO, writes it to the stream, and wait for the
6 * server response, which it processes.
7 */
8
9#include <assert.h>
10#include <errno.h>
11#include <stdarg.h>
12#include <stdlib.h>
13#include <string.h>
14#include <sys/queue.h>
15
16#include "lsquic_int_types.h"
17#include "lsquic.h"
18
19#include "lsquic_str.h"
20#include "lsquic_enc_sess.h"
21#include "lsquic_chsk_stream.h"
22#include "lsquic_ver_neg.h"
23#include "lsquic_hash.h"
24#include "lsquic_conn.h"
25#include "lsquic_mm.h"
26#include "lsquic_sizes.h"
27#include "lsquic_full_conn.h"
28
29#define LSQUIC_LOGGER_MODULE LSQLM_HSK_ADAPTER
30#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(c_hsk->lconn)
31#include "lsquic_logger.h"
32
33
34static lsquic_stream_ctx_t *
35hsk_client_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
36{
37    struct client_hsk_ctx *const c_hsk = stream_if_ctx;
38
39    LSQ_DEBUG("stream created");
40
41#if LSQUIC_ENABLE_HANDSHAKE_DISABLE
42    if (getenv("LSQUIC_DISABLE_HANDSHAKE"))
43    {
44        LSQ_WARN("Handshake disabled: faking it");
45        c_hsk->lconn->cn_flags |= LSCONN_NO_CRYPTO;
46        c_hsk->lconn->cn_if->ci_handshake_ok(c_hsk->lconn);
47        return (void *) c_hsk;
48    }
49#endif
50
51    lsquic_stream_wantwrite(stream, 1);
52
53    return (void *) c_hsk;
54}
55
56
57static void
58hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
59{
60    struct client_hsk_ctx *const c_hsk = (struct client_hsk_ctx *) sh;
61    ssize_t nread;
62    int s;
63    enum lsquic_hsk_status status;
64
65    if (!c_hsk->buf_in)
66    {
67        c_hsk->buf_in  = lsquic_mm_get_16k(c_hsk->mm);
68        if (!c_hsk->buf_in)
69        {
70            LSQ_WARN("could not get buffer: %s", strerror(errno));
71            lsquic_stream_wantread(stream, 0);
72            lsquic_conn_close(c_hsk->lconn);
73            return;
74        }
75        c_hsk->buf_sz  = 16 * 1024;
76        c_hsk->buf_off = 0;
77    }
78
79    nread = lsquic_stream_read(stream, c_hsk->buf_in + c_hsk->buf_off,
80                                            c_hsk->buf_sz - c_hsk->buf_off);
81    if (nread <= 0)
82    {
83        if (nread < 0)
84            LSQ_INFO("Could not read from handshake stream: %s",
85                                                            strerror(errno));
86        else
87            LSQ_INFO("Handshake stream closed (odd)");
88        lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
89        c_hsk->buf_in = NULL;
90        lsquic_stream_wantread(stream, 0);
91        lsquic_conn_close(c_hsk->lconn);
92        return;
93    }
94    c_hsk->buf_off += nread;
95
96    s = c_hsk->lconn->cn_esf.g->esf_handle_chlo_reply(c_hsk->lconn->cn_enc_session,
97                                        c_hsk->buf_in, c_hsk->buf_off);
98    LSQ_DEBUG("lsquic_enc_session_handle_chlo_reply returned %d", s);
99    switch (s)
100    {
101    case DATA_NOT_ENOUGH:
102        if (c_hsk->buf_off < c_hsk->buf_sz)
103            LSQ_INFO("not enough server response has arrived, continue "
104                                                                "buffering");
105        else
106        {
107            LSQ_INFO("read in %u bytes of server response, and it is still "
108                        "not enough: giving up", c_hsk->buf_off);
109            lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
110            c_hsk->buf_in = NULL;
111            lsquic_stream_wantread(stream, 0);
112            c_hsk->lconn->cn_if->ci_hsk_done(c_hsk->lconn, LSQ_HSK_FAIL);
113            lsquic_conn_close(c_hsk->lconn);
114        }
115        break;
116    case DATA_NO_ERROR:
117        lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
118        c_hsk->buf_in = NULL;
119        lsquic_stream_wantread(stream, 0);
120        if (c_hsk->lconn->cn_esf.g->esf_is_hsk_done(c_hsk->lconn->cn_enc_session))
121        {
122            LSQ_DEBUG("handshake is successful, inform connection");
123            status = (c_hsk->lconn->cn_esf_c->esf_did_zero_rtt_succeed(
124                c_hsk->lconn->cn_enc_session)) ? LSQ_HSK_0RTT_OK : LSQ_HSK_OK;
125            c_hsk->lconn->cn_if->ci_hsk_done(c_hsk->lconn, status);
126        }
127        else
128        {
129            LSQ_DEBUG("handshake not yet complete, will generate another "
130                                                                    "message");
131            lsquic_stream_wantwrite(stream, 1);
132        }
133        break;
134    case HS_SREJ:
135        LSQ_DEBUG("got HS_SREJ");
136        c_hsk->buf_off = 0;
137        lsquic_stream_wantread(stream, 0);
138        if (0 == lsquic_gquic_full_conn_srej(c_hsk->lconn))
139            lsquic_stream_wantwrite(stream, 1);
140        break;
141    default:
142        LSQ_WARN("lsquic_enc_session_handle_chlo_reply returned unknown value %d", s);
143        /* fallthru */
144    case DATA_FORMAT_ERROR:
145        LSQ_INFO("lsquic_enc_session_handle_chlo_reply returned an error");
146        c_hsk->buf_in = NULL;
147        lsquic_stream_wantread(stream, 0);
148        c_hsk->lconn->cn_if->ci_hsk_done(c_hsk->lconn, LSQ_HSK_FAIL);
149        lsquic_conn_close(c_hsk->lconn);
150        break;
151    }
152}
153
154
155/* In this function, we assume that we can write the whole message in one
156 * shot.  Otherwise, this is an error.
157 */
158static void
159hsk_client_on_write (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
160{
161    struct client_hsk_ctx *const c_hsk = (struct client_hsk_ctx *) sh;
162    unsigned char *buf;
163    size_t len;
164    ssize_t nw;
165
166    lsquic_stream_wantwrite(stream, 0);
167
168    buf = lsquic_mm_get_4k(c_hsk->mm);
169    if (!buf)
170    {
171        LSQ_WARN("cannot allocate buffer: %s", strerror(errno));
172        lsquic_conn_close(c_hsk->lconn);
173        return;
174    }
175    len = 4 * 1024;
176
177    if (0 != c_hsk->lconn->cn_esf.g->esf_gen_chlo(c_hsk->lconn->cn_enc_session,
178                                            c_hsk->ver_neg->vn_ver, buf, &len))
179    {
180        LSQ_WARN("cannot create CHLO message");
181        lsquic_mm_put_4k(c_hsk->mm, buf);
182        lsquic_conn_close(c_hsk->lconn);
183        return;
184    }
185
186    nw = lsquic_stream_write(stream, buf, len);
187    lsquic_mm_put_4k(c_hsk->mm, buf);
188
189    if (nw < 0)
190        LSQ_INFO("error writing to stream: %s", strerror(errno));
191    else if ((size_t) nw == len)
192    {
193        LSQ_INFO("wrote %zd bytes of CHLO to stream", nw);
194        lsquic_stream_flush(stream);
195        lsquic_stream_wantread(stream, 1);
196    }
197    else
198        LSQ_INFO("could only write %zd bytes to stream instead of %zd",
199                                                                    nw, len);
200}
201
202
203static void
204hsk_client_on_close (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
205{
206    struct client_hsk_ctx *const c_hsk = (struct client_hsk_ctx *) sh;
207    if (c_hsk->buf_in)
208        lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
209    LSQ_DEBUG("stream closed");
210}
211
212
213const struct lsquic_stream_if lsquic_client_hsk_stream_if =
214{
215    .on_new_stream = hsk_client_on_new_stream,
216    .on_read       = hsk_client_on_read,
217    .on_write      = hsk_client_on_write,
218    .on_close      = hsk_client_on_close,
219};
220