xref: /freebsd/contrib/bearssl/tools/sslio.c (revision cc9e6590773dba57440750c124173ed531349a06)
10957b409SSimon J. Gerraty /*
20957b409SSimon J. Gerraty  * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
30957b409SSimon J. Gerraty  *
40957b409SSimon J. Gerraty  * Permission is hereby granted, free of charge, to any person obtaining
50957b409SSimon J. Gerraty  * a copy of this software and associated documentation files (the
60957b409SSimon J. Gerraty  * "Software"), to deal in the Software without restriction, including
70957b409SSimon J. Gerraty  * without limitation the rights to use, copy, modify, merge, publish,
80957b409SSimon J. Gerraty  * distribute, sublicense, and/or sell copies of the Software, and to
90957b409SSimon J. Gerraty  * permit persons to whom the Software is furnished to do so, subject to
100957b409SSimon J. Gerraty  * the following conditions:
110957b409SSimon J. Gerraty  *
120957b409SSimon J. Gerraty  * The above copyright notice and this permission notice shall be
130957b409SSimon J. Gerraty  * included in all copies or substantial portions of the Software.
140957b409SSimon J. Gerraty  *
150957b409SSimon J. Gerraty  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
160957b409SSimon J. Gerraty  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
170957b409SSimon J. Gerraty  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
180957b409SSimon J. Gerraty  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
190957b409SSimon J. Gerraty  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
200957b409SSimon J. Gerraty  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
210957b409SSimon J. Gerraty  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
220957b409SSimon J. Gerraty  * SOFTWARE.
230957b409SSimon J. Gerraty  */
240957b409SSimon J. Gerraty 
250957b409SSimon J. Gerraty #include <stdio.h>
260957b409SSimon J. Gerraty #include <stdlib.h>
270957b409SSimon J. Gerraty #include <string.h>
280957b409SSimon J. Gerraty #include <stdint.h>
290957b409SSimon J. Gerraty #include <errno.h>
300957b409SSimon J. Gerraty 
310957b409SSimon J. Gerraty #ifdef _WIN32
320957b409SSimon J. Gerraty #include <winsock2.h>
330957b409SSimon J. Gerraty #include <ws2tcpip.h>
340957b409SSimon J. Gerraty #else
350957b409SSimon J. Gerraty #include <sys/types.h>
360957b409SSimon J. Gerraty #include <sys/socket.h>
370957b409SSimon J. Gerraty #include <netdb.h>
380957b409SSimon J. Gerraty #include <netinet/in.h>
390957b409SSimon J. Gerraty #include <arpa/inet.h>
400957b409SSimon J. Gerraty #include <unistd.h>
410957b409SSimon J. Gerraty #include <fcntl.h>
420957b409SSimon J. Gerraty #include <poll.h>
430957b409SSimon J. Gerraty 
440957b409SSimon J. Gerraty #define SOCKET           int
450957b409SSimon J. Gerraty #define INVALID_SOCKET   (-1)
460957b409SSimon J. Gerraty #endif
470957b409SSimon J. Gerraty 
480957b409SSimon J. Gerraty #include "brssl.h"
490957b409SSimon J. Gerraty 
500957b409SSimon J. Gerraty static void
dump_blob(const char * name,const void * data,size_t len)510957b409SSimon J. Gerraty dump_blob(const char *name, const void *data, size_t len)
520957b409SSimon J. Gerraty {
530957b409SSimon J. Gerraty 	const unsigned char *buf;
540957b409SSimon J. Gerraty 	size_t u;
550957b409SSimon J. Gerraty 
560957b409SSimon J. Gerraty 	buf = data;
570957b409SSimon J. Gerraty 	fprintf(stderr, "%s (len = %lu)", name, (unsigned long)len);
580957b409SSimon J. Gerraty 	for (u = 0; u < len; u ++) {
590957b409SSimon J. Gerraty 		if ((u & 15) == 0) {
600957b409SSimon J. Gerraty 			fprintf(stderr, "\n%08lX  ", (unsigned long)u);
610957b409SSimon J. Gerraty 		} else if ((u & 7) == 0) {
620957b409SSimon J. Gerraty 			fprintf(stderr, " ");
630957b409SSimon J. Gerraty 		}
640957b409SSimon J. Gerraty 		fprintf(stderr, " %02x", buf[u]);
650957b409SSimon J. Gerraty 	}
660957b409SSimon J. Gerraty 	fprintf(stderr, "\n");
670957b409SSimon J. Gerraty }
680957b409SSimon J. Gerraty 
690957b409SSimon J. Gerraty /*
700957b409SSimon J. Gerraty  * Inspect the provided data in case it is a "command" to trigger a
710957b409SSimon J. Gerraty  * special behaviour. If the command is recognised, then it is executed
720957b409SSimon J. Gerraty  * and this function returns 1. Otherwise, this function returns 0.
730957b409SSimon J. Gerraty  */
740957b409SSimon J. Gerraty static int
run_command(br_ssl_engine_context * cc,unsigned char * buf,size_t len)750957b409SSimon J. Gerraty run_command(br_ssl_engine_context *cc, unsigned char *buf, size_t len)
760957b409SSimon J. Gerraty {
770957b409SSimon J. Gerraty 	/*
780957b409SSimon J. Gerraty 	 * A single static slot for saving session parameters.
790957b409SSimon J. Gerraty 	 */
800957b409SSimon J. Gerraty 	static br_ssl_session_parameters slot;
810957b409SSimon J. Gerraty 	static int slot_used = 0;
820957b409SSimon J. Gerraty 
830957b409SSimon J. Gerraty 	size_t u;
840957b409SSimon J. Gerraty 
850957b409SSimon J. Gerraty 	if (len < 2 || len > 3) {
860957b409SSimon J. Gerraty 		return 0;
870957b409SSimon J. Gerraty 	}
880957b409SSimon J. Gerraty 	if (len == 3 && (buf[1] != '\r' || buf[2] != '\n')) {
890957b409SSimon J. Gerraty 		return 0;
900957b409SSimon J. Gerraty 	}
910957b409SSimon J. Gerraty 	if (len == 2 && buf[1] != '\n') {
920957b409SSimon J. Gerraty 		return 0;
930957b409SSimon J. Gerraty 	}
940957b409SSimon J. Gerraty 	switch (buf[0]) {
950957b409SSimon J. Gerraty 	case 'Q':
960957b409SSimon J. Gerraty 		fprintf(stderr, "closing...\n");
970957b409SSimon J. Gerraty 		br_ssl_engine_close(cc);
980957b409SSimon J. Gerraty 		return 1;
990957b409SSimon J. Gerraty 	case 'R':
1000957b409SSimon J. Gerraty 		if (br_ssl_engine_renegotiate(cc)) {
1010957b409SSimon J. Gerraty 			fprintf(stderr, "renegotiating...\n");
1020957b409SSimon J. Gerraty 		} else {
1030957b409SSimon J. Gerraty 			fprintf(stderr, "not renegotiating.\n");
1040957b409SSimon J. Gerraty 		}
1050957b409SSimon J. Gerraty 		return 1;
1060957b409SSimon J. Gerraty 	case 'F':
1070957b409SSimon J. Gerraty 		/*
1080957b409SSimon J. Gerraty 		 * Session forget is nominally client-only. But the
1090957b409SSimon J. Gerraty 		 * session parameters are in the engine structure, which
1100957b409SSimon J. Gerraty 		 * is the first field of the client context, so the cast
1110957b409SSimon J. Gerraty 		 * still works properly. On the server, this forgetting
1120957b409SSimon J. Gerraty 		 * has no effect.
1130957b409SSimon J. Gerraty 		 */
1140957b409SSimon J. Gerraty 		fprintf(stderr, "forgetting session...\n");
1150957b409SSimon J. Gerraty 		br_ssl_client_forget_session((br_ssl_client_context *)cc);
1160957b409SSimon J. Gerraty 		return 1;
1170957b409SSimon J. Gerraty 	case 'S':
1180957b409SSimon J. Gerraty 		fprintf(stderr, "saving session parameters...\n");
1190957b409SSimon J. Gerraty 		br_ssl_engine_get_session_parameters(cc, &slot);
1200957b409SSimon J. Gerraty 		fprintf(stderr, "  id = ");
1210957b409SSimon J. Gerraty 		for (u = 0; u < slot.session_id_len; u ++) {
1220957b409SSimon J. Gerraty 			fprintf(stderr, "%02X", slot.session_id[u]);
1230957b409SSimon J. Gerraty 		}
1240957b409SSimon J. Gerraty 		fprintf(stderr, "\n");
1250957b409SSimon J. Gerraty 		slot_used = 1;
1260957b409SSimon J. Gerraty 		return 1;
1270957b409SSimon J. Gerraty 	case 'P':
1280957b409SSimon J. Gerraty 		if (slot_used) {
1290957b409SSimon J. Gerraty 			fprintf(stderr, "restoring session parameters...\n");
1300957b409SSimon J. Gerraty 			fprintf(stderr, "  id = ");
1310957b409SSimon J. Gerraty 			for (u = 0; u < slot.session_id_len; u ++) {
1320957b409SSimon J. Gerraty 				fprintf(stderr, "%02X", slot.session_id[u]);
1330957b409SSimon J. Gerraty 			}
1340957b409SSimon J. Gerraty 			fprintf(stderr, "\n");
1350957b409SSimon J. Gerraty 			br_ssl_engine_set_session_parameters(cc, &slot);
1360957b409SSimon J. Gerraty 			return 1;
1370957b409SSimon J. Gerraty 		}
1380957b409SSimon J. Gerraty 		return 0;
1390957b409SSimon J. Gerraty 	default:
1400957b409SSimon J. Gerraty 		return 0;
1410957b409SSimon J. Gerraty 	}
1420957b409SSimon J. Gerraty }
1430957b409SSimon J. Gerraty 
1440957b409SSimon J. Gerraty #ifdef _WIN32
1450957b409SSimon J. Gerraty 
1460957b409SSimon J. Gerraty typedef struct {
1470957b409SSimon J. Gerraty 	unsigned char buf[1024];
1480957b409SSimon J. Gerraty 	size_t ptr, len;
1490957b409SSimon J. Gerraty } in_buffer;
1500957b409SSimon J. Gerraty 
1510957b409SSimon J. Gerraty static int
in_return_bytes(in_buffer * bb,unsigned char * buf,size_t len)1520957b409SSimon J. Gerraty in_return_bytes(in_buffer *bb, unsigned char *buf, size_t len)
1530957b409SSimon J. Gerraty {
1540957b409SSimon J. Gerraty 	if (bb->ptr < bb->len) {
1550957b409SSimon J. Gerraty 		size_t clen;
1560957b409SSimon J. Gerraty 
1570957b409SSimon J. Gerraty 		if (buf == NULL) {
1580957b409SSimon J. Gerraty 			return 1;
1590957b409SSimon J. Gerraty 		}
1600957b409SSimon J. Gerraty 		clen = bb->len - bb->ptr;
1610957b409SSimon J. Gerraty 		if (clen > len) {
1620957b409SSimon J. Gerraty 			clen = len;
1630957b409SSimon J. Gerraty 		}
1640957b409SSimon J. Gerraty 		memcpy(buf, bb->buf + bb->ptr, clen);
1650957b409SSimon J. Gerraty 		bb->ptr += clen;
1660957b409SSimon J. Gerraty 		if (bb->ptr == bb->len) {
1670957b409SSimon J. Gerraty 			bb->ptr = bb->len = 0;
1680957b409SSimon J. Gerraty 		}
1690957b409SSimon J. Gerraty 		return (int)clen;
1700957b409SSimon J. Gerraty 	}
1710957b409SSimon J. Gerraty 	return 0;
1720957b409SSimon J. Gerraty }
1730957b409SSimon J. Gerraty 
1740957b409SSimon J. Gerraty /*
1750957b409SSimon J. Gerraty  * A buffered version of in_read(), using a buffer to return only
1760957b409SSimon J. Gerraty  * full lines when feasible.
1770957b409SSimon J. Gerraty  */
1780957b409SSimon J. Gerraty static int
in_read_buffered(HANDLE h_in,in_buffer * bb,unsigned char * buf,size_t len)1790957b409SSimon J. Gerraty in_read_buffered(HANDLE h_in, in_buffer *bb, unsigned char *buf, size_t len)
1800957b409SSimon J. Gerraty {
1810957b409SSimon J. Gerraty 	int n;
1820957b409SSimon J. Gerraty 
1830957b409SSimon J. Gerraty 	if (len == 0) {
1840957b409SSimon J. Gerraty 		return 0;
1850957b409SSimon J. Gerraty 	}
1860957b409SSimon J. Gerraty 	n = in_return_bytes(bb, buf, len);
1870957b409SSimon J. Gerraty 	if (n != 0) {
1880957b409SSimon J. Gerraty 		return n;
1890957b409SSimon J. Gerraty 	}
1900957b409SSimon J. Gerraty 	for (;;) {
1910957b409SSimon J. Gerraty 		INPUT_RECORD inrec;
1920957b409SSimon J. Gerraty 		DWORD v;
1930957b409SSimon J. Gerraty 
1940957b409SSimon J. Gerraty 		if (!PeekConsoleInput(h_in, &inrec, 1, &v)) {
1950957b409SSimon J. Gerraty 			fprintf(stderr, "ERROR: PeekConsoleInput()"
1960957b409SSimon J. Gerraty 				" failed with 0x%08lX\n",
1970957b409SSimon J. Gerraty 				(unsigned long)GetLastError());
1980957b409SSimon J. Gerraty 			return -1;
1990957b409SSimon J. Gerraty 		}
2000957b409SSimon J. Gerraty 		if (v == 0) {
2010957b409SSimon J. Gerraty 			return 0;
2020957b409SSimon J. Gerraty 		}
2030957b409SSimon J. Gerraty 		if (!ReadConsoleInput(h_in, &inrec, 1, &v)) {
2040957b409SSimon J. Gerraty 			fprintf(stderr, "ERROR: ReadConsoleInput()"
2050957b409SSimon J. Gerraty 				" failed with 0x%08lX\n",
2060957b409SSimon J. Gerraty 				(unsigned long)GetLastError());
2070957b409SSimon J. Gerraty 			return -1;
2080957b409SSimon J. Gerraty 		}
2090957b409SSimon J. Gerraty 		if (v == 0) {
2100957b409SSimon J. Gerraty 			return 0;
2110957b409SSimon J. Gerraty 		}
2120957b409SSimon J. Gerraty 		if (inrec.EventType == KEY_EVENT
2130957b409SSimon J. Gerraty 			&& inrec.Event.KeyEvent.bKeyDown)
2140957b409SSimon J. Gerraty 		{
2150957b409SSimon J. Gerraty 			int c;
2160957b409SSimon J. Gerraty 
2170957b409SSimon J. Gerraty 			c = inrec.Event.KeyEvent.uChar.AsciiChar;
2180957b409SSimon J. Gerraty 			if (c == '\n' || c == '\r' || c == '\t'
2190957b409SSimon J. Gerraty 				|| (c >= 32 && c != 127))
2200957b409SSimon J. Gerraty 			{
2210957b409SSimon J. Gerraty 				if (c == '\r') {
2220957b409SSimon J. Gerraty 					c = '\n';
2230957b409SSimon J. Gerraty 				}
2240957b409SSimon J. Gerraty 				bb->buf[bb->ptr ++] = (unsigned char)c;
2250957b409SSimon J. Gerraty 				printf("%c", c);
2260957b409SSimon J. Gerraty 				fflush(stdout);
2270957b409SSimon J. Gerraty 				bb->len = bb->ptr;
2280957b409SSimon J. Gerraty 				if (bb->len == sizeof bb->buf || c == '\n') {
2290957b409SSimon J. Gerraty 					bb->ptr = 0;
2300957b409SSimon J. Gerraty 					return in_return_bytes(bb, buf, len);
2310957b409SSimon J. Gerraty 				}
2320957b409SSimon J. Gerraty 			}
2330957b409SSimon J. Gerraty 		}
2340957b409SSimon J. Gerraty 	}
2350957b409SSimon J. Gerraty }
2360957b409SSimon J. Gerraty 
2370957b409SSimon J. Gerraty static int
in_avail_buffered(HANDLE h_in,in_buffer * bb)2380957b409SSimon J. Gerraty in_avail_buffered(HANDLE h_in, in_buffer *bb)
2390957b409SSimon J. Gerraty {
2400957b409SSimon J. Gerraty 	return in_read_buffered(h_in, bb, NULL, 1);
2410957b409SSimon J. Gerraty }
2420957b409SSimon J. Gerraty 
2430957b409SSimon J. Gerraty #endif
2440957b409SSimon J. Gerraty 
2450957b409SSimon J. Gerraty /* see brssl.h */
2460957b409SSimon J. Gerraty int
run_ssl_engine(br_ssl_engine_context * cc,unsigned long fd,unsigned flags)2470957b409SSimon J. Gerraty run_ssl_engine(br_ssl_engine_context *cc, unsigned long fd, unsigned flags)
2480957b409SSimon J. Gerraty {
2490957b409SSimon J. Gerraty 	int hsdetails;
2500957b409SSimon J. Gerraty 	int retcode;
2510957b409SSimon J. Gerraty 	int verbose;
2520957b409SSimon J. Gerraty 	int trace;
2530957b409SSimon J. Gerraty #ifdef _WIN32
2540957b409SSimon J. Gerraty 	WSAEVENT fd_event;
2550957b409SSimon J. Gerraty 	int can_send, can_recv;
2560957b409SSimon J. Gerraty 	HANDLE h_in, h_out;
2570957b409SSimon J. Gerraty 	in_buffer bb;
2580957b409SSimon J. Gerraty #endif
2590957b409SSimon J. Gerraty 
2600957b409SSimon J. Gerraty 	hsdetails = 0;
2610957b409SSimon J. Gerraty 	retcode = 0;
2620957b409SSimon J. Gerraty 	verbose = (flags & RUN_ENGINE_VERBOSE) != 0;
2630957b409SSimon J. Gerraty 	trace = (flags & RUN_ENGINE_TRACE) != 0;
2640957b409SSimon J. Gerraty 
2650957b409SSimon J. Gerraty 	/*
2660957b409SSimon J. Gerraty 	 * Print algorithm details.
2670957b409SSimon J. Gerraty 	 */
2680957b409SSimon J. Gerraty 	if (verbose) {
2690957b409SSimon J. Gerraty 		const char *rngname;
2700957b409SSimon J. Gerraty 
2710957b409SSimon J. Gerraty 		fprintf(stderr, "Algorithms:\n");
2720957b409SSimon J. Gerraty 		br_prng_seeder_system(&rngname);
2730957b409SSimon J. Gerraty 		fprintf(stderr, "   RNG:           %s\n", rngname);
2740957b409SSimon J. Gerraty 		if (cc->iaes_cbcenc != 0) {
2750957b409SSimon J. Gerraty 			fprintf(stderr, "   AES/CBC (enc): %s\n",
2760957b409SSimon J. Gerraty 				get_algo_name(cc->iaes_cbcenc, 0));
2770957b409SSimon J. Gerraty 		}
2780957b409SSimon J. Gerraty 		if (cc->iaes_cbcdec != 0) {
2790957b409SSimon J. Gerraty 			fprintf(stderr, "   AES/CBC (dec): %s\n",
2800957b409SSimon J. Gerraty 				get_algo_name(cc->iaes_cbcdec, 0));
2810957b409SSimon J. Gerraty 		}
2820957b409SSimon J. Gerraty 		if (cc->iaes_ctr != 0) {
2830957b409SSimon J. Gerraty 			fprintf(stderr, "   AES/CTR:       %s\n",
284*cc9e6590SSimon J. Gerraty 				get_algo_name(cc->iaes_ctr, 0));
2850957b409SSimon J. Gerraty 		}
2860957b409SSimon J. Gerraty 		if (cc->iaes_ctrcbc != 0) {
2870957b409SSimon J. Gerraty 			fprintf(stderr, "   AES/CCM:       %s\n",
2880957b409SSimon J. Gerraty 				get_algo_name(cc->iaes_ctrcbc, 0));
2890957b409SSimon J. Gerraty 		}
2900957b409SSimon J. Gerraty 		if (cc->ides_cbcenc != 0) {
2910957b409SSimon J. Gerraty 			fprintf(stderr, "   DES/CBC (enc): %s\n",
2920957b409SSimon J. Gerraty 				get_algo_name(cc->ides_cbcenc, 0));
2930957b409SSimon J. Gerraty 		}
2940957b409SSimon J. Gerraty 		if (cc->ides_cbcdec != 0) {
2950957b409SSimon J. Gerraty 			fprintf(stderr, "   DES/CBC (dec): %s\n",
2960957b409SSimon J. Gerraty 				get_algo_name(cc->ides_cbcdec, 0));
2970957b409SSimon J. Gerraty 		}
2980957b409SSimon J. Gerraty 		if (cc->ighash != 0) {
2990957b409SSimon J. Gerraty 			fprintf(stderr, "   GHASH (GCM):   %s\n",
3000957b409SSimon J. Gerraty 				get_algo_name(cc->ighash, 0));
3010957b409SSimon J. Gerraty 		}
3020957b409SSimon J. Gerraty 		if (cc->ichacha != 0) {
3030957b409SSimon J. Gerraty 			fprintf(stderr, "   ChaCha20:      %s\n",
3040957b409SSimon J. Gerraty 				get_algo_name(cc->ichacha, 0));
3050957b409SSimon J. Gerraty 		}
3060957b409SSimon J. Gerraty 		if (cc->ipoly != 0) {
3070957b409SSimon J. Gerraty 			fprintf(stderr, "   Poly1305:      %s\n",
3080957b409SSimon J. Gerraty 				get_algo_name(cc->ipoly, 0));
3090957b409SSimon J. Gerraty 		}
3100957b409SSimon J. Gerraty 		if (cc->iec != 0) {
3110957b409SSimon J. Gerraty 			fprintf(stderr, "   EC:            %s\n",
3120957b409SSimon J. Gerraty 				get_algo_name(cc->iec, 0));
3130957b409SSimon J. Gerraty 		}
3140957b409SSimon J. Gerraty 		if (cc->iecdsa != 0) {
3150957b409SSimon J. Gerraty 			fprintf(stderr, "   ECDSA:         %s\n",
3160957b409SSimon J. Gerraty 				get_algo_name(cc->iecdsa, 0));
3170957b409SSimon J. Gerraty 		}
3180957b409SSimon J. Gerraty 		if (cc->irsavrfy != 0) {
3190957b409SSimon J. Gerraty 			fprintf(stderr, "   RSA (vrfy):    %s\n",
3200957b409SSimon J. Gerraty 				get_algo_name(cc->irsavrfy, 0));
3210957b409SSimon J. Gerraty 		}
3220957b409SSimon J. Gerraty 	}
3230957b409SSimon J. Gerraty 
3240957b409SSimon J. Gerraty #ifdef _WIN32
3250957b409SSimon J. Gerraty 	fd_event = WSA_INVALID_EVENT;
3260957b409SSimon J. Gerraty 	can_send = 0;
3270957b409SSimon J. Gerraty 	can_recv = 0;
3280957b409SSimon J. Gerraty 	bb.ptr = bb.len = 0;
3290957b409SSimon J. Gerraty #endif
3300957b409SSimon J. Gerraty 
3310957b409SSimon J. Gerraty 	/*
3320957b409SSimon J. Gerraty 	 * On Unix systems, we need to follow three descriptors:
3330957b409SSimon J. Gerraty 	 * standard input (0), standard output (1), and the socket
3340957b409SSimon J. Gerraty 	 * itself (for both read and write). This is done with a poll()
3350957b409SSimon J. Gerraty 	 * call.
3360957b409SSimon J. Gerraty 	 *
3370957b409SSimon J. Gerraty 	 * On Windows systems, we use WSAEventSelect() to associate
3380957b409SSimon J. Gerraty 	 * an event handle with the network activity, and we use
3390957b409SSimon J. Gerraty 	 * WaitForMultipleObjectsEx() on that handle and the standard
3400957b409SSimon J. Gerraty 	 * input handle, when appropriate. Standard output is assumed
3410957b409SSimon J. Gerraty 	 * to be always writeable, and standard input to be the console;
3420957b409SSimon J. Gerraty 	 * this does not work well (or at all) with redirections (to
3430957b409SSimon J. Gerraty 	 * pipes or files) but it should be enough for a debug tool
3440957b409SSimon J. Gerraty 	 * (TODO: make something that handles redirections as well).
3450957b409SSimon J. Gerraty 	 */
3460957b409SSimon J. Gerraty 
3470957b409SSimon J. Gerraty #ifdef _WIN32
3480957b409SSimon J. Gerraty 	fd_event = WSACreateEvent();
3490957b409SSimon J. Gerraty 	if (fd_event == WSA_INVALID_EVENT) {
3500957b409SSimon J. Gerraty 		fprintf(stderr, "ERROR: WSACreateEvent() failed with %d\n",
3510957b409SSimon J. Gerraty 			WSAGetLastError());
3520957b409SSimon J. Gerraty 		retcode = -2;
3530957b409SSimon J. Gerraty 		goto engine_exit;
3540957b409SSimon J. Gerraty 	}
3550957b409SSimon J. Gerraty 	WSAEventSelect(fd, fd_event, FD_READ | FD_WRITE | FD_CLOSE);
3560957b409SSimon J. Gerraty 	h_in = GetStdHandle(STD_INPUT_HANDLE);
3570957b409SSimon J. Gerraty 	h_out = GetStdHandle(STD_OUTPUT_HANDLE);
3580957b409SSimon J. Gerraty 	SetConsoleMode(h_in, ENABLE_ECHO_INPUT
3590957b409SSimon J. Gerraty 		| ENABLE_LINE_INPUT
3600957b409SSimon J. Gerraty 		| ENABLE_PROCESSED_INPUT
3610957b409SSimon J. Gerraty 		| ENABLE_PROCESSED_OUTPUT
3620957b409SSimon J. Gerraty 		| ENABLE_WRAP_AT_EOL_OUTPUT);
3630957b409SSimon J. Gerraty #else
3640957b409SSimon J. Gerraty 	/*
3650957b409SSimon J. Gerraty 	 * Make sure that stdin and stdout are non-blocking.
3660957b409SSimon J. Gerraty 	 */
3670957b409SSimon J. Gerraty 	fcntl(0, F_SETFL, O_NONBLOCK);
3680957b409SSimon J. Gerraty 	fcntl(1, F_SETFL, O_NONBLOCK);
3690957b409SSimon J. Gerraty #endif
3700957b409SSimon J. Gerraty 
3710957b409SSimon J. Gerraty 	/*
3720957b409SSimon J. Gerraty 	 * Perform the loop.
3730957b409SSimon J. Gerraty 	 */
3740957b409SSimon J. Gerraty 	for (;;) {
3750957b409SSimon J. Gerraty 		unsigned st;
3760957b409SSimon J. Gerraty 		int sendrec, recvrec, sendapp, recvapp;
3770957b409SSimon J. Gerraty #ifdef _WIN32
3780957b409SSimon J. Gerraty 		HANDLE pfd[2];
3790957b409SSimon J. Gerraty 		DWORD wt;
3800957b409SSimon J. Gerraty #else
3810957b409SSimon J. Gerraty 		struct pollfd pfd[3];
3820957b409SSimon J. Gerraty 		int n;
3830957b409SSimon J. Gerraty #endif
3840957b409SSimon J. Gerraty 		size_t u, k_fd, k_in, k_out;
3850957b409SSimon J. Gerraty 		int sendrec_ok, recvrec_ok, sendapp_ok, recvapp_ok;
3860957b409SSimon J. Gerraty 
3870957b409SSimon J. Gerraty 		/*
3880957b409SSimon J. Gerraty 		 * Get current engine state.
3890957b409SSimon J. Gerraty 		 */
3900957b409SSimon J. Gerraty 		st = br_ssl_engine_current_state(cc);
3910957b409SSimon J. Gerraty 		if (st == BR_SSL_CLOSED) {
3920957b409SSimon J. Gerraty 			int err;
3930957b409SSimon J. Gerraty 
3940957b409SSimon J. Gerraty 			err = br_ssl_engine_last_error(cc);
3950957b409SSimon J. Gerraty 			if (err == BR_ERR_OK) {
3960957b409SSimon J. Gerraty 				if (verbose) {
3970957b409SSimon J. Gerraty 					fprintf(stderr,
3980957b409SSimon J. Gerraty 						"SSL closed normally\n");
3990957b409SSimon J. Gerraty 				}
4000957b409SSimon J. Gerraty 				retcode = 0;
4010957b409SSimon J. Gerraty 				goto engine_exit;
4020957b409SSimon J. Gerraty 			} else {
4030957b409SSimon J. Gerraty 				fprintf(stderr, "ERROR: SSL error %d", err);
4040957b409SSimon J. Gerraty 				retcode = err;
4050957b409SSimon J. Gerraty 				if (err >= BR_ERR_SEND_FATAL_ALERT) {
4060957b409SSimon J. Gerraty 					err -= BR_ERR_SEND_FATAL_ALERT;
4070957b409SSimon J. Gerraty 					fprintf(stderr,
4080957b409SSimon J. Gerraty 						" (sent alert %d)\n", err);
4090957b409SSimon J. Gerraty 				} else if (err >= BR_ERR_RECV_FATAL_ALERT) {
4100957b409SSimon J. Gerraty 					err -= BR_ERR_RECV_FATAL_ALERT;
4110957b409SSimon J. Gerraty 					fprintf(stderr,
4120957b409SSimon J. Gerraty 						" (received alert %d)\n", err);
4130957b409SSimon J. Gerraty 				} else {
4140957b409SSimon J. Gerraty 					const char *ename;
4150957b409SSimon J. Gerraty 
4160957b409SSimon J. Gerraty 					ename = find_error_name(err, NULL);
4170957b409SSimon J. Gerraty 					if (ename == NULL) {
4180957b409SSimon J. Gerraty 						ename = "unknown";
4190957b409SSimon J. Gerraty 					}
4200957b409SSimon J. Gerraty 					fprintf(stderr, " (%s)\n", ename);
4210957b409SSimon J. Gerraty 				}
4220957b409SSimon J. Gerraty 				goto engine_exit;
4230957b409SSimon J. Gerraty 			}
4240957b409SSimon J. Gerraty 		}
4250957b409SSimon J. Gerraty 
4260957b409SSimon J. Gerraty 		/*
4270957b409SSimon J. Gerraty 		 * Compute descriptors that must be polled, depending
4280957b409SSimon J. Gerraty 		 * on engine state.
4290957b409SSimon J. Gerraty 		 */
4300957b409SSimon J. Gerraty 		sendrec = ((st & BR_SSL_SENDREC) != 0);
4310957b409SSimon J. Gerraty 		recvrec = ((st & BR_SSL_RECVREC) != 0);
4320957b409SSimon J. Gerraty 		sendapp = ((st & BR_SSL_SENDAPP) != 0);
4330957b409SSimon J. Gerraty 		recvapp = ((st & BR_SSL_RECVAPP) != 0);
4340957b409SSimon J. Gerraty 		if (verbose && sendapp && !hsdetails) {
4350957b409SSimon J. Gerraty 			char csn[80];
4360957b409SSimon J. Gerraty 			const char *pname;
4370957b409SSimon J. Gerraty 
4380957b409SSimon J. Gerraty 			fprintf(stderr, "Handshake completed\n");
4390957b409SSimon J. Gerraty 			fprintf(stderr, "   version:               ");
4400957b409SSimon J. Gerraty 			switch (cc->session.version) {
4410957b409SSimon J. Gerraty 			case BR_SSL30:
4420957b409SSimon J. Gerraty 				fprintf(stderr, "SSL 3.0");
4430957b409SSimon J. Gerraty 				break;
4440957b409SSimon J. Gerraty 			case BR_TLS10:
4450957b409SSimon J. Gerraty 				fprintf(stderr, "TLS 1.0");
4460957b409SSimon J. Gerraty 				break;
4470957b409SSimon J. Gerraty 			case BR_TLS11:
4480957b409SSimon J. Gerraty 				fprintf(stderr, "TLS 1.1");
4490957b409SSimon J. Gerraty 				break;
4500957b409SSimon J. Gerraty 			case BR_TLS12:
4510957b409SSimon J. Gerraty 				fprintf(stderr, "TLS 1.2");
4520957b409SSimon J. Gerraty 				break;
4530957b409SSimon J. Gerraty 			default:
4540957b409SSimon J. Gerraty 				fprintf(stderr, "unknown (0x%04X)",
4550957b409SSimon J. Gerraty 					(unsigned)cc->session.version);
4560957b409SSimon J. Gerraty 				break;
4570957b409SSimon J. Gerraty 			}
4580957b409SSimon J. Gerraty 			fprintf(stderr, "\n");
4590957b409SSimon J. Gerraty 			get_suite_name_ext(
4600957b409SSimon J. Gerraty 				cc->session.cipher_suite, csn, sizeof csn);
4610957b409SSimon J. Gerraty 			fprintf(stderr, "   cipher suite:          %s\n", csn);
4620957b409SSimon J. Gerraty 			if (uses_ecdhe(cc->session.cipher_suite)) {
4630957b409SSimon J. Gerraty 				get_curve_name_ext(
4640957b409SSimon J. Gerraty 					br_ssl_engine_get_ecdhe_curve(cc),
4650957b409SSimon J. Gerraty 					csn, sizeof csn);
4660957b409SSimon J. Gerraty 				fprintf(stderr,
4670957b409SSimon J. Gerraty 					"   ECDHE curve:           %s\n", csn);
4680957b409SSimon J. Gerraty 			}
4690957b409SSimon J. Gerraty 			fprintf(stderr, "   secure renegotiation:  %s\n",
4700957b409SSimon J. Gerraty 				cc->reneg == 1 ? "no" : "yes");
4710957b409SSimon J. Gerraty 			pname = br_ssl_engine_get_selected_protocol(cc);
4720957b409SSimon J. Gerraty 			if (pname != NULL) {
4730957b409SSimon J. Gerraty 				fprintf(stderr,
4740957b409SSimon J. Gerraty 					"   protocol name (ALPN):  %s\n",
4750957b409SSimon J. Gerraty 					pname);
4760957b409SSimon J. Gerraty 			}
4770957b409SSimon J. Gerraty 			hsdetails = 1;
4780957b409SSimon J. Gerraty 		}
4790957b409SSimon J. Gerraty 
4800957b409SSimon J. Gerraty 		k_fd = (size_t)-1;
4810957b409SSimon J. Gerraty 		k_in = (size_t)-1;
4820957b409SSimon J. Gerraty 		k_out = (size_t)-1;
4830957b409SSimon J. Gerraty 
4840957b409SSimon J. Gerraty 		u = 0;
4850957b409SSimon J. Gerraty #ifdef _WIN32
4860957b409SSimon J. Gerraty 		/*
4870957b409SSimon J. Gerraty 		 * If we recorded that we can send or receive data, and we
4880957b409SSimon J. Gerraty 		 * want to do exactly that, then we don't wait; we just do
4890957b409SSimon J. Gerraty 		 * it.
4900957b409SSimon J. Gerraty 		 */
4910957b409SSimon J. Gerraty 		recvapp_ok = 0;
4920957b409SSimon J. Gerraty 		sendrec_ok = 0;
4930957b409SSimon J. Gerraty 		recvrec_ok = 0;
4940957b409SSimon J. Gerraty 		sendapp_ok = 0;
4950957b409SSimon J. Gerraty 
4960957b409SSimon J. Gerraty 		if (sendrec && can_send) {
4970957b409SSimon J. Gerraty 			sendrec_ok = 1;
4980957b409SSimon J. Gerraty 		} else if (recvrec && can_recv) {
4990957b409SSimon J. Gerraty 			recvrec_ok = 1;
5000957b409SSimon J. Gerraty 		} else if (recvapp) {
5010957b409SSimon J. Gerraty 			recvapp_ok = 1;
5020957b409SSimon J. Gerraty 		} else if (sendapp && in_avail_buffered(h_in, &bb)) {
5030957b409SSimon J. Gerraty 			sendapp_ok = 1;
5040957b409SSimon J. Gerraty 		} else {
5050957b409SSimon J. Gerraty 			/*
5060957b409SSimon J. Gerraty 			 * If we cannot do I/O right away, then we must
5070957b409SSimon J. Gerraty 			 * wait for some event, and try again.
5080957b409SSimon J. Gerraty 			 */
5090957b409SSimon J. Gerraty 			pfd[u] = (HANDLE)fd_event;
5100957b409SSimon J. Gerraty 			k_fd = u;
5110957b409SSimon J. Gerraty 			u ++;
5120957b409SSimon J. Gerraty 			if (sendapp) {
5130957b409SSimon J. Gerraty 				pfd[u] = h_in;
5140957b409SSimon J. Gerraty 				k_in = u;
5150957b409SSimon J. Gerraty 				u ++;
5160957b409SSimon J. Gerraty 			}
5170957b409SSimon J. Gerraty 			wt = WaitForMultipleObjectsEx(u, pfd,
5180957b409SSimon J. Gerraty 				FALSE, INFINITE, FALSE);
5190957b409SSimon J. Gerraty 			if (wt == WAIT_FAILED) {
5200957b409SSimon J. Gerraty 				fprintf(stderr, "ERROR:"
5210957b409SSimon J. Gerraty 					" WaitForMultipleObjectsEx()"
5220957b409SSimon J. Gerraty 					" failed with 0x%08lX",
5230957b409SSimon J. Gerraty 					(unsigned long)GetLastError());
5240957b409SSimon J. Gerraty 				retcode = -2;
5250957b409SSimon J. Gerraty 				goto engine_exit;
5260957b409SSimon J. Gerraty 			}
5270957b409SSimon J. Gerraty 			if (wt == k_fd) {
5280957b409SSimon J. Gerraty 				WSANETWORKEVENTS e;
5290957b409SSimon J. Gerraty 
5300957b409SSimon J. Gerraty 				if (WSAEnumNetworkEvents(fd, fd_event, &e)) {
5310957b409SSimon J. Gerraty 					fprintf(stderr, "ERROR:"
5320957b409SSimon J. Gerraty 						" WSAEnumNetworkEvents()"
5330957b409SSimon J. Gerraty 						" failed with %d\n",
5340957b409SSimon J. Gerraty 						WSAGetLastError());
5350957b409SSimon J. Gerraty 					retcode = -2;
5360957b409SSimon J. Gerraty 					goto engine_exit;
5370957b409SSimon J. Gerraty 				}
5380957b409SSimon J. Gerraty 				if (e.lNetworkEvents & (FD_WRITE | FD_CLOSE)) {
5390957b409SSimon J. Gerraty 					can_send = 1;
5400957b409SSimon J. Gerraty 				}
5410957b409SSimon J. Gerraty 				if (e.lNetworkEvents & (FD_READ | FD_CLOSE)) {
5420957b409SSimon J. Gerraty 					can_recv = 1;
5430957b409SSimon J. Gerraty 				}
5440957b409SSimon J. Gerraty 			}
5450957b409SSimon J. Gerraty 			continue;
5460957b409SSimon J. Gerraty 		}
5470957b409SSimon J. Gerraty #else
5480957b409SSimon J. Gerraty 		if (sendrec || recvrec) {
5490957b409SSimon J. Gerraty 			pfd[u].fd = fd;
5500957b409SSimon J. Gerraty 			pfd[u].revents = 0;
5510957b409SSimon J. Gerraty 			pfd[u].events = 0;
5520957b409SSimon J. Gerraty 			if (sendrec) {
5530957b409SSimon J. Gerraty 				pfd[u].events |= POLLOUT;
5540957b409SSimon J. Gerraty 			}
5550957b409SSimon J. Gerraty 			if (recvrec) {
5560957b409SSimon J. Gerraty 				pfd[u].events |= POLLIN;
5570957b409SSimon J. Gerraty 			}
5580957b409SSimon J. Gerraty 			k_fd = u;
5590957b409SSimon J. Gerraty 			u ++;
5600957b409SSimon J. Gerraty 		}
5610957b409SSimon J. Gerraty 		if (sendapp) {
5620957b409SSimon J. Gerraty 			pfd[u].fd = 0;
5630957b409SSimon J. Gerraty 			pfd[u].revents = 0;
5640957b409SSimon J. Gerraty 			pfd[u].events = POLLIN;
5650957b409SSimon J. Gerraty 			k_in = u;
5660957b409SSimon J. Gerraty 			u ++;
5670957b409SSimon J. Gerraty 		}
5680957b409SSimon J. Gerraty 		if (recvapp) {
5690957b409SSimon J. Gerraty 			pfd[u].fd = 1;
5700957b409SSimon J. Gerraty 			pfd[u].revents = 0;
5710957b409SSimon J. Gerraty 			pfd[u].events = POLLOUT;
5720957b409SSimon J. Gerraty 			k_out = u;
5730957b409SSimon J. Gerraty 			u ++;
5740957b409SSimon J. Gerraty 		}
5750957b409SSimon J. Gerraty 		n = poll(pfd, u, -1);
5760957b409SSimon J. Gerraty 		if (n < 0) {
5770957b409SSimon J. Gerraty 			if (errno == EINTR) {
5780957b409SSimon J. Gerraty 				continue;
5790957b409SSimon J. Gerraty 			}
5800957b409SSimon J. Gerraty 			perror("ERROR: poll()");
5810957b409SSimon J. Gerraty 			retcode = -2;
5820957b409SSimon J. Gerraty 			goto engine_exit;
5830957b409SSimon J. Gerraty 		}
5840957b409SSimon J. Gerraty 		if (n == 0) {
5850957b409SSimon J. Gerraty 			continue;
5860957b409SSimon J. Gerraty 		}
5870957b409SSimon J. Gerraty 
5880957b409SSimon J. Gerraty 		/*
5890957b409SSimon J. Gerraty 		 * We transform closures/errors into read+write accesses
5900957b409SSimon J. Gerraty 		 * so as to force the read() or write() call that will
5910957b409SSimon J. Gerraty 		 * detect the situation.
5920957b409SSimon J. Gerraty 		 */
5930957b409SSimon J. Gerraty 		while (u -- > 0) {
5940957b409SSimon J. Gerraty 			if (pfd[u].revents & (POLLERR | POLLHUP)) {
5950957b409SSimon J. Gerraty 				pfd[u].revents |= POLLIN | POLLOUT;
5960957b409SSimon J. Gerraty 			}
5970957b409SSimon J. Gerraty 		}
5980957b409SSimon J. Gerraty 
5990957b409SSimon J. Gerraty 		recvapp_ok = recvapp && (pfd[k_out].revents & POLLOUT) != 0;
6000957b409SSimon J. Gerraty 		sendrec_ok = sendrec && (pfd[k_fd].revents & POLLOUT) != 0;
6010957b409SSimon J. Gerraty 		recvrec_ok = recvrec && (pfd[k_fd].revents & POLLIN) != 0;
6020957b409SSimon J. Gerraty 		sendapp_ok = sendapp && (pfd[k_in].revents & POLLIN) != 0;
6030957b409SSimon J. Gerraty #endif
6040957b409SSimon J. Gerraty 
6050957b409SSimon J. Gerraty 		/*
6060957b409SSimon J. Gerraty 		 * We give preference to outgoing data, on stdout and on
6070957b409SSimon J. Gerraty 		 * the socket.
6080957b409SSimon J. Gerraty 		 */
6090957b409SSimon J. Gerraty 		if (recvapp_ok) {
6100957b409SSimon J. Gerraty 			unsigned char *buf;
6110957b409SSimon J. Gerraty 			size_t len;
6120957b409SSimon J. Gerraty #ifdef _WIN32
6130957b409SSimon J. Gerraty 			DWORD wlen;
6140957b409SSimon J. Gerraty #else
6150957b409SSimon J. Gerraty 			ssize_t wlen;
6160957b409SSimon J. Gerraty #endif
6170957b409SSimon J. Gerraty 
6180957b409SSimon J. Gerraty 			buf = br_ssl_engine_recvapp_buf(cc, &len);
6190957b409SSimon J. Gerraty #ifdef _WIN32
6200957b409SSimon J. Gerraty 			if (!WriteFile(h_out, buf, len, &wlen, NULL)) {
6210957b409SSimon J. Gerraty 				if (verbose) {
6220957b409SSimon J. Gerraty 					fprintf(stderr, "stdout closed...\n");
6230957b409SSimon J. Gerraty 				}
6240957b409SSimon J. Gerraty 				retcode = -2;
6250957b409SSimon J. Gerraty 				goto engine_exit;
6260957b409SSimon J. Gerraty 			}
6270957b409SSimon J. Gerraty #else
6280957b409SSimon J. Gerraty 			wlen = write(1, buf, len);
6290957b409SSimon J. Gerraty 			if (wlen <= 0) {
6300957b409SSimon J. Gerraty 				if (verbose) {
6310957b409SSimon J. Gerraty 					fprintf(stderr, "stdout closed...\n");
6320957b409SSimon J. Gerraty 				}
6330957b409SSimon J. Gerraty 				retcode = -2;
6340957b409SSimon J. Gerraty 				goto engine_exit;
6350957b409SSimon J. Gerraty 			}
6360957b409SSimon J. Gerraty #endif
6370957b409SSimon J. Gerraty 			br_ssl_engine_recvapp_ack(cc, wlen);
6380957b409SSimon J. Gerraty 			continue;
6390957b409SSimon J. Gerraty 		}
6400957b409SSimon J. Gerraty 		if (sendrec_ok) {
6410957b409SSimon J. Gerraty 			unsigned char *buf;
6420957b409SSimon J. Gerraty 			size_t len;
6430957b409SSimon J. Gerraty 			int wlen;
6440957b409SSimon J. Gerraty 
6450957b409SSimon J. Gerraty 			buf = br_ssl_engine_sendrec_buf(cc, &len);
6460957b409SSimon J. Gerraty 			wlen = send(fd, buf, len, 0);
6470957b409SSimon J. Gerraty 			if (wlen <= 0) {
6480957b409SSimon J. Gerraty #ifdef _WIN32
6490957b409SSimon J. Gerraty 				int err;
6500957b409SSimon J. Gerraty 
6510957b409SSimon J. Gerraty 				err = WSAGetLastError();
6520957b409SSimon J. Gerraty 				if (err == EWOULDBLOCK
6530957b409SSimon J. Gerraty 					|| err == WSAEWOULDBLOCK)
6540957b409SSimon J. Gerraty 				{
6550957b409SSimon J. Gerraty 					can_send = 0;
6560957b409SSimon J. Gerraty 					continue;
6570957b409SSimon J. Gerraty 				}
6580957b409SSimon J. Gerraty #else
6590957b409SSimon J. Gerraty 				if (errno == EINTR || errno == EWOULDBLOCK) {
6600957b409SSimon J. Gerraty 					continue;
6610957b409SSimon J. Gerraty 				}
6620957b409SSimon J. Gerraty #endif
6630957b409SSimon J. Gerraty 				if (verbose) {
6640957b409SSimon J. Gerraty 					fprintf(stderr, "socket closed...\n");
6650957b409SSimon J. Gerraty 				}
6660957b409SSimon J. Gerraty 				retcode = -1;
6670957b409SSimon J. Gerraty 				goto engine_exit;
6680957b409SSimon J. Gerraty 			}
6690957b409SSimon J. Gerraty 			if (trace) {
6700957b409SSimon J. Gerraty 				dump_blob("Outgoing bytes", buf, wlen);
6710957b409SSimon J. Gerraty 			}
6720957b409SSimon J. Gerraty 			br_ssl_engine_sendrec_ack(cc, wlen);
6730957b409SSimon J. Gerraty 			continue;
6740957b409SSimon J. Gerraty 		}
6750957b409SSimon J. Gerraty 		if (recvrec_ok) {
6760957b409SSimon J. Gerraty 			unsigned char *buf;
6770957b409SSimon J. Gerraty 			size_t len;
6780957b409SSimon J. Gerraty 			int rlen;
6790957b409SSimon J. Gerraty 
6800957b409SSimon J. Gerraty 			buf = br_ssl_engine_recvrec_buf(cc, &len);
6810957b409SSimon J. Gerraty 			rlen = recv(fd, buf, len, 0);
6820957b409SSimon J. Gerraty 			if (rlen == 0) {
6830957b409SSimon J. Gerraty 				if (verbose) {
6840957b409SSimon J. Gerraty 					fprintf(stderr, "socket closed...\n");
6850957b409SSimon J. Gerraty 				}
6860957b409SSimon J. Gerraty 				retcode = -1;
6870957b409SSimon J. Gerraty 				goto engine_exit;
6880957b409SSimon J. Gerraty 			}
6890957b409SSimon J. Gerraty 			if (rlen < 0) {
6900957b409SSimon J. Gerraty #ifdef _WIN32
6910957b409SSimon J. Gerraty 				int err;
6920957b409SSimon J. Gerraty 
6930957b409SSimon J. Gerraty 				err = WSAGetLastError();
6940957b409SSimon J. Gerraty 				if (err == EWOULDBLOCK
6950957b409SSimon J. Gerraty 					|| err == WSAEWOULDBLOCK)
6960957b409SSimon J. Gerraty 				{
6970957b409SSimon J. Gerraty 					can_recv = 0;
6980957b409SSimon J. Gerraty 					continue;
6990957b409SSimon J. Gerraty 				}
7000957b409SSimon J. Gerraty #else
7010957b409SSimon J. Gerraty 				if (errno == EINTR || errno == EWOULDBLOCK) {
7020957b409SSimon J. Gerraty 					continue;
7030957b409SSimon J. Gerraty 				}
7040957b409SSimon J. Gerraty #endif
7050957b409SSimon J. Gerraty 				if (verbose) {
7060957b409SSimon J. Gerraty 					fprintf(stderr, "socket broke...\n");
7070957b409SSimon J. Gerraty 				}
7080957b409SSimon J. Gerraty 				retcode = -1;
7090957b409SSimon J. Gerraty 				goto engine_exit;
7100957b409SSimon J. Gerraty 			}
7110957b409SSimon J. Gerraty 			if (trace) {
7120957b409SSimon J. Gerraty 				dump_blob("Incoming bytes", buf, rlen);
7130957b409SSimon J. Gerraty 			}
7140957b409SSimon J. Gerraty 			br_ssl_engine_recvrec_ack(cc, rlen);
7150957b409SSimon J. Gerraty 			continue;
7160957b409SSimon J. Gerraty 		}
7170957b409SSimon J. Gerraty 		if (sendapp_ok) {
7180957b409SSimon J. Gerraty 			unsigned char *buf;
7190957b409SSimon J. Gerraty 			size_t len;
7200957b409SSimon J. Gerraty #ifdef _WIN32
7210957b409SSimon J. Gerraty 			int rlen;
7220957b409SSimon J. Gerraty #else
7230957b409SSimon J. Gerraty 			ssize_t rlen;
7240957b409SSimon J. Gerraty #endif
7250957b409SSimon J. Gerraty 
7260957b409SSimon J. Gerraty 			buf = br_ssl_engine_sendapp_buf(cc, &len);
7270957b409SSimon J. Gerraty #ifdef _WIN32
7280957b409SSimon J. Gerraty 			rlen = in_read_buffered(h_in, &bb, buf, len);
7290957b409SSimon J. Gerraty #else
7300957b409SSimon J. Gerraty 			rlen = read(0, buf, len);
7310957b409SSimon J. Gerraty #endif
7320957b409SSimon J. Gerraty 			if (rlen <= 0) {
7330957b409SSimon J. Gerraty 				if (verbose) {
7340957b409SSimon J. Gerraty 					fprintf(stderr, "stdin closed...\n");
7350957b409SSimon J. Gerraty 				}
7360957b409SSimon J. Gerraty 				br_ssl_engine_close(cc);
7370957b409SSimon J. Gerraty 			} else if (!run_command(cc, buf, rlen)) {
7380957b409SSimon J. Gerraty 				br_ssl_engine_sendapp_ack(cc, rlen);
7390957b409SSimon J. Gerraty 			}
7400957b409SSimon J. Gerraty 			br_ssl_engine_flush(cc, 0);
7410957b409SSimon J. Gerraty 			continue;
7420957b409SSimon J. Gerraty 		}
7430957b409SSimon J. Gerraty 
7440957b409SSimon J. Gerraty 		/* We should never reach that point. */
7450957b409SSimon J. Gerraty 		fprintf(stderr, "ERROR: poll() misbehaves\n");
7460957b409SSimon J. Gerraty 		retcode = -2;
7470957b409SSimon J. Gerraty 		goto engine_exit;
7480957b409SSimon J. Gerraty 	}
7490957b409SSimon J. Gerraty 
7500957b409SSimon J. Gerraty 	/*
7510957b409SSimon J. Gerraty 	 * Release allocated structures.
7520957b409SSimon J. Gerraty 	 */
7530957b409SSimon J. Gerraty engine_exit:
7540957b409SSimon J. Gerraty #ifdef _WIN32
7550957b409SSimon J. Gerraty 	if (fd_event != WSA_INVALID_EVENT) {
7560957b409SSimon J. Gerraty 		WSACloseEvent(fd_event);
7570957b409SSimon J. Gerraty 	}
7580957b409SSimon J. Gerraty #endif
7590957b409SSimon J. Gerraty 	return retcode;
7600957b409SSimon J. Gerraty }
761