1*0957b409SSimon J. Gerraty /* 2*0957b409SSimon J. Gerraty * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> 3*0957b409SSimon J. Gerraty * 4*0957b409SSimon J. Gerraty * Permission is hereby granted, free of charge, to any person obtaining 5*0957b409SSimon J. Gerraty * a copy of this software and associated documentation files (the 6*0957b409SSimon J. Gerraty * "Software"), to deal in the Software without restriction, including 7*0957b409SSimon J. Gerraty * without limitation the rights to use, copy, modify, merge, publish, 8*0957b409SSimon J. Gerraty * distribute, sublicense, and/or sell copies of the Software, and to 9*0957b409SSimon J. Gerraty * permit persons to whom the Software is furnished to do so, subject to 10*0957b409SSimon J. Gerraty * the following conditions: 11*0957b409SSimon J. Gerraty * 12*0957b409SSimon J. Gerraty * The above copyright notice and this permission notice shall be 13*0957b409SSimon J. Gerraty * included in all copies or substantial portions of the Software. 14*0957b409SSimon J. Gerraty * 15*0957b409SSimon J. Gerraty * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16*0957b409SSimon J. Gerraty * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17*0957b409SSimon J. Gerraty * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18*0957b409SSimon J. Gerraty * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19*0957b409SSimon J. Gerraty * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20*0957b409SSimon J. Gerraty * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21*0957b409SSimon J. Gerraty * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22*0957b409SSimon J. Gerraty * SOFTWARE. 23*0957b409SSimon J. Gerraty */ 24*0957b409SSimon J. Gerraty 25*0957b409SSimon J. Gerraty #include <stdio.h> 26*0957b409SSimon J. Gerraty #include <stdlib.h> 27*0957b409SSimon J. Gerraty #include <string.h> 28*0957b409SSimon J. Gerraty #include <stdint.h> 29*0957b409SSimon J. Gerraty #include <errno.h> 30*0957b409SSimon J. Gerraty 31*0957b409SSimon J. Gerraty #ifdef _WIN32 32*0957b409SSimon J. Gerraty #include <winsock2.h> 33*0957b409SSimon J. Gerraty #include <ws2tcpip.h> 34*0957b409SSimon J. Gerraty #else 35*0957b409SSimon J. Gerraty #include <sys/types.h> 36*0957b409SSimon J. Gerraty #include <sys/socket.h> 37*0957b409SSimon J. Gerraty #include <netdb.h> 38*0957b409SSimon J. Gerraty #include <netinet/in.h> 39*0957b409SSimon J. Gerraty #include <arpa/inet.h> 40*0957b409SSimon J. Gerraty #include <unistd.h> 41*0957b409SSimon J. Gerraty #include <fcntl.h> 42*0957b409SSimon J. Gerraty #include <poll.h> 43*0957b409SSimon J. Gerraty 44*0957b409SSimon J. Gerraty #define SOCKET int 45*0957b409SSimon J. Gerraty #define INVALID_SOCKET (-1) 46*0957b409SSimon J. Gerraty #endif 47*0957b409SSimon J. Gerraty 48*0957b409SSimon J. Gerraty #include "brssl.h" 49*0957b409SSimon J. Gerraty 50*0957b409SSimon J. Gerraty static void 51*0957b409SSimon J. Gerraty dump_blob(const char *name, const void *data, size_t len) 52*0957b409SSimon J. Gerraty { 53*0957b409SSimon J. Gerraty const unsigned char *buf; 54*0957b409SSimon J. Gerraty size_t u; 55*0957b409SSimon J. Gerraty 56*0957b409SSimon J. Gerraty buf = data; 57*0957b409SSimon J. Gerraty fprintf(stderr, "%s (len = %lu)", name, (unsigned long)len); 58*0957b409SSimon J. Gerraty for (u = 0; u < len; u ++) { 59*0957b409SSimon J. Gerraty if ((u & 15) == 0) { 60*0957b409SSimon J. Gerraty fprintf(stderr, "\n%08lX ", (unsigned long)u); 61*0957b409SSimon J. Gerraty } else if ((u & 7) == 0) { 62*0957b409SSimon J. Gerraty fprintf(stderr, " "); 63*0957b409SSimon J. Gerraty } 64*0957b409SSimon J. Gerraty fprintf(stderr, " %02x", buf[u]); 65*0957b409SSimon J. Gerraty } 66*0957b409SSimon J. Gerraty fprintf(stderr, "\n"); 67*0957b409SSimon J. Gerraty } 68*0957b409SSimon J. Gerraty 69*0957b409SSimon J. Gerraty /* 70*0957b409SSimon J. Gerraty * Inspect the provided data in case it is a "command" to trigger a 71*0957b409SSimon J. Gerraty * special behaviour. If the command is recognised, then it is executed 72*0957b409SSimon J. Gerraty * and this function returns 1. Otherwise, this function returns 0. 73*0957b409SSimon J. Gerraty */ 74*0957b409SSimon J. Gerraty static int 75*0957b409SSimon J. Gerraty run_command(br_ssl_engine_context *cc, unsigned char *buf, size_t len) 76*0957b409SSimon J. Gerraty { 77*0957b409SSimon J. Gerraty /* 78*0957b409SSimon J. Gerraty * A single static slot for saving session parameters. 79*0957b409SSimon J. Gerraty */ 80*0957b409SSimon J. Gerraty static br_ssl_session_parameters slot; 81*0957b409SSimon J. Gerraty static int slot_used = 0; 82*0957b409SSimon J. Gerraty 83*0957b409SSimon J. Gerraty size_t u; 84*0957b409SSimon J. Gerraty 85*0957b409SSimon J. Gerraty if (len < 2 || len > 3) { 86*0957b409SSimon J. Gerraty return 0; 87*0957b409SSimon J. Gerraty } 88*0957b409SSimon J. Gerraty if (len == 3 && (buf[1] != '\r' || buf[2] != '\n')) { 89*0957b409SSimon J. Gerraty return 0; 90*0957b409SSimon J. Gerraty } 91*0957b409SSimon J. Gerraty if (len == 2 && buf[1] != '\n') { 92*0957b409SSimon J. Gerraty return 0; 93*0957b409SSimon J. Gerraty } 94*0957b409SSimon J. Gerraty switch (buf[0]) { 95*0957b409SSimon J. Gerraty case 'Q': 96*0957b409SSimon J. Gerraty fprintf(stderr, "closing...\n"); 97*0957b409SSimon J. Gerraty br_ssl_engine_close(cc); 98*0957b409SSimon J. Gerraty return 1; 99*0957b409SSimon J. Gerraty case 'R': 100*0957b409SSimon J. Gerraty if (br_ssl_engine_renegotiate(cc)) { 101*0957b409SSimon J. Gerraty fprintf(stderr, "renegotiating...\n"); 102*0957b409SSimon J. Gerraty } else { 103*0957b409SSimon J. Gerraty fprintf(stderr, "not renegotiating.\n"); 104*0957b409SSimon J. Gerraty } 105*0957b409SSimon J. Gerraty return 1; 106*0957b409SSimon J. Gerraty case 'F': 107*0957b409SSimon J. Gerraty /* 108*0957b409SSimon J. Gerraty * Session forget is nominally client-only. But the 109*0957b409SSimon J. Gerraty * session parameters are in the engine structure, which 110*0957b409SSimon J. Gerraty * is the first field of the client context, so the cast 111*0957b409SSimon J. Gerraty * still works properly. On the server, this forgetting 112*0957b409SSimon J. Gerraty * has no effect. 113*0957b409SSimon J. Gerraty */ 114*0957b409SSimon J. Gerraty fprintf(stderr, "forgetting session...\n"); 115*0957b409SSimon J. Gerraty br_ssl_client_forget_session((br_ssl_client_context *)cc); 116*0957b409SSimon J. Gerraty return 1; 117*0957b409SSimon J. Gerraty case 'S': 118*0957b409SSimon J. Gerraty fprintf(stderr, "saving session parameters...\n"); 119*0957b409SSimon J. Gerraty br_ssl_engine_get_session_parameters(cc, &slot); 120*0957b409SSimon J. Gerraty fprintf(stderr, " id = "); 121*0957b409SSimon J. Gerraty for (u = 0; u < slot.session_id_len; u ++) { 122*0957b409SSimon J. Gerraty fprintf(stderr, "%02X", slot.session_id[u]); 123*0957b409SSimon J. Gerraty } 124*0957b409SSimon J. Gerraty fprintf(stderr, "\n"); 125*0957b409SSimon J. Gerraty slot_used = 1; 126*0957b409SSimon J. Gerraty return 1; 127*0957b409SSimon J. Gerraty case 'P': 128*0957b409SSimon J. Gerraty if (slot_used) { 129*0957b409SSimon J. Gerraty fprintf(stderr, "restoring session parameters...\n"); 130*0957b409SSimon J. Gerraty fprintf(stderr, " id = "); 131*0957b409SSimon J. Gerraty for (u = 0; u < slot.session_id_len; u ++) { 132*0957b409SSimon J. Gerraty fprintf(stderr, "%02X", slot.session_id[u]); 133*0957b409SSimon J. Gerraty } 134*0957b409SSimon J. Gerraty fprintf(stderr, "\n"); 135*0957b409SSimon J. Gerraty br_ssl_engine_set_session_parameters(cc, &slot); 136*0957b409SSimon J. Gerraty return 1; 137*0957b409SSimon J. Gerraty } 138*0957b409SSimon J. Gerraty return 0; 139*0957b409SSimon J. Gerraty default: 140*0957b409SSimon J. Gerraty return 0; 141*0957b409SSimon J. Gerraty } 142*0957b409SSimon J. Gerraty } 143*0957b409SSimon J. Gerraty 144*0957b409SSimon J. Gerraty #ifdef _WIN32 145*0957b409SSimon J. Gerraty 146*0957b409SSimon J. Gerraty typedef struct { 147*0957b409SSimon J. Gerraty unsigned char buf[1024]; 148*0957b409SSimon J. Gerraty size_t ptr, len; 149*0957b409SSimon J. Gerraty } in_buffer; 150*0957b409SSimon J. Gerraty 151*0957b409SSimon J. Gerraty static int 152*0957b409SSimon J. Gerraty in_return_bytes(in_buffer *bb, unsigned char *buf, size_t len) 153*0957b409SSimon J. Gerraty { 154*0957b409SSimon J. Gerraty if (bb->ptr < bb->len) { 155*0957b409SSimon J. Gerraty size_t clen; 156*0957b409SSimon J. Gerraty 157*0957b409SSimon J. Gerraty if (buf == NULL) { 158*0957b409SSimon J. Gerraty return 1; 159*0957b409SSimon J. Gerraty } 160*0957b409SSimon J. Gerraty clen = bb->len - bb->ptr; 161*0957b409SSimon J. Gerraty if (clen > len) { 162*0957b409SSimon J. Gerraty clen = len; 163*0957b409SSimon J. Gerraty } 164*0957b409SSimon J. Gerraty memcpy(buf, bb->buf + bb->ptr, clen); 165*0957b409SSimon J. Gerraty bb->ptr += clen; 166*0957b409SSimon J. Gerraty if (bb->ptr == bb->len) { 167*0957b409SSimon J. Gerraty bb->ptr = bb->len = 0; 168*0957b409SSimon J. Gerraty } 169*0957b409SSimon J. Gerraty return (int)clen; 170*0957b409SSimon J. Gerraty } 171*0957b409SSimon J. Gerraty return 0; 172*0957b409SSimon J. Gerraty } 173*0957b409SSimon J. Gerraty 174*0957b409SSimon J. Gerraty /* 175*0957b409SSimon J. Gerraty * A buffered version of in_read(), using a buffer to return only 176*0957b409SSimon J. Gerraty * full lines when feasible. 177*0957b409SSimon J. Gerraty */ 178*0957b409SSimon J. Gerraty static int 179*0957b409SSimon J. Gerraty in_read_buffered(HANDLE h_in, in_buffer *bb, unsigned char *buf, size_t len) 180*0957b409SSimon J. Gerraty { 181*0957b409SSimon J. Gerraty int n; 182*0957b409SSimon J. Gerraty 183*0957b409SSimon J. Gerraty if (len == 0) { 184*0957b409SSimon J. Gerraty return 0; 185*0957b409SSimon J. Gerraty } 186*0957b409SSimon J. Gerraty n = in_return_bytes(bb, buf, len); 187*0957b409SSimon J. Gerraty if (n != 0) { 188*0957b409SSimon J. Gerraty return n; 189*0957b409SSimon J. Gerraty } 190*0957b409SSimon J. Gerraty for (;;) { 191*0957b409SSimon J. Gerraty INPUT_RECORD inrec; 192*0957b409SSimon J. Gerraty DWORD v; 193*0957b409SSimon J. Gerraty 194*0957b409SSimon J. Gerraty if (!PeekConsoleInput(h_in, &inrec, 1, &v)) { 195*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: PeekConsoleInput()" 196*0957b409SSimon J. Gerraty " failed with 0x%08lX\n", 197*0957b409SSimon J. Gerraty (unsigned long)GetLastError()); 198*0957b409SSimon J. Gerraty return -1; 199*0957b409SSimon J. Gerraty } 200*0957b409SSimon J. Gerraty if (v == 0) { 201*0957b409SSimon J. Gerraty return 0; 202*0957b409SSimon J. Gerraty } 203*0957b409SSimon J. Gerraty if (!ReadConsoleInput(h_in, &inrec, 1, &v)) { 204*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: ReadConsoleInput()" 205*0957b409SSimon J. Gerraty " failed with 0x%08lX\n", 206*0957b409SSimon J. Gerraty (unsigned long)GetLastError()); 207*0957b409SSimon J. Gerraty return -1; 208*0957b409SSimon J. Gerraty } 209*0957b409SSimon J. Gerraty if (v == 0) { 210*0957b409SSimon J. Gerraty return 0; 211*0957b409SSimon J. Gerraty } 212*0957b409SSimon J. Gerraty if (inrec.EventType == KEY_EVENT 213*0957b409SSimon J. Gerraty && inrec.Event.KeyEvent.bKeyDown) 214*0957b409SSimon J. Gerraty { 215*0957b409SSimon J. Gerraty int c; 216*0957b409SSimon J. Gerraty 217*0957b409SSimon J. Gerraty c = inrec.Event.KeyEvent.uChar.AsciiChar; 218*0957b409SSimon J. Gerraty if (c == '\n' || c == '\r' || c == '\t' 219*0957b409SSimon J. Gerraty || (c >= 32 && c != 127)) 220*0957b409SSimon J. Gerraty { 221*0957b409SSimon J. Gerraty if (c == '\r') { 222*0957b409SSimon J. Gerraty c = '\n'; 223*0957b409SSimon J. Gerraty } 224*0957b409SSimon J. Gerraty bb->buf[bb->ptr ++] = (unsigned char)c; 225*0957b409SSimon J. Gerraty printf("%c", c); 226*0957b409SSimon J. Gerraty fflush(stdout); 227*0957b409SSimon J. Gerraty bb->len = bb->ptr; 228*0957b409SSimon J. Gerraty if (bb->len == sizeof bb->buf || c == '\n') { 229*0957b409SSimon J. Gerraty bb->ptr = 0; 230*0957b409SSimon J. Gerraty return in_return_bytes(bb, buf, len); 231*0957b409SSimon J. Gerraty } 232*0957b409SSimon J. Gerraty } 233*0957b409SSimon J. Gerraty } 234*0957b409SSimon J. Gerraty } 235*0957b409SSimon J. Gerraty } 236*0957b409SSimon J. Gerraty 237*0957b409SSimon J. Gerraty static int 238*0957b409SSimon J. Gerraty in_avail_buffered(HANDLE h_in, in_buffer *bb) 239*0957b409SSimon J. Gerraty { 240*0957b409SSimon J. Gerraty return in_read_buffered(h_in, bb, NULL, 1); 241*0957b409SSimon J. Gerraty } 242*0957b409SSimon J. Gerraty 243*0957b409SSimon J. Gerraty #endif 244*0957b409SSimon J. Gerraty 245*0957b409SSimon J. Gerraty /* see brssl.h */ 246*0957b409SSimon J. Gerraty int 247*0957b409SSimon J. Gerraty run_ssl_engine(br_ssl_engine_context *cc, unsigned long fd, unsigned flags) 248*0957b409SSimon J. Gerraty { 249*0957b409SSimon J. Gerraty int hsdetails; 250*0957b409SSimon J. Gerraty int retcode; 251*0957b409SSimon J. Gerraty int verbose; 252*0957b409SSimon J. Gerraty int trace; 253*0957b409SSimon J. Gerraty #ifdef _WIN32 254*0957b409SSimon J. Gerraty WSAEVENT fd_event; 255*0957b409SSimon J. Gerraty int can_send, can_recv; 256*0957b409SSimon J. Gerraty HANDLE h_in, h_out; 257*0957b409SSimon J. Gerraty in_buffer bb; 258*0957b409SSimon J. Gerraty #endif 259*0957b409SSimon J. Gerraty 260*0957b409SSimon J. Gerraty hsdetails = 0; 261*0957b409SSimon J. Gerraty retcode = 0; 262*0957b409SSimon J. Gerraty verbose = (flags & RUN_ENGINE_VERBOSE) != 0; 263*0957b409SSimon J. Gerraty trace = (flags & RUN_ENGINE_TRACE) != 0; 264*0957b409SSimon J. Gerraty 265*0957b409SSimon J. Gerraty /* 266*0957b409SSimon J. Gerraty * Print algorithm details. 267*0957b409SSimon J. Gerraty */ 268*0957b409SSimon J. Gerraty if (verbose) { 269*0957b409SSimon J. Gerraty const char *rngname; 270*0957b409SSimon J. Gerraty 271*0957b409SSimon J. Gerraty fprintf(stderr, "Algorithms:\n"); 272*0957b409SSimon J. Gerraty br_prng_seeder_system(&rngname); 273*0957b409SSimon J. Gerraty fprintf(stderr, " RNG: %s\n", rngname); 274*0957b409SSimon J. Gerraty if (cc->iaes_cbcenc != 0) { 275*0957b409SSimon J. Gerraty fprintf(stderr, " AES/CBC (enc): %s\n", 276*0957b409SSimon J. Gerraty get_algo_name(cc->iaes_cbcenc, 0)); 277*0957b409SSimon J. Gerraty } 278*0957b409SSimon J. Gerraty if (cc->iaes_cbcdec != 0) { 279*0957b409SSimon J. Gerraty fprintf(stderr, " AES/CBC (dec): %s\n", 280*0957b409SSimon J. Gerraty get_algo_name(cc->iaes_cbcdec, 0)); 281*0957b409SSimon J. Gerraty } 282*0957b409SSimon J. Gerraty if (cc->iaes_ctr != 0) { 283*0957b409SSimon J. Gerraty fprintf(stderr, " AES/CTR: %s\n", 284*0957b409SSimon J. Gerraty get_algo_name(cc->iaes_cbcdec, 0)); 285*0957b409SSimon J. Gerraty } 286*0957b409SSimon J. Gerraty if (cc->iaes_ctrcbc != 0) { 287*0957b409SSimon J. Gerraty fprintf(stderr, " AES/CCM: %s\n", 288*0957b409SSimon J. Gerraty get_algo_name(cc->iaes_ctrcbc, 0)); 289*0957b409SSimon J. Gerraty } 290*0957b409SSimon J. Gerraty if (cc->ides_cbcenc != 0) { 291*0957b409SSimon J. Gerraty fprintf(stderr, " DES/CBC (enc): %s\n", 292*0957b409SSimon J. Gerraty get_algo_name(cc->ides_cbcenc, 0)); 293*0957b409SSimon J. Gerraty } 294*0957b409SSimon J. Gerraty if (cc->ides_cbcdec != 0) { 295*0957b409SSimon J. Gerraty fprintf(stderr, " DES/CBC (dec): %s\n", 296*0957b409SSimon J. Gerraty get_algo_name(cc->ides_cbcdec, 0)); 297*0957b409SSimon J. Gerraty } 298*0957b409SSimon J. Gerraty if (cc->ighash != 0) { 299*0957b409SSimon J. Gerraty fprintf(stderr, " GHASH (GCM): %s\n", 300*0957b409SSimon J. Gerraty get_algo_name(cc->ighash, 0)); 301*0957b409SSimon J. Gerraty } 302*0957b409SSimon J. Gerraty if (cc->ichacha != 0) { 303*0957b409SSimon J. Gerraty fprintf(stderr, " ChaCha20: %s\n", 304*0957b409SSimon J. Gerraty get_algo_name(cc->ichacha, 0)); 305*0957b409SSimon J. Gerraty } 306*0957b409SSimon J. Gerraty if (cc->ipoly != 0) { 307*0957b409SSimon J. Gerraty fprintf(stderr, " Poly1305: %s\n", 308*0957b409SSimon J. Gerraty get_algo_name(cc->ipoly, 0)); 309*0957b409SSimon J. Gerraty } 310*0957b409SSimon J. Gerraty if (cc->iec != 0) { 311*0957b409SSimon J. Gerraty fprintf(stderr, " EC: %s\n", 312*0957b409SSimon J. Gerraty get_algo_name(cc->iec, 0)); 313*0957b409SSimon J. Gerraty } 314*0957b409SSimon J. Gerraty if (cc->iecdsa != 0) { 315*0957b409SSimon J. Gerraty fprintf(stderr, " ECDSA: %s\n", 316*0957b409SSimon J. Gerraty get_algo_name(cc->iecdsa, 0)); 317*0957b409SSimon J. Gerraty } 318*0957b409SSimon J. Gerraty if (cc->irsavrfy != 0) { 319*0957b409SSimon J. Gerraty fprintf(stderr, " RSA (vrfy): %s\n", 320*0957b409SSimon J. Gerraty get_algo_name(cc->irsavrfy, 0)); 321*0957b409SSimon J. Gerraty } 322*0957b409SSimon J. Gerraty } 323*0957b409SSimon J. Gerraty 324*0957b409SSimon J. Gerraty #ifdef _WIN32 325*0957b409SSimon J. Gerraty fd_event = WSA_INVALID_EVENT; 326*0957b409SSimon J. Gerraty can_send = 0; 327*0957b409SSimon J. Gerraty can_recv = 0; 328*0957b409SSimon J. Gerraty bb.ptr = bb.len = 0; 329*0957b409SSimon J. Gerraty #endif 330*0957b409SSimon J. Gerraty 331*0957b409SSimon J. Gerraty /* 332*0957b409SSimon J. Gerraty * On Unix systems, we need to follow three descriptors: 333*0957b409SSimon J. Gerraty * standard input (0), standard output (1), and the socket 334*0957b409SSimon J. Gerraty * itself (for both read and write). This is done with a poll() 335*0957b409SSimon J. Gerraty * call. 336*0957b409SSimon J. Gerraty * 337*0957b409SSimon J. Gerraty * On Windows systems, we use WSAEventSelect() to associate 338*0957b409SSimon J. Gerraty * an event handle with the network activity, and we use 339*0957b409SSimon J. Gerraty * WaitForMultipleObjectsEx() on that handle and the standard 340*0957b409SSimon J. Gerraty * input handle, when appropriate. Standard output is assumed 341*0957b409SSimon J. Gerraty * to be always writeable, and standard input to be the console; 342*0957b409SSimon J. Gerraty * this does not work well (or at all) with redirections (to 343*0957b409SSimon J. Gerraty * pipes or files) but it should be enough for a debug tool 344*0957b409SSimon J. Gerraty * (TODO: make something that handles redirections as well). 345*0957b409SSimon J. Gerraty */ 346*0957b409SSimon J. Gerraty 347*0957b409SSimon J. Gerraty #ifdef _WIN32 348*0957b409SSimon J. Gerraty fd_event = WSACreateEvent(); 349*0957b409SSimon J. Gerraty if (fd_event == WSA_INVALID_EVENT) { 350*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: WSACreateEvent() failed with %d\n", 351*0957b409SSimon J. Gerraty WSAGetLastError()); 352*0957b409SSimon J. Gerraty retcode = -2; 353*0957b409SSimon J. Gerraty goto engine_exit; 354*0957b409SSimon J. Gerraty } 355*0957b409SSimon J. Gerraty WSAEventSelect(fd, fd_event, FD_READ | FD_WRITE | FD_CLOSE); 356*0957b409SSimon J. Gerraty h_in = GetStdHandle(STD_INPUT_HANDLE); 357*0957b409SSimon J. Gerraty h_out = GetStdHandle(STD_OUTPUT_HANDLE); 358*0957b409SSimon J. Gerraty SetConsoleMode(h_in, ENABLE_ECHO_INPUT 359*0957b409SSimon J. Gerraty | ENABLE_LINE_INPUT 360*0957b409SSimon J. Gerraty | ENABLE_PROCESSED_INPUT 361*0957b409SSimon J. Gerraty | ENABLE_PROCESSED_OUTPUT 362*0957b409SSimon J. Gerraty | ENABLE_WRAP_AT_EOL_OUTPUT); 363*0957b409SSimon J. Gerraty #else 364*0957b409SSimon J. Gerraty /* 365*0957b409SSimon J. Gerraty * Make sure that stdin and stdout are non-blocking. 366*0957b409SSimon J. Gerraty */ 367*0957b409SSimon J. Gerraty fcntl(0, F_SETFL, O_NONBLOCK); 368*0957b409SSimon J. Gerraty fcntl(1, F_SETFL, O_NONBLOCK); 369*0957b409SSimon J. Gerraty #endif 370*0957b409SSimon J. Gerraty 371*0957b409SSimon J. Gerraty /* 372*0957b409SSimon J. Gerraty * Perform the loop. 373*0957b409SSimon J. Gerraty */ 374*0957b409SSimon J. Gerraty for (;;) { 375*0957b409SSimon J. Gerraty unsigned st; 376*0957b409SSimon J. Gerraty int sendrec, recvrec, sendapp, recvapp; 377*0957b409SSimon J. Gerraty #ifdef _WIN32 378*0957b409SSimon J. Gerraty HANDLE pfd[2]; 379*0957b409SSimon J. Gerraty DWORD wt; 380*0957b409SSimon J. Gerraty #else 381*0957b409SSimon J. Gerraty struct pollfd pfd[3]; 382*0957b409SSimon J. Gerraty int n; 383*0957b409SSimon J. Gerraty #endif 384*0957b409SSimon J. Gerraty size_t u, k_fd, k_in, k_out; 385*0957b409SSimon J. Gerraty int sendrec_ok, recvrec_ok, sendapp_ok, recvapp_ok; 386*0957b409SSimon J. Gerraty 387*0957b409SSimon J. Gerraty /* 388*0957b409SSimon J. Gerraty * Get current engine state. 389*0957b409SSimon J. Gerraty */ 390*0957b409SSimon J. Gerraty st = br_ssl_engine_current_state(cc); 391*0957b409SSimon J. Gerraty if (st == BR_SSL_CLOSED) { 392*0957b409SSimon J. Gerraty int err; 393*0957b409SSimon J. Gerraty 394*0957b409SSimon J. Gerraty err = br_ssl_engine_last_error(cc); 395*0957b409SSimon J. Gerraty if (err == BR_ERR_OK) { 396*0957b409SSimon J. Gerraty if (verbose) { 397*0957b409SSimon J. Gerraty fprintf(stderr, 398*0957b409SSimon J. Gerraty "SSL closed normally\n"); 399*0957b409SSimon J. Gerraty } 400*0957b409SSimon J. Gerraty retcode = 0; 401*0957b409SSimon J. Gerraty goto engine_exit; 402*0957b409SSimon J. Gerraty } else { 403*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: SSL error %d", err); 404*0957b409SSimon J. Gerraty retcode = err; 405*0957b409SSimon J. Gerraty if (err >= BR_ERR_SEND_FATAL_ALERT) { 406*0957b409SSimon J. Gerraty err -= BR_ERR_SEND_FATAL_ALERT; 407*0957b409SSimon J. Gerraty fprintf(stderr, 408*0957b409SSimon J. Gerraty " (sent alert %d)\n", err); 409*0957b409SSimon J. Gerraty } else if (err >= BR_ERR_RECV_FATAL_ALERT) { 410*0957b409SSimon J. Gerraty err -= BR_ERR_RECV_FATAL_ALERT; 411*0957b409SSimon J. Gerraty fprintf(stderr, 412*0957b409SSimon J. Gerraty " (received alert %d)\n", err); 413*0957b409SSimon J. Gerraty } else { 414*0957b409SSimon J. Gerraty const char *ename; 415*0957b409SSimon J. Gerraty 416*0957b409SSimon J. Gerraty ename = find_error_name(err, NULL); 417*0957b409SSimon J. Gerraty if (ename == NULL) { 418*0957b409SSimon J. Gerraty ename = "unknown"; 419*0957b409SSimon J. Gerraty } 420*0957b409SSimon J. Gerraty fprintf(stderr, " (%s)\n", ename); 421*0957b409SSimon J. Gerraty } 422*0957b409SSimon J. Gerraty goto engine_exit; 423*0957b409SSimon J. Gerraty } 424*0957b409SSimon J. Gerraty } 425*0957b409SSimon J. Gerraty 426*0957b409SSimon J. Gerraty /* 427*0957b409SSimon J. Gerraty * Compute descriptors that must be polled, depending 428*0957b409SSimon J. Gerraty * on engine state. 429*0957b409SSimon J. Gerraty */ 430*0957b409SSimon J. Gerraty sendrec = ((st & BR_SSL_SENDREC) != 0); 431*0957b409SSimon J. Gerraty recvrec = ((st & BR_SSL_RECVREC) != 0); 432*0957b409SSimon J. Gerraty sendapp = ((st & BR_SSL_SENDAPP) != 0); 433*0957b409SSimon J. Gerraty recvapp = ((st & BR_SSL_RECVAPP) != 0); 434*0957b409SSimon J. Gerraty if (verbose && sendapp && !hsdetails) { 435*0957b409SSimon J. Gerraty char csn[80]; 436*0957b409SSimon J. Gerraty const char *pname; 437*0957b409SSimon J. Gerraty 438*0957b409SSimon J. Gerraty fprintf(stderr, "Handshake completed\n"); 439*0957b409SSimon J. Gerraty fprintf(stderr, " version: "); 440*0957b409SSimon J. Gerraty switch (cc->session.version) { 441*0957b409SSimon J. Gerraty case BR_SSL30: 442*0957b409SSimon J. Gerraty fprintf(stderr, "SSL 3.0"); 443*0957b409SSimon J. Gerraty break; 444*0957b409SSimon J. Gerraty case BR_TLS10: 445*0957b409SSimon J. Gerraty fprintf(stderr, "TLS 1.0"); 446*0957b409SSimon J. Gerraty break; 447*0957b409SSimon J. Gerraty case BR_TLS11: 448*0957b409SSimon J. Gerraty fprintf(stderr, "TLS 1.1"); 449*0957b409SSimon J. Gerraty break; 450*0957b409SSimon J. Gerraty case BR_TLS12: 451*0957b409SSimon J. Gerraty fprintf(stderr, "TLS 1.2"); 452*0957b409SSimon J. Gerraty break; 453*0957b409SSimon J. Gerraty default: 454*0957b409SSimon J. Gerraty fprintf(stderr, "unknown (0x%04X)", 455*0957b409SSimon J. Gerraty (unsigned)cc->session.version); 456*0957b409SSimon J. Gerraty break; 457*0957b409SSimon J. Gerraty } 458*0957b409SSimon J. Gerraty fprintf(stderr, "\n"); 459*0957b409SSimon J. Gerraty get_suite_name_ext( 460*0957b409SSimon J. Gerraty cc->session.cipher_suite, csn, sizeof csn); 461*0957b409SSimon J. Gerraty fprintf(stderr, " cipher suite: %s\n", csn); 462*0957b409SSimon J. Gerraty if (uses_ecdhe(cc->session.cipher_suite)) { 463*0957b409SSimon J. Gerraty get_curve_name_ext( 464*0957b409SSimon J. Gerraty br_ssl_engine_get_ecdhe_curve(cc), 465*0957b409SSimon J. Gerraty csn, sizeof csn); 466*0957b409SSimon J. Gerraty fprintf(stderr, 467*0957b409SSimon J. Gerraty " ECDHE curve: %s\n", csn); 468*0957b409SSimon J. Gerraty } 469*0957b409SSimon J. Gerraty fprintf(stderr, " secure renegotiation: %s\n", 470*0957b409SSimon J. Gerraty cc->reneg == 1 ? "no" : "yes"); 471*0957b409SSimon J. Gerraty pname = br_ssl_engine_get_selected_protocol(cc); 472*0957b409SSimon J. Gerraty if (pname != NULL) { 473*0957b409SSimon J. Gerraty fprintf(stderr, 474*0957b409SSimon J. Gerraty " protocol name (ALPN): %s\n", 475*0957b409SSimon J. Gerraty pname); 476*0957b409SSimon J. Gerraty } 477*0957b409SSimon J. Gerraty hsdetails = 1; 478*0957b409SSimon J. Gerraty } 479*0957b409SSimon J. Gerraty 480*0957b409SSimon J. Gerraty k_fd = (size_t)-1; 481*0957b409SSimon J. Gerraty k_in = (size_t)-1; 482*0957b409SSimon J. Gerraty k_out = (size_t)-1; 483*0957b409SSimon J. Gerraty 484*0957b409SSimon J. Gerraty u = 0; 485*0957b409SSimon J. Gerraty #ifdef _WIN32 486*0957b409SSimon J. Gerraty /* 487*0957b409SSimon J. Gerraty * If we recorded that we can send or receive data, and we 488*0957b409SSimon J. Gerraty * want to do exactly that, then we don't wait; we just do 489*0957b409SSimon J. Gerraty * it. 490*0957b409SSimon J. Gerraty */ 491*0957b409SSimon J. Gerraty recvapp_ok = 0; 492*0957b409SSimon J. Gerraty sendrec_ok = 0; 493*0957b409SSimon J. Gerraty recvrec_ok = 0; 494*0957b409SSimon J. Gerraty sendapp_ok = 0; 495*0957b409SSimon J. Gerraty 496*0957b409SSimon J. Gerraty if (sendrec && can_send) { 497*0957b409SSimon J. Gerraty sendrec_ok = 1; 498*0957b409SSimon J. Gerraty } else if (recvrec && can_recv) { 499*0957b409SSimon J. Gerraty recvrec_ok = 1; 500*0957b409SSimon J. Gerraty } else if (recvapp) { 501*0957b409SSimon J. Gerraty recvapp_ok = 1; 502*0957b409SSimon J. Gerraty } else if (sendapp && in_avail_buffered(h_in, &bb)) { 503*0957b409SSimon J. Gerraty sendapp_ok = 1; 504*0957b409SSimon J. Gerraty } else { 505*0957b409SSimon J. Gerraty /* 506*0957b409SSimon J. Gerraty * If we cannot do I/O right away, then we must 507*0957b409SSimon J. Gerraty * wait for some event, and try again. 508*0957b409SSimon J. Gerraty */ 509*0957b409SSimon J. Gerraty pfd[u] = (HANDLE)fd_event; 510*0957b409SSimon J. Gerraty k_fd = u; 511*0957b409SSimon J. Gerraty u ++; 512*0957b409SSimon J. Gerraty if (sendapp) { 513*0957b409SSimon J. Gerraty pfd[u] = h_in; 514*0957b409SSimon J. Gerraty k_in = u; 515*0957b409SSimon J. Gerraty u ++; 516*0957b409SSimon J. Gerraty } 517*0957b409SSimon J. Gerraty wt = WaitForMultipleObjectsEx(u, pfd, 518*0957b409SSimon J. Gerraty FALSE, INFINITE, FALSE); 519*0957b409SSimon J. Gerraty if (wt == WAIT_FAILED) { 520*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR:" 521*0957b409SSimon J. Gerraty " WaitForMultipleObjectsEx()" 522*0957b409SSimon J. Gerraty " failed with 0x%08lX", 523*0957b409SSimon J. Gerraty (unsigned long)GetLastError()); 524*0957b409SSimon J. Gerraty retcode = -2; 525*0957b409SSimon J. Gerraty goto engine_exit; 526*0957b409SSimon J. Gerraty } 527*0957b409SSimon J. Gerraty if (wt == k_fd) { 528*0957b409SSimon J. Gerraty WSANETWORKEVENTS e; 529*0957b409SSimon J. Gerraty 530*0957b409SSimon J. Gerraty if (WSAEnumNetworkEvents(fd, fd_event, &e)) { 531*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR:" 532*0957b409SSimon J. Gerraty " WSAEnumNetworkEvents()" 533*0957b409SSimon J. Gerraty " failed with %d\n", 534*0957b409SSimon J. Gerraty WSAGetLastError()); 535*0957b409SSimon J. Gerraty retcode = -2; 536*0957b409SSimon J. Gerraty goto engine_exit; 537*0957b409SSimon J. Gerraty } 538*0957b409SSimon J. Gerraty if (e.lNetworkEvents & (FD_WRITE | FD_CLOSE)) { 539*0957b409SSimon J. Gerraty can_send = 1; 540*0957b409SSimon J. Gerraty } 541*0957b409SSimon J. Gerraty if (e.lNetworkEvents & (FD_READ | FD_CLOSE)) { 542*0957b409SSimon J. Gerraty can_recv = 1; 543*0957b409SSimon J. Gerraty } 544*0957b409SSimon J. Gerraty } 545*0957b409SSimon J. Gerraty continue; 546*0957b409SSimon J. Gerraty } 547*0957b409SSimon J. Gerraty #else 548*0957b409SSimon J. Gerraty if (sendrec || recvrec) { 549*0957b409SSimon J. Gerraty pfd[u].fd = fd; 550*0957b409SSimon J. Gerraty pfd[u].revents = 0; 551*0957b409SSimon J. Gerraty pfd[u].events = 0; 552*0957b409SSimon J. Gerraty if (sendrec) { 553*0957b409SSimon J. Gerraty pfd[u].events |= POLLOUT; 554*0957b409SSimon J. Gerraty } 555*0957b409SSimon J. Gerraty if (recvrec) { 556*0957b409SSimon J. Gerraty pfd[u].events |= POLLIN; 557*0957b409SSimon J. Gerraty } 558*0957b409SSimon J. Gerraty k_fd = u; 559*0957b409SSimon J. Gerraty u ++; 560*0957b409SSimon J. Gerraty } 561*0957b409SSimon J. Gerraty if (sendapp) { 562*0957b409SSimon J. Gerraty pfd[u].fd = 0; 563*0957b409SSimon J. Gerraty pfd[u].revents = 0; 564*0957b409SSimon J. Gerraty pfd[u].events = POLLIN; 565*0957b409SSimon J. Gerraty k_in = u; 566*0957b409SSimon J. Gerraty u ++; 567*0957b409SSimon J. Gerraty } 568*0957b409SSimon J. Gerraty if (recvapp) { 569*0957b409SSimon J. Gerraty pfd[u].fd = 1; 570*0957b409SSimon J. Gerraty pfd[u].revents = 0; 571*0957b409SSimon J. Gerraty pfd[u].events = POLLOUT; 572*0957b409SSimon J. Gerraty k_out = u; 573*0957b409SSimon J. Gerraty u ++; 574*0957b409SSimon J. Gerraty } 575*0957b409SSimon J. Gerraty n = poll(pfd, u, -1); 576*0957b409SSimon J. Gerraty if (n < 0) { 577*0957b409SSimon J. Gerraty if (errno == EINTR) { 578*0957b409SSimon J. Gerraty continue; 579*0957b409SSimon J. Gerraty } 580*0957b409SSimon J. Gerraty perror("ERROR: poll()"); 581*0957b409SSimon J. Gerraty retcode = -2; 582*0957b409SSimon J. Gerraty goto engine_exit; 583*0957b409SSimon J. Gerraty } 584*0957b409SSimon J. Gerraty if (n == 0) { 585*0957b409SSimon J. Gerraty continue; 586*0957b409SSimon J. Gerraty } 587*0957b409SSimon J. Gerraty 588*0957b409SSimon J. Gerraty /* 589*0957b409SSimon J. Gerraty * We transform closures/errors into read+write accesses 590*0957b409SSimon J. Gerraty * so as to force the read() or write() call that will 591*0957b409SSimon J. Gerraty * detect the situation. 592*0957b409SSimon J. Gerraty */ 593*0957b409SSimon J. Gerraty while (u -- > 0) { 594*0957b409SSimon J. Gerraty if (pfd[u].revents & (POLLERR | POLLHUP)) { 595*0957b409SSimon J. Gerraty pfd[u].revents |= POLLIN | POLLOUT; 596*0957b409SSimon J. Gerraty } 597*0957b409SSimon J. Gerraty } 598*0957b409SSimon J. Gerraty 599*0957b409SSimon J. Gerraty recvapp_ok = recvapp && (pfd[k_out].revents & POLLOUT) != 0; 600*0957b409SSimon J. Gerraty sendrec_ok = sendrec && (pfd[k_fd].revents & POLLOUT) != 0; 601*0957b409SSimon J. Gerraty recvrec_ok = recvrec && (pfd[k_fd].revents & POLLIN) != 0; 602*0957b409SSimon J. Gerraty sendapp_ok = sendapp && (pfd[k_in].revents & POLLIN) != 0; 603*0957b409SSimon J. Gerraty #endif 604*0957b409SSimon J. Gerraty 605*0957b409SSimon J. Gerraty /* 606*0957b409SSimon J. Gerraty * We give preference to outgoing data, on stdout and on 607*0957b409SSimon J. Gerraty * the socket. 608*0957b409SSimon J. Gerraty */ 609*0957b409SSimon J. Gerraty if (recvapp_ok) { 610*0957b409SSimon J. Gerraty unsigned char *buf; 611*0957b409SSimon J. Gerraty size_t len; 612*0957b409SSimon J. Gerraty #ifdef _WIN32 613*0957b409SSimon J. Gerraty DWORD wlen; 614*0957b409SSimon J. Gerraty #else 615*0957b409SSimon J. Gerraty ssize_t wlen; 616*0957b409SSimon J. Gerraty #endif 617*0957b409SSimon J. Gerraty 618*0957b409SSimon J. Gerraty buf = br_ssl_engine_recvapp_buf(cc, &len); 619*0957b409SSimon J. Gerraty #ifdef _WIN32 620*0957b409SSimon J. Gerraty if (!WriteFile(h_out, buf, len, &wlen, NULL)) { 621*0957b409SSimon J. Gerraty if (verbose) { 622*0957b409SSimon J. Gerraty fprintf(stderr, "stdout closed...\n"); 623*0957b409SSimon J. Gerraty } 624*0957b409SSimon J. Gerraty retcode = -2; 625*0957b409SSimon J. Gerraty goto engine_exit; 626*0957b409SSimon J. Gerraty } 627*0957b409SSimon J. Gerraty #else 628*0957b409SSimon J. Gerraty wlen = write(1, buf, len); 629*0957b409SSimon J. Gerraty if (wlen <= 0) { 630*0957b409SSimon J. Gerraty if (verbose) { 631*0957b409SSimon J. Gerraty fprintf(stderr, "stdout closed...\n"); 632*0957b409SSimon J. Gerraty } 633*0957b409SSimon J. Gerraty retcode = -2; 634*0957b409SSimon J. Gerraty goto engine_exit; 635*0957b409SSimon J. Gerraty } 636*0957b409SSimon J. Gerraty #endif 637*0957b409SSimon J. Gerraty br_ssl_engine_recvapp_ack(cc, wlen); 638*0957b409SSimon J. Gerraty continue; 639*0957b409SSimon J. Gerraty } 640*0957b409SSimon J. Gerraty if (sendrec_ok) { 641*0957b409SSimon J. Gerraty unsigned char *buf; 642*0957b409SSimon J. Gerraty size_t len; 643*0957b409SSimon J. Gerraty int wlen; 644*0957b409SSimon J. Gerraty 645*0957b409SSimon J. Gerraty buf = br_ssl_engine_sendrec_buf(cc, &len); 646*0957b409SSimon J. Gerraty wlen = send(fd, buf, len, 0); 647*0957b409SSimon J. Gerraty if (wlen <= 0) { 648*0957b409SSimon J. Gerraty #ifdef _WIN32 649*0957b409SSimon J. Gerraty int err; 650*0957b409SSimon J. Gerraty 651*0957b409SSimon J. Gerraty err = WSAGetLastError(); 652*0957b409SSimon J. Gerraty if (err == EWOULDBLOCK 653*0957b409SSimon J. Gerraty || err == WSAEWOULDBLOCK) 654*0957b409SSimon J. Gerraty { 655*0957b409SSimon J. Gerraty can_send = 0; 656*0957b409SSimon J. Gerraty continue; 657*0957b409SSimon J. Gerraty } 658*0957b409SSimon J. Gerraty #else 659*0957b409SSimon J. Gerraty if (errno == EINTR || errno == EWOULDBLOCK) { 660*0957b409SSimon J. Gerraty continue; 661*0957b409SSimon J. Gerraty } 662*0957b409SSimon J. Gerraty #endif 663*0957b409SSimon J. Gerraty if (verbose) { 664*0957b409SSimon J. Gerraty fprintf(stderr, "socket closed...\n"); 665*0957b409SSimon J. Gerraty } 666*0957b409SSimon J. Gerraty retcode = -1; 667*0957b409SSimon J. Gerraty goto engine_exit; 668*0957b409SSimon J. Gerraty } 669*0957b409SSimon J. Gerraty if (trace) { 670*0957b409SSimon J. Gerraty dump_blob("Outgoing bytes", buf, wlen); 671*0957b409SSimon J. Gerraty } 672*0957b409SSimon J. Gerraty br_ssl_engine_sendrec_ack(cc, wlen); 673*0957b409SSimon J. Gerraty continue; 674*0957b409SSimon J. Gerraty } 675*0957b409SSimon J. Gerraty if (recvrec_ok) { 676*0957b409SSimon J. Gerraty unsigned char *buf; 677*0957b409SSimon J. Gerraty size_t len; 678*0957b409SSimon J. Gerraty int rlen; 679*0957b409SSimon J. Gerraty 680*0957b409SSimon J. Gerraty buf = br_ssl_engine_recvrec_buf(cc, &len); 681*0957b409SSimon J. Gerraty rlen = recv(fd, buf, len, 0); 682*0957b409SSimon J. Gerraty if (rlen == 0) { 683*0957b409SSimon J. Gerraty if (verbose) { 684*0957b409SSimon J. Gerraty fprintf(stderr, "socket closed...\n"); 685*0957b409SSimon J. Gerraty } 686*0957b409SSimon J. Gerraty retcode = -1; 687*0957b409SSimon J. Gerraty goto engine_exit; 688*0957b409SSimon J. Gerraty } 689*0957b409SSimon J. Gerraty if (rlen < 0) { 690*0957b409SSimon J. Gerraty #ifdef _WIN32 691*0957b409SSimon J. Gerraty int err; 692*0957b409SSimon J. Gerraty 693*0957b409SSimon J. Gerraty err = WSAGetLastError(); 694*0957b409SSimon J. Gerraty if (err == EWOULDBLOCK 695*0957b409SSimon J. Gerraty || err == WSAEWOULDBLOCK) 696*0957b409SSimon J. Gerraty { 697*0957b409SSimon J. Gerraty can_recv = 0; 698*0957b409SSimon J. Gerraty continue; 699*0957b409SSimon J. Gerraty } 700*0957b409SSimon J. Gerraty #else 701*0957b409SSimon J. Gerraty if (errno == EINTR || errno == EWOULDBLOCK) { 702*0957b409SSimon J. Gerraty continue; 703*0957b409SSimon J. Gerraty } 704*0957b409SSimon J. Gerraty #endif 705*0957b409SSimon J. Gerraty if (verbose) { 706*0957b409SSimon J. Gerraty fprintf(stderr, "socket broke...\n"); 707*0957b409SSimon J. Gerraty } 708*0957b409SSimon J. Gerraty retcode = -1; 709*0957b409SSimon J. Gerraty goto engine_exit; 710*0957b409SSimon J. Gerraty } 711*0957b409SSimon J. Gerraty if (trace) { 712*0957b409SSimon J. Gerraty dump_blob("Incoming bytes", buf, rlen); 713*0957b409SSimon J. Gerraty } 714*0957b409SSimon J. Gerraty br_ssl_engine_recvrec_ack(cc, rlen); 715*0957b409SSimon J. Gerraty continue; 716*0957b409SSimon J. Gerraty } 717*0957b409SSimon J. Gerraty if (sendapp_ok) { 718*0957b409SSimon J. Gerraty unsigned char *buf; 719*0957b409SSimon J. Gerraty size_t len; 720*0957b409SSimon J. Gerraty #ifdef _WIN32 721*0957b409SSimon J. Gerraty int rlen; 722*0957b409SSimon J. Gerraty #else 723*0957b409SSimon J. Gerraty ssize_t rlen; 724*0957b409SSimon J. Gerraty #endif 725*0957b409SSimon J. Gerraty 726*0957b409SSimon J. Gerraty buf = br_ssl_engine_sendapp_buf(cc, &len); 727*0957b409SSimon J. Gerraty #ifdef _WIN32 728*0957b409SSimon J. Gerraty rlen = in_read_buffered(h_in, &bb, buf, len); 729*0957b409SSimon J. Gerraty #else 730*0957b409SSimon J. Gerraty rlen = read(0, buf, len); 731*0957b409SSimon J. Gerraty #endif 732*0957b409SSimon J. Gerraty if (rlen <= 0) { 733*0957b409SSimon J. Gerraty if (verbose) { 734*0957b409SSimon J. Gerraty fprintf(stderr, "stdin closed...\n"); 735*0957b409SSimon J. Gerraty } 736*0957b409SSimon J. Gerraty br_ssl_engine_close(cc); 737*0957b409SSimon J. Gerraty } else if (!run_command(cc, buf, rlen)) { 738*0957b409SSimon J. Gerraty br_ssl_engine_sendapp_ack(cc, rlen); 739*0957b409SSimon J. Gerraty } 740*0957b409SSimon J. Gerraty br_ssl_engine_flush(cc, 0); 741*0957b409SSimon J. Gerraty continue; 742*0957b409SSimon J. Gerraty } 743*0957b409SSimon J. Gerraty 744*0957b409SSimon J. Gerraty /* We should never reach that point. */ 745*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: poll() misbehaves\n"); 746*0957b409SSimon J. Gerraty retcode = -2; 747*0957b409SSimon J. Gerraty goto engine_exit; 748*0957b409SSimon J. Gerraty } 749*0957b409SSimon J. Gerraty 750*0957b409SSimon J. Gerraty /* 751*0957b409SSimon J. Gerraty * Release allocated structures. 752*0957b409SSimon J. Gerraty */ 753*0957b409SSimon J. Gerraty engine_exit: 754*0957b409SSimon J. Gerraty #ifdef _WIN32 755*0957b409SSimon J. Gerraty if (fd_event != WSA_INVALID_EVENT) { 756*0957b409SSimon J. Gerraty WSACloseEvent(fd_event); 757*0957b409SSimon J. Gerraty } 758*0957b409SSimon J. Gerraty #endif 759*0957b409SSimon J. Gerraty return retcode; 760*0957b409SSimon J. Gerraty } 761