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