From 854f4f69af9003c0c29d3838001f549beaf36936 Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Sat, 12 Sep 2015 07:48:06 -0500 Subject: add 'nc' to the distribution as an example of libtls client and server --- apps/CMakeLists.txt | 108 ++++++------ apps/Makefile.am | 116 +------------ apps/apps_win.c | 29 ---- apps/certhash_disabled.c | 13 -- apps/nc/Makefile.am | 11 ++ apps/openssl/Makefile.am | 116 +++++++++++++ apps/openssl/compat/apps_win.c | 29 ++++ apps/openssl/compat/certhash_win.c | 13 ++ apps/openssl/compat/poll_win.c | 327 +++++++++++++++++++++++++++++++++++++ apps/poll_win.c | 327 ------------------------------------- 10 files changed, 552 insertions(+), 537 deletions(-) delete mode 100644 apps/apps_win.c delete mode 100644 apps/certhash_disabled.c create mode 100644 apps/nc/Makefile.am create mode 100644 apps/openssl/Makefile.am create mode 100644 apps/openssl/compat/apps_win.c create mode 100644 apps/openssl/compat/certhash_win.c create mode 100644 apps/openssl/compat/poll_win.c delete mode 100644 apps/poll_win.c (limited to 'apps') diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index ee1880d..8c49c9b 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -6,72 +6,72 @@ include_directories( set( OPENSSL_SRC - apps.c - asn1pars.c - ca.c - ciphers.c - cms.c - crl.c - crl2p7.c - dgst.c - dh.c - dhparam.c - dsa.c - dsaparam.c - ec.c - ecparam.c - enc.c - errstr.c - gendh.c - gendsa.c - genpkey.c - genrsa.c - nseq.c - ocsp.c - openssl.c - passwd.c - pkcs12.c - pkcs7.c - pkcs8.c - pkey.c - pkeyparam.c - pkeyutl.c - prime.c - rand.c - req.c - rsa.c - rsautl.c - s_cb.c - s_client.c - s_server.c - s_socket.c - s_time.c - sess_id.c - smime.c - speed.c - spkac.c - ts.c - verify.c - version.c - x509.c + openssl/apps.c + openssl/asn1pars.c + openssl/ca.c + openssl/ciphers.c + openssl/cms.c + openssl/crl.c + openssl/crl2p7.c + openssl/dgst.c + openssl/dh.c + openssl/dhparam.c + openssl/dsa.c + openssl/dsaparam.c + openssl/ec.c + openssl/ecparam.c + openssl/enc.c + openssl/errstr.c + openssl/gendh.c + openssl/gendsa.c + openssl/genpkey.c + openssl/genrsa.c + openssl/nseq.c + openssl/ocsp.c + openssl/openssl.c + openssl/passwd.c + openssl/pkcs12.c + openssl/pkcs7.c + openssl/pkcs8.c + openssl/pkey.c + openssl/pkeyparam.c + openssl/pkeyutl.c + openssl/prime.c + openssl/rand.c + openssl/req.c + openssl/rsa.c + openssl/rsautl.c + openssl/s_cb.c + openssl/s_client.c + openssl/s_server.c + openssl/s_socket.c + openssl/s_time.c + openssl/sess_id.c + openssl/smime.c + openssl/speed.c + openssl/spkac.c + openssl/ts.c + openssl/verify.c + openssl/version.c + openssl/x509.c ) if(CMAKE_HOST_UNIX) - set(OPENSSL_SRC ${OPENSSL_SRC} apps_posix.c) - set(OPENSSL_SRC ${OPENSSL_SRC} certhash.c) + set(OPENSSL_SRC ${OPENSSL_SRC} openssl/apps_posix.c) + set(OPENSSL_SRC ${OPENSSL_SRC} openssl/certhash.c) endif() if(CMAKE_HOST_WIN32) - set(OPENSSL_SRC ${OPENSSL_SRC} apps_win.c) - set(OPENSSL_SRC ${OPENSSL_SRC} certhash_disabled.c) - set(OPENSSL_SRC ${OPENSSL_SRC} poll_win.c) + set(OPENSSL_SRC ${OPENSSL_SRC} openssl/compat/apps_win.c) + set(OPENSSL_SRC ${OPENSSL_SRC} openssl/compat/hash_win.c) + set(OPENSSL_SRC ${OPENSSL_SRC} openssl/compat/poll_win.c) endif() check_function_exists(strtonum HAVE_STRTONUM) if(HAVE_STRTONUM) add_definitions(-DHAVE_STRTONUM) else() - set(OPENSSL_SRC ${OPENSSL_SRC} strtonum.c) + set(OPENSSL_SRC ${OPENSSL_SRC} openssl/compat/strtonum.c) endif() add_executable(openssl ${OPENSSL_SRC}) diff --git a/apps/Makefile.am b/apps/Makefile.am index 20cf586..60d0c60 100644 --- a/apps/Makefile.am +++ b/apps/Makefile.am @@ -1,117 +1,5 @@ include $(top_srcdir)/Makefile.am.common -bin_PROGRAMS = openssl +SUBDIRS = openssl nc -openssl_LDADD = $(PLATFORM_LDADD) $(PROG_LDADD) -openssl_LDADD += $(top_builddir)/ssl/libssl.la -openssl_LDADD += $(top_builddir)/crypto/libcrypto.la - -openssl_SOURCES = apps.c -openssl_SOURCES += asn1pars.c -openssl_SOURCES += ca.c -openssl_SOURCES += ciphers.c -openssl_SOURCES += cms.c -openssl_SOURCES += crl.c -openssl_SOURCES += crl2p7.c -openssl_SOURCES += dgst.c -openssl_SOURCES += dh.c -openssl_SOURCES += dhparam.c -openssl_SOURCES += dsa.c -openssl_SOURCES += dsaparam.c -openssl_SOURCES += ec.c -openssl_SOURCES += ecparam.c -openssl_SOURCES += enc.c -openssl_SOURCES += errstr.c -openssl_SOURCES += gendh.c -openssl_SOURCES += gendsa.c -openssl_SOURCES += genpkey.c -openssl_SOURCES += genrsa.c -openssl_SOURCES += nseq.c -openssl_SOURCES += ocsp.c -openssl_SOURCES += openssl.c -openssl_SOURCES += passwd.c -openssl_SOURCES += pkcs12.c -openssl_SOURCES += pkcs7.c -openssl_SOURCES += pkcs8.c -openssl_SOURCES += pkey.c -openssl_SOURCES += pkeyparam.c -openssl_SOURCES += pkeyutl.c -openssl_SOURCES += prime.c -openssl_SOURCES += rand.c -openssl_SOURCES += req.c -openssl_SOURCES += rsa.c -openssl_SOURCES += rsautl.c -openssl_SOURCES += s_cb.c -openssl_SOURCES += s_client.c -openssl_SOURCES += s_server.c -openssl_SOURCES += s_socket.c -openssl_SOURCES += s_time.c -openssl_SOURCES += sess_id.c -openssl_SOURCES += smime.c -openssl_SOURCES += speed.c -openssl_SOURCES += spkac.c -openssl_SOURCES += ts.c -openssl_SOURCES += verify.c -openssl_SOURCES += version.c -openssl_SOURCES += x509.c - -if BUILD_CERTHASH -openssl_SOURCES += certhash.c -else -openssl_SOURCES += certhash_disabled.c -endif - -if HOST_WIN -openssl_SOURCES += apps_win.c -else -openssl_SOURCES += apps_posix.c -endif - -if !HAVE_POLL -if HOST_WIN -openssl_SOURCES += poll_win.c -endif -endif - -if !HAVE_STRTONUM -openssl_SOURCES += strtonum.c -endif - -noinst_HEADERS = apps.h -noinst_HEADERS += progs.h -noinst_HEADERS += s_apps.h -noinst_HEADERS += testdsa.h -noinst_HEADERS += testrsa.h -noinst_HEADERS += timeouts.h - -EXTRA_DIST = cert.pem -EXTRA_DIST += openssl.cnf -EXTRA_DIST += x509v3.cnf -EXTRA_DIST += CMakeLists.txt - -install-exec-hook: - @if [ "@OPENSSLDIR@x" != "x" ]; then \ - OPENSSLDIR="$(DESTDIR)/@OPENSSLDIR@"; \ - else \ - OPENSSLDIR="$(DESTDIR)/$(sysconfdir)/ssl"; \ - fi; \ - mkdir -p "$$OPENSSLDIR/certs"; \ - for i in cert.pem openssl.cnf x509v3.cnf; do \ - if [ ! -f "$$OPENSSLDIR/$i" ]; then \ - $(INSTALL) -m 644 "$(srcdir)/$$i" "$$OPENSSLDIR/$$i"; \ - else \ - echo " $$OPENSSLDIR/$$i already exists, install will not overwrite"; \ - fi \ - done - -uninstall-local: - @if [ "@OPENSSLDIR@x" != "x" ]; then \ - OPENSSLDIR="$(DESTDIR)/@OPENSSLDIR@"; \ - else \ - OPENSSLDIR="$(DESTDIR)/$(sysconfdir)/ssl"; \ - fi; \ - for i in cert.pem openssl.cnf x509v3.cnf; do \ - if cmp -s "$$OPENSSLDIR/$$i" "$(srcdir)/$$i"; then \ - rm -f "$$OPENSSLDIR/$$i"; \ - fi \ - done +EXTRA_DIST = CMakeLists.txt diff --git a/apps/apps_win.c b/apps/apps_win.c deleted file mode 100644 index 496ac03..0000000 --- a/apps/apps_win.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Public domain - * - * Dongsheng Song - * Brent Cook - */ - -#include - -#include "apps.h" - -double -app_tminterval(int stop, int usertime) -{ - static unsigned __int64 tmstart; - union { - unsigned __int64 u64; - FILETIME ft; - } ct, et, kt, ut; - - GetProcessTimes(GetCurrentProcess(), &ct.ft, &et.ft, &kt.ft, &ut.ft); - - if (stop == TM_START) { - tmstart = ut.u64 + kt.u64; - } else { - return (ut.u64 + kt.u64 - tmstart) / (double) 10000000; - } - return 0; -} diff --git a/apps/certhash_disabled.c b/apps/certhash_disabled.c deleted file mode 100644 index 8238ff7..0000000 --- a/apps/certhash_disabled.c +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Public domain - * certhash dummy implementation for platforms without symlinks - */ - -#include "apps.h" - -int -certhash_main(int argc, char **argv) -{ - fprintf(stderr, "certhash is not enabled on this platform\n"); - return (1); -} diff --git a/apps/nc/Makefile.am b/apps/nc/Makefile.am new file mode 100644 index 0000000..ccb770a --- /dev/null +++ b/apps/nc/Makefile.am @@ -0,0 +1,11 @@ +include $(top_srcdir)/Makefile.am.common + +bin_PROGRAMS = nc + +nc_LDADD = $(PLATFORM_LDADD) $(PROG_LDADD) +nc_LDADD += $(top_builddir)/tls/libtls.la + +nc_SOURCES = atomicio.c +nc_SOURCES += netcat.c +nc_SOURCES += socks.c +noinst_HEADERS = atomicio.h diff --git a/apps/openssl/Makefile.am b/apps/openssl/Makefile.am new file mode 100644 index 0000000..9c763e1 --- /dev/null +++ b/apps/openssl/Makefile.am @@ -0,0 +1,116 @@ +include $(top_srcdir)/Makefile.am.common + +bin_PROGRAMS = openssl + +openssl_LDADD = $(PLATFORM_LDADD) $(PROG_LDADD) +openssl_LDADD += $(top_builddir)/ssl/libssl.la +openssl_LDADD += $(top_builddir)/crypto/libcrypto.la + +openssl_SOURCES = apps.c +openssl_SOURCES += asn1pars.c +openssl_SOURCES += ca.c +openssl_SOURCES += ciphers.c +openssl_SOURCES += cms.c +openssl_SOURCES += crl.c +openssl_SOURCES += crl2p7.c +openssl_SOURCES += dgst.c +openssl_SOURCES += dh.c +openssl_SOURCES += dhparam.c +openssl_SOURCES += dsa.c +openssl_SOURCES += dsaparam.c +openssl_SOURCES += ec.c +openssl_SOURCES += ecparam.c +openssl_SOURCES += enc.c +openssl_SOURCES += errstr.c +openssl_SOURCES += gendh.c +openssl_SOURCES += gendsa.c +openssl_SOURCES += genpkey.c +openssl_SOURCES += genrsa.c +openssl_SOURCES += nseq.c +openssl_SOURCES += ocsp.c +openssl_SOURCES += openssl.c +openssl_SOURCES += passwd.c +openssl_SOURCES += pkcs12.c +openssl_SOURCES += pkcs7.c +openssl_SOURCES += pkcs8.c +openssl_SOURCES += pkey.c +openssl_SOURCES += pkeyparam.c +openssl_SOURCES += pkeyutl.c +openssl_SOURCES += prime.c +openssl_SOURCES += rand.c +openssl_SOURCES += req.c +openssl_SOURCES += rsa.c +openssl_SOURCES += rsautl.c +openssl_SOURCES += s_cb.c +openssl_SOURCES += s_client.c +openssl_SOURCES += s_server.c +openssl_SOURCES += s_socket.c +openssl_SOURCES += s_time.c +openssl_SOURCES += sess_id.c +openssl_SOURCES += smime.c +openssl_SOURCES += speed.c +openssl_SOURCES += spkac.c +openssl_SOURCES += ts.c +openssl_SOURCES += verify.c +openssl_SOURCES += version.c +openssl_SOURCES += x509.c + +if BUILD_CERTHASH +openssl_SOURCES += certhash.c +else +openssl_SOURCES += compat/certhash_win.c +endif + +if HOST_WIN +openssl_SOURCES += compat/apps_win.c +else +openssl_SOURCES += apps_posix.c +endif + +if !HAVE_POLL +if HOST_WIN +openssl_SOURCES += compat/poll_win.c +endif +endif + +if !HAVE_STRTONUM +openssl_SOURCES += compat/strtonum.c +endif + +noinst_HEADERS = apps.h +noinst_HEADERS += progs.h +noinst_HEADERS += s_apps.h +noinst_HEADERS += testdsa.h +noinst_HEADERS += testrsa.h +noinst_HEADERS += timeouts.h + +EXTRA_DIST = cert.pem +EXTRA_DIST += openssl.cnf +EXTRA_DIST += x509v3.cnf + +install-exec-hook: + @if [ "@OPENSSLDIR@x" != "x" ]; then \ + OPENSSLDIR="$(DESTDIR)/@OPENSSLDIR@"; \ + else \ + OPENSSLDIR="$(DESTDIR)/$(sysconfdir)/ssl"; \ + fi; \ + mkdir -p "$$OPENSSLDIR/certs"; \ + for i in cert.pem openssl.cnf x509v3.cnf; do \ + if [ ! -f "$$OPENSSLDIR/$i" ]; then \ + $(INSTALL) -m 644 "$(srcdir)/$$i" "$$OPENSSLDIR/$$i"; \ + else \ + echo " $$OPENSSLDIR/$$i already exists, install will not overwrite"; \ + fi \ + done + +uninstall-local: + @if [ "@OPENSSLDIR@x" != "x" ]; then \ + OPENSSLDIR="$(DESTDIR)/@OPENSSLDIR@"; \ + else \ + OPENSSLDIR="$(DESTDIR)/$(sysconfdir)/ssl"; \ + fi; \ + for i in cert.pem openssl.cnf x509v3.cnf; do \ + if cmp -s "$$OPENSSLDIR/$$i" "$(srcdir)/$$i"; then \ + rm -f "$$OPENSSLDIR/$$i"; \ + fi \ + done diff --git a/apps/openssl/compat/apps_win.c b/apps/openssl/compat/apps_win.c new file mode 100644 index 0000000..496ac03 --- /dev/null +++ b/apps/openssl/compat/apps_win.c @@ -0,0 +1,29 @@ +/* + * Public domain + * + * Dongsheng Song + * Brent Cook + */ + +#include + +#include "apps.h" + +double +app_tminterval(int stop, int usertime) +{ + static unsigned __int64 tmstart; + union { + unsigned __int64 u64; + FILETIME ft; + } ct, et, kt, ut; + + GetProcessTimes(GetCurrentProcess(), &ct.ft, &et.ft, &kt.ft, &ut.ft); + + if (stop == TM_START) { + tmstart = ut.u64 + kt.u64; + } else { + return (ut.u64 + kt.u64 - tmstart) / (double) 10000000; + } + return 0; +} diff --git a/apps/openssl/compat/certhash_win.c b/apps/openssl/compat/certhash_win.c new file mode 100644 index 0000000..8238ff7 --- /dev/null +++ b/apps/openssl/compat/certhash_win.c @@ -0,0 +1,13 @@ +/* + * Public domain + * certhash dummy implementation for platforms without symlinks + */ + +#include "apps.h" + +int +certhash_main(int argc, char **argv) +{ + fprintf(stderr, "certhash is not enabled on this platform\n"); + return (1); +} diff --git a/apps/openssl/compat/poll_win.c b/apps/openssl/compat/poll_win.c new file mode 100644 index 0000000..ce47b01 --- /dev/null +++ b/apps/openssl/compat/poll_win.c @@ -0,0 +1,327 @@ +/* + * Public domain + * + * poll(2) emulation for Windows + * + * This emulates just-enough poll functionality on Windows to work in the + * context of the openssl(1) program. This is not a replacement for + * POSIX.1-2001 poll(2), though it may come closer than I care to admit. + * + * Dongsheng Song + * Brent Cook + */ + +#include +#include +#include +#include +#include + +static int +conn_is_closed(int fd) +{ + char buf[1]; + int ret = recv(fd, buf, 1, MSG_PEEK); + if (ret == -1) { + switch (WSAGetLastError()) { + case WSAECONNABORTED: + case WSAECONNRESET: + case WSAENETRESET: + case WSAESHUTDOWN: + return 1; + } + } + return 0; +} + +static int +conn_has_oob_data(int fd) +{ + char buf[1]; + return (recv(fd, buf, 1, MSG_PEEK | MSG_OOB) == 1); +} + +static int +is_socket(int fd) +{ + if (fd < 3) + return 0; + WSANETWORKEVENTS events; + return (WSAEnumNetworkEvents((SOCKET)fd, NULL, &events) == 0); +} + +static int +compute_select_revents(int fd, short events, + fd_set *rfds, fd_set *wfds, fd_set *efds) +{ + int rc = 0; + + if ((events & (POLLIN | POLLRDNORM | POLLRDBAND)) && + FD_ISSET(fd, rfds)) { + if (conn_is_closed(fd)) + rc |= POLLHUP; + else + rc |= POLLIN | POLLRDNORM; + } + + if ((events & (POLLOUT | POLLWRNORM | POLLWRBAND)) && + FD_ISSET(fd, wfds)) + rc |= POLLOUT; + + if (FD_ISSET(fd, efds)) { + if (conn_is_closed(fd)) + rc |= POLLHUP; + else if (conn_has_oob_data(fd)) + rc |= POLLRDBAND | POLLPRI; + } + + return rc; +} + +static int +compute_wait_revents(HANDLE h, short events, int object, int wait_rc) +{ + int rc = 0; + INPUT_RECORD record; + DWORD num_read; + + /* + * Assume we can always write to file handles (probably a bad + * assumption but works for now, at least it doesn't block). + */ + if (events & (POLLOUT | POLLWRNORM)) + rc |= POLLOUT; + + /* + * Check if this handle was signaled by WaitForMultipleObjects + */ + if (wait_rc >= WAIT_OBJECT_0 && (object == (wait_rc - WAIT_OBJECT_0)) + && (events & (POLLIN | POLLRDNORM))) { + + /* + * Check if this file is stdin, and if so, if it is a console. + */ + if (h == GetStdHandle(STD_INPUT_HANDLE) && + PeekConsoleInput(h, &record, 1, &num_read) == 1) { + + /* + * Handle the input console buffer differently, + * since it can signal on other events like + * window and mouse, but read can still block. + */ + if (record.EventType == KEY_EVENT && + record.Event.KeyEvent.bKeyDown) { + rc |= POLLIN; + } else { + /* + * Flush non-character events from the + * console buffer. + */ + ReadConsoleInput(h, &record, 1, &num_read); + } + } else { + rc |= POLLIN; + } + } + + return rc; +} + +static int +wsa_select_errno(int err) +{ + switch (err) { + case WSAEINTR: + case WSAEINPROGRESS: + errno = EINTR; + break; + case WSAEFAULT: + /* + * Windows uses WSAEFAULT for both resource allocation failures + * and arguments not being contained in the user's address + * space. So, we have to choose EFAULT or ENOMEM. + */ + errno = EFAULT; + break; + case WSAEINVAL: + errno = EINVAL; + break; + case WSANOTINITIALISED: + errno = EPERM; + break; + case WSAENETDOWN: + errno = ENOMEM; + break; + } + return -1; +} + +int +poll(struct pollfd *pfds, nfds_t nfds, int timeout_ms) +{ + nfds_t i; + int timespent_ms, looptime_ms; + + /* + * select machinery + */ + fd_set rfds, wfds, efds; + int rc; + int num_sockets; + + /* + * wait machinery + */ + DWORD wait_rc; + HANDLE handles[FD_SETSIZE]; + int num_handles; + + if (pfds == NULL) { + errno = EINVAL; + return -1; + } + + if (nfds <= 0) { + return 0; + } + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&efds); + num_sockets = 0; + num_handles = 0; + + for (i = 0; i < nfds; i++) { + if ((int)pfds[i].fd < 0) + continue; + + if (is_socket(pfds[i].fd)) { + if (num_sockets >= FD_SETSIZE) { + errno = EINVAL; + return -1; + } + + FD_SET(pfds[i].fd, &efds); + + if (pfds[i].events & + (POLLIN | POLLRDNORM | POLLRDBAND)) { + FD_SET(pfds[i].fd, &rfds); + } + + if (pfds[i].events & + (POLLOUT | POLLWRNORM | POLLWRBAND)) { + FD_SET(pfds[i].fd, &wfds); + } + num_sockets++; + + } else { + if (num_handles >= FD_SETSIZE) { + errno = EINVAL; + return -1; + } + + handles[num_handles++] = + (HANDLE)_get_osfhandle(pfds[i].fd); + } + } + + /* + * Determine if the files, pipes, sockets, consoles, etc. have signaled. + * + * Do this by alternating a loop between WaitForMultipleObjects for + * non-sockets and and select for sockets. + * + * I tried to implement this all in terms of WaitForMultipleObjects + * with a select-based 'poll' of the sockets at the end to get extra + * specific socket status. + * + * However, the cost of setting up an event handle for each socket and + * cleaning them up reliably was pretty high. Since the event handle + * associated with a socket is also global, creating a new one here + * cancels one that may exist externally to this function. + * + * At any rate, even if global socket event handles were not an issue, + * the 'FD_WRITE' status of a socket event handle does not behave in an + * expected fashion, being triggered by an edge on a write buffer rather + * than simply triggering if there is space available. + */ + timespent_ms = 0; + wait_rc = WAIT_FAILED; + + if (timeout_ms < 0) + timeout_ms = INFINITE; + looptime_ms = timeout_ms > 100 ? 100 : timeout_ms; + + do { + struct timeval tv = {0, looptime_ms * 1000}; + int handle_signaled = 0; + + /* + * Check if any file handles have signaled + */ + if (num_handles) { + wait_rc = WaitForMultipleObjects(num_handles, handles, + FALSE, 0); + if (wait_rc == WAIT_FAILED) { + /* + * The documentation for WaitForMultipleObjects + * does not specify what values GetLastError + * may return here. Rather than enumerate + * badness like for wsa_select_errno, assume a + * general errno value. + */ + errno = ENOMEM; + return 0; + } + } + + /* + * If we signaled on a file handle, don't wait on the sockets. + */ + if (wait_rc >= WAIT_OBJECT_0 && + (wait_rc <= WAIT_OBJECT_0 + num_handles - 1)) { + tv.tv_usec = 0; + handle_signaled = 1; + } + + /* + * Check if any sockets have signaled + */ + rc = select(0, &rfds, &wfds, &efds, &tv); + if (!handle_signaled && rc == SOCKET_ERROR) + return wsa_select_errno(WSAGetLastError()); + + if (handle_signaled || (num_sockets && rc > 0)) + break; + + timespent_ms += looptime_ms; + + } while (timespent_ms < timeout_ms); + + rc = 0; + num_handles = 0; + for (i = 0; i < nfds; i++) { + pfds[i].revents = 0; + + if ((int)pfds[i].fd < 0) + continue; + + if (is_socket(pfds[i].fd)) { + + pfds[i].revents = compute_select_revents(pfds[i].fd, + pfds[i].events, &rfds, &wfds, &efds); + + } else { + pfds[i].revents = compute_wait_revents( + handles[num_handles], pfds[i].events, num_handles, + wait_rc); + num_handles++; + } + + if (pfds[i].revents) + rc++; + } + + return rc; +} + diff --git a/apps/poll_win.c b/apps/poll_win.c deleted file mode 100644 index ce47b01..0000000 --- a/apps/poll_win.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Public domain - * - * poll(2) emulation for Windows - * - * This emulates just-enough poll functionality on Windows to work in the - * context of the openssl(1) program. This is not a replacement for - * POSIX.1-2001 poll(2), though it may come closer than I care to admit. - * - * Dongsheng Song - * Brent Cook - */ - -#include -#include -#include -#include -#include - -static int -conn_is_closed(int fd) -{ - char buf[1]; - int ret = recv(fd, buf, 1, MSG_PEEK); - if (ret == -1) { - switch (WSAGetLastError()) { - case WSAECONNABORTED: - case WSAECONNRESET: - case WSAENETRESET: - case WSAESHUTDOWN: - return 1; - } - } - return 0; -} - -static int -conn_has_oob_data(int fd) -{ - char buf[1]; - return (recv(fd, buf, 1, MSG_PEEK | MSG_OOB) == 1); -} - -static int -is_socket(int fd) -{ - if (fd < 3) - return 0; - WSANETWORKEVENTS events; - return (WSAEnumNetworkEvents((SOCKET)fd, NULL, &events) == 0); -} - -static int -compute_select_revents(int fd, short events, - fd_set *rfds, fd_set *wfds, fd_set *efds) -{ - int rc = 0; - - if ((events & (POLLIN | POLLRDNORM | POLLRDBAND)) && - FD_ISSET(fd, rfds)) { - if (conn_is_closed(fd)) - rc |= POLLHUP; - else - rc |= POLLIN | POLLRDNORM; - } - - if ((events & (POLLOUT | POLLWRNORM | POLLWRBAND)) && - FD_ISSET(fd, wfds)) - rc |= POLLOUT; - - if (FD_ISSET(fd, efds)) { - if (conn_is_closed(fd)) - rc |= POLLHUP; - else if (conn_has_oob_data(fd)) - rc |= POLLRDBAND | POLLPRI; - } - - return rc; -} - -static int -compute_wait_revents(HANDLE h, short events, int object, int wait_rc) -{ - int rc = 0; - INPUT_RECORD record; - DWORD num_read; - - /* - * Assume we can always write to file handles (probably a bad - * assumption but works for now, at least it doesn't block). - */ - if (events & (POLLOUT | POLLWRNORM)) - rc |= POLLOUT; - - /* - * Check if this handle was signaled by WaitForMultipleObjects - */ - if (wait_rc >= WAIT_OBJECT_0 && (object == (wait_rc - WAIT_OBJECT_0)) - && (events & (POLLIN | POLLRDNORM))) { - - /* - * Check if this file is stdin, and if so, if it is a console. - */ - if (h == GetStdHandle(STD_INPUT_HANDLE) && - PeekConsoleInput(h, &record, 1, &num_read) == 1) { - - /* - * Handle the input console buffer differently, - * since it can signal on other events like - * window and mouse, but read can still block. - */ - if (record.EventType == KEY_EVENT && - record.Event.KeyEvent.bKeyDown) { - rc |= POLLIN; - } else { - /* - * Flush non-character events from the - * console buffer. - */ - ReadConsoleInput(h, &record, 1, &num_read); - } - } else { - rc |= POLLIN; - } - } - - return rc; -} - -static int -wsa_select_errno(int err) -{ - switch (err) { - case WSAEINTR: - case WSAEINPROGRESS: - errno = EINTR; - break; - case WSAEFAULT: - /* - * Windows uses WSAEFAULT for both resource allocation failures - * and arguments not being contained in the user's address - * space. So, we have to choose EFAULT or ENOMEM. - */ - errno = EFAULT; - break; - case WSAEINVAL: - errno = EINVAL; - break; - case WSANOTINITIALISED: - errno = EPERM; - break; - case WSAENETDOWN: - errno = ENOMEM; - break; - } - return -1; -} - -int -poll(struct pollfd *pfds, nfds_t nfds, int timeout_ms) -{ - nfds_t i; - int timespent_ms, looptime_ms; - - /* - * select machinery - */ - fd_set rfds, wfds, efds; - int rc; - int num_sockets; - - /* - * wait machinery - */ - DWORD wait_rc; - HANDLE handles[FD_SETSIZE]; - int num_handles; - - if (pfds == NULL) { - errno = EINVAL; - return -1; - } - - if (nfds <= 0) { - return 0; - } - - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_ZERO(&efds); - num_sockets = 0; - num_handles = 0; - - for (i = 0; i < nfds; i++) { - if ((int)pfds[i].fd < 0) - continue; - - if (is_socket(pfds[i].fd)) { - if (num_sockets >= FD_SETSIZE) { - errno = EINVAL; - return -1; - } - - FD_SET(pfds[i].fd, &efds); - - if (pfds[i].events & - (POLLIN | POLLRDNORM | POLLRDBAND)) { - FD_SET(pfds[i].fd, &rfds); - } - - if (pfds[i].events & - (POLLOUT | POLLWRNORM | POLLWRBAND)) { - FD_SET(pfds[i].fd, &wfds); - } - num_sockets++; - - } else { - if (num_handles >= FD_SETSIZE) { - errno = EINVAL; - return -1; - } - - handles[num_handles++] = - (HANDLE)_get_osfhandle(pfds[i].fd); - } - } - - /* - * Determine if the files, pipes, sockets, consoles, etc. have signaled. - * - * Do this by alternating a loop between WaitForMultipleObjects for - * non-sockets and and select for sockets. - * - * I tried to implement this all in terms of WaitForMultipleObjects - * with a select-based 'poll' of the sockets at the end to get extra - * specific socket status. - * - * However, the cost of setting up an event handle for each socket and - * cleaning them up reliably was pretty high. Since the event handle - * associated with a socket is also global, creating a new one here - * cancels one that may exist externally to this function. - * - * At any rate, even if global socket event handles were not an issue, - * the 'FD_WRITE' status of a socket event handle does not behave in an - * expected fashion, being triggered by an edge on a write buffer rather - * than simply triggering if there is space available. - */ - timespent_ms = 0; - wait_rc = WAIT_FAILED; - - if (timeout_ms < 0) - timeout_ms = INFINITE; - looptime_ms = timeout_ms > 100 ? 100 : timeout_ms; - - do { - struct timeval tv = {0, looptime_ms * 1000}; - int handle_signaled = 0; - - /* - * Check if any file handles have signaled - */ - if (num_handles) { - wait_rc = WaitForMultipleObjects(num_handles, handles, - FALSE, 0); - if (wait_rc == WAIT_FAILED) { - /* - * The documentation for WaitForMultipleObjects - * does not specify what values GetLastError - * may return here. Rather than enumerate - * badness like for wsa_select_errno, assume a - * general errno value. - */ - errno = ENOMEM; - return 0; - } - } - - /* - * If we signaled on a file handle, don't wait on the sockets. - */ - if (wait_rc >= WAIT_OBJECT_0 && - (wait_rc <= WAIT_OBJECT_0 + num_handles - 1)) { - tv.tv_usec = 0; - handle_signaled = 1; - } - - /* - * Check if any sockets have signaled - */ - rc = select(0, &rfds, &wfds, &efds, &tv); - if (!handle_signaled && rc == SOCKET_ERROR) - return wsa_select_errno(WSAGetLastError()); - - if (handle_signaled || (num_sockets && rc > 0)) - break; - - timespent_ms += looptime_ms; - - } while (timespent_ms < timeout_ms); - - rc = 0; - num_handles = 0; - for (i = 0; i < nfds; i++) { - pfds[i].revents = 0; - - if ((int)pfds[i].fd < 0) - continue; - - if (is_socket(pfds[i].fd)) { - - pfds[i].revents = compute_select_revents(pfds[i].fd, - pfds[i].events, &rfds, &wfds, &efds); - - } else { - pfds[i].revents = compute_wait_revents( - handles[num_handles], pfds[i].events, num_handles, - wait_rc); - num_handles++; - } - - if (pfds[i].revents) - rc++; - } - - return rc; -} - -- cgit v1.2.3-55-g6feb