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