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