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