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