xref: /freebsd/contrib/bearssl/tools/sslio.c (revision 0957b409a90fd597c1e9124cbaf3edd2b488f4ac)
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