summaryrefslogtreecommitdiffstats
path: root/nsock
diff options
context:
space:
mode:
Diffstat (limited to 'nsock')
-rw-r--r--nsock/examples/Makefile29
-rw-r--r--nsock/examples/README9
-rw-r--r--nsock/examples/nsock_telnet.c259
-rw-r--r--nsock/examples/nsock_test_timers.c162
-rw-r--r--nsock/include/nsock.h716
-rw-r--r--nsock/include/nsock_config.h.in90
-rw-r--r--nsock/include/nsock_winconfig.h70
-rw-r--r--nsock/nsock.vcxproj237
-rw-r--r--nsock/src/Makefile.in97
-rw-r--r--nsock/src/acinclude.m4119
-rw-r--r--nsock/src/aclocal.m415
-rwxr-xr-xnsock/src/configure6298
-rw-r--r--nsock/src/configure.ac317
-rw-r--r--nsock/src/engine_epoll.c354
-rw-r--r--nsock/src/engine_iocp.c788
-rw-r--r--nsock/src/engine_kqueue.c368
-rw-r--r--nsock/src/engine_poll.c429
-rw-r--r--nsock/src/engine_select.c395
-rw-r--r--nsock/src/error.c85
-rw-r--r--nsock/src/error.h87
-rw-r--r--nsock/src/filespace.c114
-rw-r--r--nsock/src/filespace.h102
-rw-r--r--nsock/src/gh_heap.c250
-rw-r--r--nsock/src/gh_heap.h143
-rw-r--r--nsock/src/gh_list.h296
-rw-r--r--nsock/src/netutils.c183
-rw-r--r--nsock/src/netutils.h103
-rw-r--r--nsock/src/nsock_connect.c652
-rw-r--r--nsock/src/nsock_core.c1415
-rw-r--r--nsock/src/nsock_engines.c187
-rw-r--r--nsock/src/nsock_event.c538
-rw-r--r--nsock/src/nsock_internal.h522
-rw-r--r--nsock/src/nsock_iod.c455
-rw-r--r--nsock/src/nsock_log.c116
-rw-r--r--nsock/src/nsock_log.h115
-rw-r--r--nsock/src/nsock_pcap.c516
-rw-r--r--nsock/src/nsock_pcap.h152
-rw-r--r--nsock/src/nsock_pool.c308
-rw-r--r--nsock/src/nsock_proxy.c439
-rw-r--r--nsock/src/nsock_proxy.h176
-rw-r--r--nsock/src/nsock_read.c130
-rw-r--r--nsock/src/nsock_ssl.c278
-rw-r--r--nsock/src/nsock_ssl.h85
-rw-r--r--nsock/src/nsock_timers.c76
-rw-r--r--nsock/src/nsock_write.c236
-rw-r--r--nsock/src/proxy_http.c210
-rw-r--r--nsock/src/proxy_socks4.c241
-rw-r--r--nsock/tests/Makefile.in43
-rw-r--r--nsock/tests/README5
-rw-r--r--nsock/tests/basic.c52
-rw-r--r--nsock/tests/cancel.c134
-rw-r--r--nsock/tests/connect.c113
-rw-r--r--nsock/tests/ghheaps.c151
-rw-r--r--nsock/tests/ghlists.c189
-rw-r--r--nsock/tests/logs.c176
-rw-r--r--nsock/tests/proxychain.c159
-rwxr-xr-xnsock/tests/run_tests.sh86
-rw-r--r--nsock/tests/test-common.h89
-rw-r--r--nsock/tests/tests_main.c133
-rw-r--r--nsock/tests/timer.c129
60 files changed, 20421 insertions, 0 deletions
diff --git a/nsock/examples/Makefile b/nsock/examples/Makefile
new file mode 100644
index 0000000..de40593
--- /dev/null
+++ b/nsock/examples/Makefile
@@ -0,0 +1,29 @@
+CC = gcc
+CCOPT =
+DEFS =
+NBASEDIR=../../nbase
+NSOCKLIB=../src/libnsock.a
+NBASELIB=$(NBASEDIR)/libnbase.a
+OPENSSLLIB=-lssl -lpcap -lcrypto
+INCLS = -I../include -I$(NBASEDIR)
+CFLAGS = -I/usr/local/include -Wall -g $(CCOPT) $(DEFS) $(INCLS)
+LDFLAGS =
+PCAPBASEDIR=../../libpcap
+PCAPLIB=$(PCAPBASEDIR)/libpcap.a
+RM = rm -f
+
+TARGETS = nsock_test_timers nsock_telnet
+
+all: $(TARGETS)
+
+nsock_telnet: nsock_telnet.o $(NSOCKLIB)
+ $(CC) -o $@ $(CFLAGS) nsock_telnet.o $(NSOCKLIB) $(NBASELIB) $(OPENSSLLIB)
+
+nsock_test_timers: nsock_test_timers.o $(NSOCKLIB)
+ $(CC) -o $@ $(CFLAGS) nsock_test_timers.o $(NSOCKLIB) $(NBASELIB) $(OPENSSLLIB)
+
+nsock_pcap: nsock_pcap.o $(NSOCKLIB) $(PCAPLIB)
+ $(CC) -o $@ $(CFLAGS) nsock_pcap.o $(NSOCKLIB) $(NBASELIB) $(OPENSSLLIB) $(PCAPLIB)
+
+clean:
+ $(RM) *.o $(TARGETS)
diff --git a/nsock/examples/README b/nsock/examples/README
new file mode 100644
index 0000000..d3c66f5
--- /dev/null
+++ b/nsock/examples/README
@@ -0,0 +1,9 @@
+$Id$
+
+Here are some example programs, they weren't really written to
+present nice and elegant use of the nsock library. They were
+actually written for my testing purposes during development. So don't
+be surprised if you see code that looks strange, or even downright
+evil -- I'm testing the code reliability.
+
+-Fyodor \ No newline at end of file
diff --git a/nsock/examples/nsock_telnet.c b/nsock/examples/nsock_telnet.c
new file mode 100644
index 0000000..cb2a7c0
--- /dev/null
+++ b/nsock/examples/nsock_telnet.c
@@ -0,0 +1,259 @@
+/***************************************************************************
+ * nsock_telnet.c -- A simple "telnet" client -- a trivial example of *
+ * using the nsock parallel socket event library *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+
+#include "nsock.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <sys/time.h>
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+/* #include <nbase.h> */
+
+/* from nbase.h */
+int socket_errno();
+
+
+extern char *optarg;
+
+extern int optind;
+
+struct telnet_state {
+ nsock_iod tcp_nsi;
+ nsock_iod stdin_nsi;
+ nsock_event_id latest_readtcpev;
+ nsock_event_id latest_readstdinev;
+ void *ssl_session;
+};
+
+/* Tries to resolve given hostname and stores
+ result in ip . returns 0 if hostname cannot
+ be resolved */
+int resolve(char *hostname, struct in_addr *ip) {
+ struct hostent *h;
+
+ if (!hostname || !*hostname) {
+ fprintf(stderr, "NULL or zero-length hostname passed to resolve(). Quitting.\n");
+ exit(1);
+ }
+
+ if (inet_aton(hostname, ip))
+ return 1; /* damn, that was easy ;) */
+ if ((h = gethostbyname(hostname))) {
+ memcpy(ip, h->h_addr_list[0], sizeof(struct in_addr));
+ return 1;
+ }
+ return 0;
+}
+
+void telnet_event_handler(nsock_pool nsp, nsock_event nse, void *mydata) {
+ nsock_iod nsi = nse_iod(nse);
+ enum nse_status status = nse_status(nse);
+ enum nse_type type = nse_type(nse);
+ struct sockaddr_in peer;
+ struct telnet_state *ts;
+ int nbytes;
+ char *str;
+ int read_timeout = -1;
+ int write_timeout = 2000;
+ ts = (struct telnet_state *)mydata;
+
+ printf("telnet_event_handler: Received callback of type %s with status %s\n", nse_type2str(type), nse_status2str(status));
+
+ if (status == NSE_STATUS_SUCCESS) {
+ switch (type) {
+ case NSE_TYPE_CONNECT:
+ case NSE_TYPE_CONNECT_SSL:
+ nsock_iod_get_communication_info(nsi, NULL, NULL, NULL, (struct sockaddr *)&peer, sizeof peer);
+ printf("Successfully connected %sto %s:%hu -- start typing lines\n", (type == NSE_TYPE_CONNECT_SSL) ? "(SSL!) " : "", inet_ntoa(peer.sin_addr), ntohs(peer.sin_port));
+ /* First of all, lets add STDIN to our list of watched filehandles */
+ if ((ts->stdin_nsi = nsock_iod_new2(nsp, STDIN_FILENO, NULL)) == NULL) {
+ fprintf(stderr, "Failed to create stdin msi\n");
+ exit(1);
+ }
+
+ /* Now lets read from stdin and the network, line buffered (by nsock) */
+ ts->latest_readtcpev = nsock_readlines(nsp, ts->tcp_nsi, telnet_event_handler, read_timeout, ts, 1);
+ ts->latest_readstdinev = nsock_readlines(nsp, ts->stdin_nsi, telnet_event_handler, read_timeout, ts, 1);
+ break;
+ case NSE_TYPE_READ:
+ str = nse_readbuf(nse, &nbytes);
+ if (nsi == ts->tcp_nsi) {
+ printf("%s", str);
+ /* printf("Read from tcp socket (%d bytes):\n%s", nbytes, str); */
+ ts->latest_readtcpev = nsock_readlines(nsp, ts->tcp_nsi, telnet_event_handler, read_timeout, ts, 1);
+ } else {
+ /* printf("Read from stdin (%d bytes):\n%s", nbytes, str); */
+ nsock_write(nsp, ts->tcp_nsi, telnet_event_handler, write_timeout, ts, str, nbytes);
+ ts->latest_readstdinev = nsock_readlines(nsp, ts->stdin_nsi, telnet_event_handler, read_timeout, ts, 1);
+ }
+ break;
+ case NSE_TYPE_WRITE:
+ /* Nothing to do, really */
+ break;
+ case NSE_TYPE_TIMER:
+ break;
+ default:
+ fprintf(stderr, "telnet_event_handler: Got bogus type -- quitting\n");
+ exit(1);
+ break;
+ }
+ } else if (status == NSE_STATUS_EOF) {
+ printf("Got EOF from %s\nCancelling outstanding readevents.\n", (nsi == ts->tcp_nsi) ? "tcp socket" : "stdin");
+ /* One of these is the event I am currently handling! But I wanted to
+ be evil when testing this out... */
+ if (nsock_event_cancel(nsp, ts->latest_readtcpev, 1) != 0) {
+ printf("Cancelled tcp event: %li\n", ts->latest_readtcpev);
+ }
+ if (nsock_event_cancel(nsp, ts->latest_readstdinev, 1) != 0) {
+ printf("Cancelled stdin event: %li\n", ts->latest_readstdinev);
+ }
+ } else if (status == NSE_STATUS_ERROR) {
+ if (nsock_iod_check_ssl(nsi)) {
+ printf("SSL %s failed: %s\n", nse_type2str(type), ERR_error_string(ERR_get_error(), NULL));
+ } else {
+ int err;
+
+ err = nse_errorcode(nse);
+ printf("%s failed: (%d) %s\n", nse_type2str(type), err, strerror(err));
+ }
+ }
+ return;
+}
+
+void usage() {
+ fprintf(stderr, "\nUsage: nsock_telnet [-s] <hostnameorip> [portnum]\n" " Where -s enables SSL for the connection\n\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ struct in_addr target;
+ nsock_pool nsp;
+ nsock_event_id ev;
+ unsigned short portno;
+ enum nsock_loopstatus loopret;
+ struct telnet_state ts;
+ int c;
+ int usessl = 0;
+ struct timeval now;
+ struct sockaddr_in taddr;
+
+ ts.stdin_nsi = NULL;
+
+ while ((c = getopt(argc, argv, "s")) != -1) {
+ switch (c) {
+ case 's':
+ usessl = 1;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (argc - optind <= 0 || argc - optind > 2)
+ usage();
+
+
+ if (!resolve(argv[optind], &target)) {
+ fprintf(stderr, "Failed to resolve target host: %s\nQUITTING.\n", argv[optind]);
+ exit(1);
+ }
+ optind++;
+
+ if (optind < argc)
+ portno = atoi(argv[optind]);
+ else
+ portno = 23;
+
+ /* OK, we start with creating a p00l */
+ if ((nsp = nsock_pool_new(NULL)) == NULL) {
+ fprintf(stderr, "Failed to create new pool. QUITTING.\n");
+ exit(1);
+ }
+
+ gettimeofday(&now, NULL);
+
+ if ((ts.tcp_nsi = nsock_iod_new(nsp, NULL)) == NULL) {
+ fprintf(stderr, "Failed to create new nsock_iod. QUITTING.\n");
+ exit(1);
+ }
+
+ taddr.sin_family = AF_INET;
+ taddr.sin_addr = target;
+ taddr.sin_port = portno;
+
+ if (usessl) {
+ ts.ssl_session = NULL;
+ ev = nsock_connect_ssl(nsp, ts.tcp_nsi, telnet_event_handler, 10000, &ts, (struct sockaddr *)&taddr, sizeof taddr, IPPROTO_TCP, portno, ts.ssl_session);
+ } else
+ ev = nsock_connect_tcp(nsp, ts.tcp_nsi, telnet_event_handler, 10000, &ts, (struct sockaddr *)&taddr, sizeof taddr, portno);
+
+ printf("The event id is %lu -- initiating l00p\n", ev);
+
+ /* Now lets get this party started right! */
+ loopret = nsock_loop(nsp, -1);
+
+ printf("nsock_loop returned %d\n", (int)loopret);
+
+ return 0;
+}
diff --git a/nsock/examples/nsock_test_timers.c b/nsock/examples/nsock_test_timers.c
new file mode 100644
index 0000000..24972e2
--- /dev/null
+++ b/nsock/examples/nsock_test_timers.c
@@ -0,0 +1,162 @@
+/***************************************************************************
+ * nsock_test_timers.c -- A test program to exercise the nsock timer *
+ * routines. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+
+#include "nsock.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+
+nsock_event_id ev_ids[2048];
+
+int num_ids = 0;
+
+nsock_event_id request_timer(nsock_pool nsp, nsock_ev_handler handler, int timeout_msecs, void *userdata) {
+ nsock_event_id id;
+
+ id = nsock_timer_create(nsp, handler, timeout_msecs, userdata);
+ printf("%ld: Created timer ID %li for %d ms from now\n", time(NULL), id, timeout_msecs);
+
+ return id;
+
+}
+
+int try_cancel_timer(nsock_pool nsp, int idx, int notify) {
+ int res;
+
+ printf("%ld:Attempting to cancel id %li (idx %d) %s notify.\n", time(NULL), ev_ids[idx], idx, ((notify) ? "WITH" : "WITHOUT"));
+ res = nsock_event_cancel(nsp, ev_ids[idx], notify);
+ printf("Kill of %li %s\n", ev_ids[idx], (res == 0) ? "FAILED" : "SUCCEEDED");
+ return res;
+}
+
+void timer_handler(nsock_pool nsp, nsock_event nse, void *mydata) {
+ enum nse_status status = nse_status(nse);
+ enum nse_type type = nse_type(nse);
+ int rnd, rnd2;
+
+ printf("%ld:timer_handler: Received callback of type %s; status %s; id %li\n", time(NULL), nse_type2str(type), nse_status2str(status), nse_id(nse));
+
+ rnd = rand() % num_ids;
+ rnd2 = rand() % 3;
+
+ if (num_ids > (sizeof(ev_ids) / sizeof(nsock_event_id)) - 3) {
+ printf("\n\nSUCCEEDED DUE TO CREATING ENOUGH EVENTS THAT IT WAS GOING TO OVERFLOW MY BUFFER :)\n\n");
+ exit(0);
+ }
+
+ if (status == NSE_STATUS_SUCCESS) {
+ switch (rnd2) {
+ case 0:
+ /* do nothing */
+ /* Actually I think I'll create two timers :) */
+ ev_ids[num_ids++] = request_timer(nsp, timer_handler, rand() % 3000, NULL);
+ ev_ids[num_ids++] = request_timer(nsp, timer_handler, rand() % 3000, NULL);
+ break;
+ case 1:
+ /* Kill another id (which may or may not be active */
+ try_cancel_timer(nsp, rnd, rand() % 2);
+ break;
+ case 2:
+ /* Create a new timer */
+ ev_ids[num_ids++] = request_timer(nsp, timer_handler, rand() % 3000, NULL);
+ break;
+ default:
+ assert(0);
+ }
+ }
+}
+
+int main(int argc, char *argv[]) {
+ nsock_pool nsp;
+ enum nsock_loopstatus loopret;
+ int num_loops = 0;
+
+ srand(time(NULL));
+ /* OK, we start with creating a p00l */
+ if ((nsp = nsock_pool_new(NULL)) == NULL) {
+ fprintf(stderr, "Failed to create new pool. QUITTING.\n");
+ exit(1);
+ }
+
+ ev_ids[num_ids++] = request_timer(nsp, timer_handler, 1800, NULL);
+ ev_ids[num_ids++] = request_timer(nsp, timer_handler, 800, NULL);
+ ev_ids[num_ids++] = request_timer(nsp, timer_handler, 1300, NULL);
+ ev_ids[num_ids++] = request_timer(nsp, timer_handler, 0, NULL);
+ ev_ids[num_ids++] = request_timer(nsp, timer_handler, 100, NULL);
+
+ /* Now lets get this party started right! */
+ while (num_loops++ < 5) {
+ loopret = nsock_loop(nsp, 1500);
+ if (loopret == NSOCK_LOOP_TIMEOUT)
+ printf("Finished l00p #%d due to l00p timeout :) I may do another\n", num_loops);
+ else if (loopret == NSOCK_LOOP_NOEVENTS) {
+ printf("SUCCESS -- NO EVENTS LEFT\n");
+ exit(0);
+ } else {
+ printf("nsock_loop FAILED!\n");
+ exit(1);
+ }
+ }
+ printf("Trying to kill my msp!\n");
+ nsock_pool_delete(nsp);
+ printf("SUCCESS -- completed %d l00ps.\n", num_loops);
+
+ return 0;
+}
diff --git a/nsock/include/nsock.h b/nsock/include/nsock.h
new file mode 100644
index 0000000..280e36b
--- /dev/null
+++ b/nsock/include/nsock.h
@@ -0,0 +1,716 @@
+/***************************************************************************
+ * nsock.h -- public interface definitions for the nsock parallel socket *
+ * event library *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifndef NSOCK_H
+#define NSOCK_H
+
+/* Keep assert() defined for security reasons */
+#undef NDEBUG
+
+#ifndef WIN32
+#include "nsock_config.h"
+#else
+#include "nsock_winconfig.h"
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#else
+#include <winsock2.h> /* for struct timeval... */
+#endif
+
+#if HAVE_SYS_UN_H
+#include <sys/un.h>
+
+#ifndef SUN_LEN
+#include <string.h>
+#define SUN_LEN(ptr) ((sizeof(*(ptr)) - sizeof((ptr)->sun_path)) \
+ + strlen((ptr)->sun_path))
+#endif
+#endif /* HAVE_SYS_UN_H */
+
+#if HAVE_LINUX_VM_SOCKETS_H
+#include <linux/vm_sockets.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The read calls will generally return after reading at least this
+ * much data so that the caller can process it and so that the
+ * connection spewing data doesn't monopolize resources. The caller
+ * can always initiate another read request to ask for more. */
+#define NSOCK_READ_CHUNK_SIZE 0x8FFFF
+
+struct npool;
+struct niod;
+struct nevent;
+struct proxy_chain;
+
+/* ------------------- TYPEDEFS ------------------- */
+
+/* nsock_pool, nsock_iod, and nsock_event are opaque objects that should
+ * only be accessed using the appropriate accessor functions (described below). */
+
+/* An nsock_pool aggregates and manages events and i/o descriptors */
+typedef struct npool *nsock_pool;
+
+/* nsock_iod is an I/O descriptor -- you create it and then use it to
+ * make calls to do connect()s, read()s, write()s, etc. A single IOD can handle
+ * multiple event calls, but only one at a time. Also the event calls must be in
+ * a "reasonable" order. For example, you might start with nsock_connect_tcp()
+ * followed by a bunch of nsock_read* and nsock_write* calls. Then you either
+ * destroy the iod for good with nsock_iod_delete() and allocate a new one via
+ * nsock_iod_new for your next connection. */
+typedef struct niod *nsock_iod;
+
+/* An event is created when you do various calls (for reading, writing,
+ * connecting, timers, etc) and is provided back to you in the callback when the
+ * call completes/fails. It is automatically destroyed after the callback */
+typedef struct nevent *nsock_event;
+
+/* Provided by calls which (internally) create an nsock_event. This allows you
+ * to cancel the event */
+typedef unsigned long nsock_event_id;
+
+/* This is used to save SSL sessionids between SSL connections */
+typedef void *nsock_ssl_session;
+typedef void *nsock_ssl_ctx;
+typedef void *nsock_ssl;
+
+typedef struct proxy_chain *nsock_proxychain;
+
+
+/* Logging-related data structures */
+
+typedef enum {
+ /* --
+ * Actual message priority values */
+ NSOCK_LOG_DBG_ALL,
+ NSOCK_LOG_DBG,
+ NSOCK_LOG_INFO,
+ NSOCK_LOG_ERROR,
+ /* --
+ * No messages are issued by nsock with this value.
+ * Users can therefore set loglevel to NSOCK_LOG_NONE
+ * to disable logging */
+ NSOCK_LOG_NONE
+} nsock_loglevel_t;
+
+struct nsock_log_rec {
+ /* Message emission time */
+ struct timeval time;
+ /* Message log level */
+ nsock_loglevel_t level;
+ /* Source file */
+ const char *file;
+ /* Statement line in nsock source */
+ int line;
+ /* Function that emitted the message */
+ const char *func;
+ /* Actual log message */
+ char *msg;
+};
+
+/* Nsock logging function. This function receives all nsock log records whose
+ * level is greater than or equal to nsp loglevel. The rec structure is
+ * allocated and freed by nsock. */
+typedef void (*nsock_logger_t)(const struct nsock_log_rec *rec);
+
+
+/* ------------------- PROTOTYPES ------------------- */
+
+/* Here is the all important looping function that tells the event
+ * engine to start up and begin processing events. It will continue until all
+ * events have been delivered (including new ones started from event handlers),
+ * or the msec_timeout is reached, or a major error has occurred. Use -1 if you
+ * don't want to set a maximum time for it to run. A timeout of 0 will return
+ * after 1 non-blocking loop. The nsock loop can be restarted again after it
+ * returns. For example you could do a series of 15 second runs, allowing you
+ * to do other stuff between them. Or you could just schedule a timer to call
+ * you back every 15 seconds. */
+enum nsock_loopstatus {
+ NSOCK_LOOP_NOEVENTS = 2,
+ NSOCK_LOOP_TIMEOUT,
+ NSOCK_LOOP_ERROR,
+ NSOCK_LOOP_QUIT
+};
+
+enum nsock_loopstatus nsock_loop(nsock_pool nsp, int msec_timeout);
+
+/* Calling this function will cause nsock_loop to quit on its next iteration
+ * with a return value of NSOCK_LOOP_QUIT. */
+void nsock_loop_quit(nsock_pool nsp);
+
+/* This next function returns the errno style error code -- which is only valid
+ * if the status is NSOCK_LOOP_ERROR was returned by nsock_loop() */
+int nsock_pool_get_error(nsock_pool nsp);
+
+nsock_ssl nsock_iod_get_ssl(nsock_iod nsockiod);
+
+/* Note that nsock_iod_get_ssl_session will increment the usage count of the
+ * SSL_SESSION if inc_ref is not zero, since nsock does a free when the IOD
+ * is destroyed. It's up to any calling function/etc to do a SSL_SESSION_free()
+ * on it. Passing in inc_ref=0 doesn't increment, and is for informational
+ * purposes only. */
+nsock_ssl_session nsock_iod_get_ssl_session(nsock_iod nsockiod, int inc_ref);
+
+/* Sometimes it is useful to store a pointer to information inside the NSP so
+ * you can retrieve it during a callback. */
+void nsock_pool_set_udata(nsock_pool nsp, void *data);
+
+/* And the function above wouldn't make much sense if we didn't have a way to
+ * retrieve that data ... */
+void *nsock_pool_get_udata(nsock_pool nsp);
+
+/* Turns on or off broadcast support on new sockets. Default is off (0, false)
+ * set in nsock_pool_new(). Any non-zero (true) value sets SO_BROADCAST on all
+ * new sockets (value of optval will be used directly in the setsockopt() call). */
+void nsock_pool_set_broadcast(nsock_pool nsp, int optval);
+
+/* Sets the name of the interface for new sockets to bind to. */
+void nsock_pool_set_device(nsock_pool nsp, const char *device);
+
+/* Initializes an Nsock pool to create SSL connections. This sets an internal
+ * SSL_CTX, which is like a template that sets options for all connections that
+ * are made from it. Returns the SSL_CTX so you can set your own options.
+ *
+ * Use the NSOCK_SSL_MAX_SPEED to emphasize speed over security.
+ * Insecure ciphers are used when they are faster and no certificate
+ * verification is done.
+ *
+ * Returns the SSL_CTX so you can set your own options.
+ * By default, do no server certificate verification. To enable it, do
+ * something like:
+ * SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
+ *
+ * on the SSL_CTX returned. If you do, it is then up to the application to
+ * load trusted certificates with SSL_CTX_load_verify_locations or
+ * SSL_CTX_set_default_verify_paths, or else every connection will fail. It
+ * is also up to the application to do any further checks such as domain name
+ * validation. */
+#define NSOCK_SSL_MAX_SPEED (1 << 0)
+nsock_ssl_ctx nsock_pool_ssl_init(nsock_pool ms_pool, int flags);
+
+/* Initializes an Nsock pool to create a DTLS connect. This sets and internal
+ * SSL_CTX, which is like a template that sets options for all connections that
+ * are made from it. Returns the SSL_CTX so tyou can set your own options.
+ *
+ * Functionally similar to nsock_pool_ssl_init, just for the DTLS */
+nsock_ssl_ctx nsock_pool_dtls_init(nsock_pool ms_pool, int flags);
+
+/* Enforce use of a given IO engine.
+ * The engine parameter is a zero-terminated string that will be
+ * strup()'ed by the library. No validity check is performed by this function,
+ * beware nsock_pool_new() will fatal() if an invalid/unavailable engine name was
+ * supplied before.
+ * Pass NULL to reset to default (use most efficient engine available).
+ *
+ * Function returns 0 on success and -1 on error. */
+int nsock_set_default_engine(char *engine);
+
+/* Get a comma-separated list of available engines. */
+const char *nsock_list_engines(void);
+
+/* And here is how you create an nsock_pool. This allocates, initializes, and
+ * returns an nsock_pool event aggregator. In the case of error, NULL will be
+ * returned. If you do not wish to immediately associate any userdata, pass in
+ * NULL. */
+nsock_pool nsock_pool_new(void *udata);
+
+/* If nsock_pool_new returned success, you must free the nsp when you are done with it
+ * to conserve memory (and in some cases, sockets). After this call, nsp may no
+ * longer be used. Any pending events are sent an NSE_STATUS_KILL callback and
+ * all outstanding iods are deleted. */
+void nsock_pool_delete(nsock_pool nsp);
+
+/* Logging subsystem: set custom logging function.
+ * A NULL logger will reset the default (stderr) logger.
+ * (See nsock_logger_t type definition). */
+void nsock_set_log_function(nsock_logger_t logger);
+
+nsock_loglevel_t nsock_get_loglevel(void);
+void nsock_set_loglevel(nsock_loglevel_t loglevel);
+
+/* Parse a proxy chain description string and build a nsock_proxychain object
+ * accordingly. If the optional nsock_pool parameter is passed in, it gets
+ * associated to the chain object. The alternative is to pass nsp=NULL and call
+ * nsock_pool_set_proxychain() manually. Whatever is done, the chain object has
+ * to be deleted by the caller, using proxychain_delete().
+ * Returns 1 on success, -1 on failure. */
+int nsock_proxychain_new(const char *proxystr, nsock_proxychain *chain, nsock_pool nspool);
+
+/* If nsock_proxychain_new() returned success, caller has to free the chain
+ * object using this function. */
+void nsock_proxychain_delete(nsock_proxychain chain);
+
+/* Assign a previously created proxychain object to a nsock pool. After this,
+ * new connections requests will be issued through the chain of proxies (if
+ * possible). This only applies to nsock_iod created *after* the call to
+ * nsock_pool_set_proxychain(). Existing nsock_iod will connect as normal. */
+int nsock_pool_set_proxychain(nsock_pool nspool, nsock_proxychain chain);
+
+/* nsock_event handles a single event. Its ID is generally returned when the
+ * event is created, and the event itself is included in callbacks
+ *
+ * ---------------------------------------------------------------------------
+ * IF YOU ADD NEW NSE_TYPES YOU MUST INCREASE TYPE_CODE_NUM_BITS SO THAT IT IS
+ * ALWAYS log2(maximum_nse_type_value + 1)
+ * --------------------------------------------------------------------------- */
+#define TYPE_CODE_NUM_BITS 3
+enum nse_type {
+ NSE_TYPE_CONNECT = 0,
+ NSE_TYPE_CONNECT_SSL = 1,
+ NSE_TYPE_READ = 2,
+ NSE_TYPE_WRITE = 3,
+ NSE_TYPE_TIMER = 4,
+ NSE_TYPE_PCAP_READ = 5,
+ NSE_TYPE_MAX = 6,
+}; /* At some point I was considering a NSE_TYPE_START and NSE_TYPE_CUSTOM */
+
+/* Find the type of an event that spawned a callback */
+enum nse_type nse_type(nsock_event nse);
+
+/* Takes an nse_type (as returned by nse_type()) and returns a static string name
+ * that you can use for printing, etc. */
+const char *nse_type2str(enum nse_type type);
+
+/* Did the event succeed? What is the status? */
+enum nse_status {
+ NSE_STATUS_NONE = 0, /* User should never see this */
+ NSE_STATUS_SUCCESS, /* Everything went A-OK! */
+ NSE_STATUS_ERROR, /* Uh-oh! Problem, check the nse_errorcode() */
+ NSE_STATUS_TIMEOUT, /* The async call surpassed the timeout you specified */
+ NSE_STATUS_CANCELLED, /* Someone cancelled the event. (by calling nsock_event_cancel()). */
+ NSE_STATUS_KILL, /* The event has been killed, this generally means the
+ nspool is being deleted -- you should free up any
+ resources you have allocated and exit. Don't you
+ dare make any more async nsock calls! */
+ NSE_STATUS_EOF, /* We got EOF and NO DATA -- if we got data first,
+ SUCCESS is reported (see nse_eof()). */
+ NSE_STATUS_PROXYERROR
+};
+
+enum nse_status nse_status(nsock_event nse);
+
+/* Takes an nse_status (as returned by nse_status() and returns a static string
+ * name that you can use for printing, etc. */
+const char *nse_status2str(enum nse_status status);
+
+/* This next function tells whether we received an EOF when we were reading. It
+ * is generally a better way to check for EOF than looking at the status because
+ * sometimes we read some data before getting the EOF, in which SUCCESS is
+ * returned (although another read attempt would return a status of EOF).
+ * nse_eof returns nonzero if we have reached EOF, zero if we have NOT reach
+ * EOF. */
+int nse_eof(nsock_event nse);
+
+/* This next function returns the errno style error code -- which is only valid
+ * if the status is NSE_STATUS_ERROR (this is a normal errno style error code). */
+int nse_errorcode(nsock_event nse);
+
+/* Every event has an ID which will be unique throughout the program's execution
+ * (for a given nsock_pool) unless you blow through 500,000,000 of them */
+nsock_event_id nse_id(nsock_event nse);
+
+/* If you did a read request, and the result was STATUS_SUCCESS, this function
+ * provides the buffer that was read in as well as the number of chars read.
+ * The buffer should not be modified or free'd . It is not guaranteed to be
+ * NUL-terminated and it may even contain nuls */
+char *nse_readbuf(nsock_event nse, int *nbytes);
+
+/* Obtains the nsock_iod (see below) associated with the event. Note that some
+ * events (such as timers) don't have an nsock_iod associated with them */
+nsock_iod nse_iod(nsock_event nse);
+
+/* nsock_iod is like a "file descriptor" for the nsock library. You use it to
+ * request events. And here is how you create an nsock_iod. nsock_iod_new
+ * returns NULL if the iod cannot be allocated. Pass NULL as udata if you
+ * don't want to immediately associate any user data with the IOD. */
+nsock_iod nsock_iod_new(nsock_pool nsockp, void *udata);
+
+/* This version allows you to associate an existing sd with the msi so that you
+ * can read/write it using the nsock infrastructure. For example, you may want
+ * to watch for data from STDIN_FILENO at the same time as you read/write
+ * various sockets. STDIN_FILENO is a special case, however. Any other sd is
+ * dup()ed, so you may close or otherwise manipulate your copy. The duped copy
+ * will be destroyed when the IOD is destroyed */
+nsock_iod nsock_iod_new2(nsock_pool nsockp, int sd, void *udata);
+
+/* If nsock_iod_new returned success, you must free the iod when you are done
+ * with it to conserve memory (and in some cases, sockets). After this call,
+ * nsockiod may no longer be used -- you need to create a new one with
+ * nsock_iod_new(). pending_response tells what to do with any events that are
+ * pending on this nsock_iod. This can be NSOCK_PENDING_NOTIFY (send a KILL
+ * notification to each event), NSOCK_PENDING_SILENT (do not send notification
+ * to the killed events), or NSOCK_PENDING_ERROR (print an error message and
+ * quit the program) */
+enum nsock_del_mode {
+ NSOCK_PENDING_NOTIFY,
+ NSOCK_PENDING_SILENT,
+ NSOCK_PENDING_ERROR,
+};
+
+void nsock_iod_delete(nsock_iod iod, enum nsock_del_mode pending_response);
+
+/* Sometimes it is useful to store a pointer to information inside
+ * the nsiod so you can retrieve it during a callback. */
+void nsock_iod_set_udata(nsock_iod iod, void *udata);
+
+/* And the function above wouldn't make much sense if we didn't have a way to
+ * retrieve that data ... */
+void *nsock_iod_get_udata(nsock_iod iod);
+
+/* I didn't want to do this. Its an ugly hack, but I suspect it will be
+ * necessary. I certainly can't reproduce in nsock EVERYTHING you might want
+ * to do with a socket. So I'm offering you this function to obtain the socket
+ * descriptor which is (usually) wrapped in a nsock_iod). You can do
+ * "reasonable" things with it, like setting socket receive buffers. But don't
+ * create havok by closing the descriptor! If the descriptor you get back is
+ * -1, the iod does not currently possess a valid descriptor */
+int nsock_iod_get_sd(nsock_iod iod);
+
+/* Returns the ID of an nsock_iod . This ID is always unique amongst ids for a
+ * given nspool (unless you blow through billions of them). */
+unsigned long nsock_iod_id(nsock_iod iod);
+
+/* Returns Packets received in bytes */
+unsigned long nsock_iod_get_read_count(nsock_iod iod);
+
+/* Returns Packets sent in bytes */
+unsigned long nsock_iod_get_write_count(nsock_iod iod);
+
+/* Returns 1 if an NSI is communicating via SSL, 0 otherwise */
+int nsock_iod_check_ssl(nsock_iod iod);
+
+/* Returns the remote peer port (or -1 if unavailable). Note the return value
+ * is a whole int so that -1 can be distinguished from 65535. Port is returned
+ * in host byte order. */
+int nsock_iod_get_peerport(nsock_iod iod);
+
+/* Sets the local address to bind to before connect() */
+int nsock_iod_set_localaddr(nsock_iod iod, struct sockaddr_storage *ss, size_t sslen);
+
+/* Sets IPv4 options to apply before connect(). It makes a copy of the options,
+ * so you can free() yours if necessary. This copy is freed when the iod is
+ * destroyed */
+int nsock_iod_set_ipoptions(nsock_iod iod, void *ipopts, size_t ipoptslen);
+
+/* Returns that host/port/protocol information for the last communication (or
+ * comm. attempt) this nsi has been involved with. By "involved" with I mean
+ * interactions like establishing (or trying to) a connection or sending a UDP
+ * datagram through an unconnected nsock_iod. AF is the address family (AF_INET
+ * or AF_INET6), Protocol is IPPROTO_TCP or IPPROTO_UDP. Pass NULL for
+ * information you do not need. If ANY of the information you requested is not
+ * available, 0 will be returned and the unavailable sockets are zeroed. If
+ * protocol or af is requested but not available, it will be set to -1 (and 0
+ * returned). The pointers you pass in must be NULL or point to allocated
+ * address space. The sockaddr members should actually be sockaddr_storage,
+ * sockaddr_in6, or sockaddr_in with the socklen of them set appropriately (eg
+ * sizeof(sockaddr_storage) if that is what you are passing). */
+int nsock_iod_get_communication_info(nsock_iod iod, int *protocol, int *af,
+ struct sockaddr *local,
+ struct sockaddr *remote, size_t socklen);
+
+/* Set the hostname of the remote host, for when that matters. This is currently
+ * only used for Server Name Indication in SSL connections. */
+int nsock_iod_set_hostname(nsock_iod iod, const char *hostname);
+
+/* EVENT CREATION FUNCTIONS
+ * ---
+ * These functions request asynchronous
+ * notification of completion of an event. The handler will never be
+ * synchronously called back during the event creation call (that causes too
+ * many hard to debug errors and plus we don't want people to have to deal with
+ * callbacks until they actually call nsock_loop). */
+
+/* These functions generally take a common 5 initial parameters:
+ *
+ * nsock_pool mst:
+ * The is the nsock_pool describing the events you have scheduled, etc
+ *
+ * nsock_iod nsiod:
+ * The I/O Descriptor that should be used in the request. Note that timer
+ * events don't have this argument since they don't use an iod. You can
+ * obtain it in the callback from the nsock_event.
+ *
+ * nsock_ev_handler handler:
+ * This is the function you want the system to call when your event is
+ * triggered (or times out, or hits an error, etc.). The function should be
+ * of this form: void funcname(nsock_pool nsp, nsock_event nse, void *userdata)
+ *
+ * int timeout_msecs:
+ * The timeout for the request in milliseconds. If the request hasn't
+ * completed (or in a few cases started) within the timeout specified, the
+ * handler will be called with a TIMEOUT status and the request will be
+ * aborted.
+ *
+ * void *userdata:
+ * The nsock_event that comes back can optionally have a pointer associated
+ * with it. You can set that pointer here. If you don't want one, just
+ * pass NULL.
+ *
+ * These functions return an nsock_event_id which can be used to cancel the
+ * event if necessary.
+ */
+typedef void (*nsock_ev_handler)(nsock_pool, nsock_event, void *);
+
+/* Initialize an unconnected UDP socket. */
+int nsock_setup_udp(nsock_pool nsp, nsock_iod ms_iod, int af);
+
+#if HAVE_SYS_UN_H
+
+/* Request a UNIX domain sockets connection to the same system (by path to socket).
+ * This function connects to the socket of type SOCK_STREAM. ss should be a
+ * sockaddr_storage, sockaddr_un as appropriate (just like what you would pass to
+ * connect). sslen should be the sizeof the structure you are passing in. */
+nsock_event_id nsock_connect_unixsock_stream(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler,
+ int timeout_msecs, void *userdata, struct sockaddr *ss,
+ size_t sslen);
+
+/* Request a UNIX domain sockets connection to the same system (by path to socket).
+ * This function connects to the socket of type SOCK_DGRAM. ss should be a
+ * sockaddr_storage, sockaddr_un as appropriate (just like what you would pass to
+ * connect). sslen should be the sizeof the structure you are passing in. */
+nsock_event_id nsock_connect_unixsock_datagram(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler,
+ void *userdata, struct sockaddr *ss, size_t sslen);
+#endif /* HAVE_SYS_UN_H */
+
+#if HAVE_LINUX_VM_SOCKETS_H
+/* Request a vsock stream connection to another system. ss should be a
+ * sockaddr_storage or sockaddr_vm, as appropriate (just like what you would
+ * pass to connect). sslen should be the sizeof the structure you are passing
+ * in. */
+nsock_event_id nsock_connect_vsock_stream(nsock_pool nsp, nsock_iod ms_iod,
+ nsock_ev_handler handler,
+ int timeout_msecs, void *userdata,
+ struct sockaddr *saddr, size_t sslen,
+ unsigned int port);
+
+/* Request a vsock datagram "connection" to another system. Since this is a
+ * datagram socket, no packets are actually sent. The destination CID and port
+ * are just associated with the nsiod (an actual OS connect() call is made).
+ * You can then use the normal nsock write calls on the socket. There is no
+ * timeout since this call always calls your callback at the next opportunity.
+ * The advantages to having a connected datagram socket (as opposed to just
+ * specifying an address with sendto() are that we can now use a consistent set
+ * of write/read calls for stream and datagram sockets, received packets from
+ * the non-partner are automatically dropped by the OS, and the OS can provide
+ * asynchronous errors (see Unix Network Programming pp224). ss should be a
+ * sockaddr_storage or sockaddr_vm, as appropriate (just like what you would
+ * pass to connect). sslen should be the sizeof the structure you are passing
+ * in. */
+nsock_event_id nsock_connect_vsock_datagram(nsock_pool nsp, nsock_iod nsiod,
+ nsock_ev_handler handler,
+ void *userdata,
+ struct sockaddr *saddr,
+ size_t sslen, unsigned int port);
+#endif /* HAVE_LINUX_VM_SOCKETS_H */
+
+/* Request a TCP connection to another system (by IP address). The in_addr is
+ * normal network byte order, but the port number should be given in HOST BYTE
+ * ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as
+ * appropriate (just like what you would pass to connect). sslen should be the
+ * sizeof the structure you are passing in. */
+nsock_event_id nsock_connect_tcp(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs,
+ void *userdata, struct sockaddr *ss, size_t sslen, unsigned short port);
+
+/* Request an SCTP association to another system (by IP address). The in_addr is
+ * normal network byte order, but the port number should be given in HOST BYTE
+ * ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as
+ * appropriate (just like what you would pass to connect). sslen should be the
+ * sizeof the structure you are passing in. */
+nsock_event_id nsock_connect_sctp(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs,
+ void *userdata, struct sockaddr *ss, size_t sslen, unsigned short port);
+
+/* Request a UDP "connection" to another system (by IP address). The in_addr is
+ * normal network byte order, but the port number should be given in HOST BYTE
+ * ORDER. Since this is UDP, no packets are actually sent. The destination IP
+ * and port are just associated with the nsiod (an actual OS connect() call is
+ * made). You can then use the normal nsock write calls on the socket. There
+ * is no timeout since this call always calls your callback at the next
+ * opportunity. The advantages to having a connected UDP socket (as opposed to
+ * just specifying an address with sendto()) are that we can now use a consistent
+ * set of write/read calls for TCP/UDP, received packets from the non-partner
+ * are automatically dropped by the OS, and the OS can provide asynchronous
+ * errors (see Unix Network Programming pp224). ss should be a
+ * sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate (just like what
+ * you would pass to connect). sslen should be the sizeof the structure you are
+ * passing in. */
+nsock_event_id nsock_connect_udp(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, void *userdata,
+ struct sockaddr *ss, size_t sslen, unsigned short port);
+
+/* Request an SSL over TCP/SCTP connection to another system (by IP address).
+ * The in_addr is normal network byte order, but the port number should be given
+ * in HOST BYTE ORDER. This function will call back only after it has made the
+ * connection AND done the initial SSL negotiation. From that point on, you use
+ * the normal read/write calls and decryption will happen transparently. ss
+ * should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate
+ * (just like what you would pass to connect). sslen should be the sizeof the
+ * structure you are passing in. */
+nsock_event_id nsock_connect_ssl(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs,
+ void *userdata, struct sockaddr *ss, size_t sslen, int proto, unsigned short port, nsock_ssl_session ssl_session);
+
+/* Request ssl connection over already established TCP/SCTP connection. nsiod
+ * must be socket that is already connected to target using nsock_connect_tcp or
+ * nsock_connect_sctp. All parameters have the same meaning as in
+ * 'nsock_connect_ssl' */
+nsock_event_id nsock_reconnect_ssl(nsock_pool nsp, nsock_iod nsiod,
+ nsock_ev_handler handler, int timeout_msecs, void *userdata, nsock_ssl_session ssl_session);
+
+/* Read up to nlines lines (terminated with \n, which of course inclues \r\n),
+ * or until EOF, or until the timeout, whichever comes first. Note that
+ * NSE_STATUS_SUCCESS will be returned in the case of EOF or timeout if at least
+ * 1 char has been read. Also note that you may get more than 'nlines' back --
+ * we just stop once "at least" 'nlines' is read */
+nsock_event_id nsock_readlines(nsock_pool nsp, nsock_iod nsiod,
+ nsock_ev_handler handler, int timeout_msecs, void *userdata, int nlines);
+
+/* Same as above, except it tries to read at least 'nbytes' instead of 'nlines'. */
+nsock_event_id nsock_readbytes(nsock_pool nsp, nsock_iod nsiod,
+ nsock_ev_handler handler, int timeout_msecs, void *userdata, int nbytes);
+
+/* The simplest read function -- returns NSE_STATUS_SUCCESS when it reads
+ * anything, otherwise it returns timeout, eof, or error as appropriate */
+nsock_event_id nsock_read(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs, void *userdata);
+
+/* Write some data to the socket. If the write is not COMPLETED within
+ * timeout_msecs , NSE_STATUS_TIMEOUT will be returned. If you are supplying
+ * NUL-terminated data, you can optionally pass -1 for datalen and nsock_write
+ * will figure out the length itself */
+nsock_event_id nsock_write(nsock_pool nsp, nsock_iod nsiod,
+ nsock_ev_handler handler, int timeout_msecs, void *userdata, const char *data, int datalen);
+
+nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
+ void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port, const char *data, int datalen);
+
+/* Same as nsock_write except you can use a printf-style format and you can only
+ * use this for ASCII strings */
+nsock_event_id nsock_printf(nsock_pool nsp, nsock_iod nsiod,
+ nsock_ev_handler handler, int timeout_msecs, void *userdata, char *format, ... );
+
+/* Send back an NSE_TYPE_TIMER after the number of milliseconds specified. Of
+ * course it can also return due to error, cancellation, etc. */
+nsock_event_id nsock_timer_create(nsock_pool nsp, nsock_ev_handler handler, int timeout_msecs, void *userdata);
+
+/* Cancel an event (such as a timer or read request). If notify is nonzero, the
+ * requester will be sent an event CANCELLED status back to the given handler.
+ * But in some cases there is no need to do this (like if the function deleting
+ * it is the one which created it), in which case 0 can be passed to skip the
+ * step. This function returns zero if the event is not found, nonzero
+ * otherwise */
+int nsock_event_cancel(nsock_pool ms_pool, nsock_event_id id, int notify );
+
+/* Grab the latest time as recorded by the nsock library, which does so at least
+ * once per event loop (in main_loop). Not only does this function (generally)
+ * avoid a system call, but in many circumstances it is better to use nsock's
+ * time rather than the system time. If nsock has never obtained the time when
+ * you call it, it will do so before returning */
+const struct timeval *nsock_gettimeofday();
+
+
+#ifdef HAVE_PCAP
+/* Open pcap device and connect it to nsp. Other parameters have the
+ * same meaning as for pcap_open_live in pcap(3).
+ *
+ * device: pcap-style device name
+ * snaplen: size of packet to be copied to handler
+ * promisc: whether to open device in promiscuous mode
+ * bpf_fmt: berkeley filter
+ *
+ * return value: 0 if everything was okay, or error code if error occurred.
+ * */
+int nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod, const char *pcap_device,
+ int snaplen, int promisc, const char *bpf_fmt, ...);
+
+/* Requests exactly one packet to be captured.from pcap.
+ * See nsock_read() for parameters description. */
+nsock_event_id nsock_pcap_read_packet(nsock_pool nsp, nsock_iod nsiod,
+ nsock_ev_handler handler,
+ int timeout_msecs, void *userdata);
+
+/* Gets packet data. This should be called after successful receipt of packet
+ * to get packet. If you're not interested in some values, just pass NULL
+ * instead of valid pointer.
+ * l3_data is just after l2_data in buffer. Feel free to treat l2_data as one
+ * buffer with size of (l2_len + l3_len).
+ * Ts time is fixed for systems that don't support proper timing, like Windows.
+ * So TS is pointing to time when packet was received or to the time _after_.
+ * As a result you'll get longer times than you should, but it's safer to
+ * think that host is a bit further.
+ * */
+void nse_readpcap(nsock_event nsee, const unsigned char **l2_data,
+ size_t *l2_len, const unsigned char **l3_data, size_t *l3_len,
+ size_t *packet_len, struct timeval *ts);
+
+/* Well. Just pcap-style datalink.
+ * Like DLT_EN10MB or DLT_SLIP. Check in pcap(3) manpage. */
+int nsock_iod_linktype(nsock_iod iod);
+
+/* Is this nsiod a pcap descriptor? */
+int nsock_iod_is_pcap(nsock_iod iod);
+
+#endif /* HAVE_PCAP */
+
+#ifdef __cplusplus
+} /* End of 'extern "C"' */
+#endif
+
+#endif /* NSOCK_H */
+
diff --git a/nsock/include/nsock_config.h.in b/nsock/include/nsock_config.h.in
new file mode 100644
index 0000000..e1d9587
--- /dev/null
+++ b/nsock/include/nsock_config.h.in
@@ -0,0 +1,90 @@
+/***************************************************************************
+ * nsock_config.h.in -- Autoconf uses this template, combined with the *
+ * configure script knowledge about system capabilities, to build the *
+ * nsock_config.h include file that lets nsock better understand system *
+ * particulars. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#undef HAVE_PCAP
+#undef DEC
+#undef LINUX
+#undef FREEBSD
+#undef OPENBSD
+#undef SOLARIS
+#undef SUNOS
+#undef BSDI
+#undef IRIX
+#undef HPUX
+#undef NETBSD
+#undef MACOSX
+
+#undef SOLARIS_BPF_PCAP_CAPTURE
+
+#undef HAVE_NET_BPF_H
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
+#undef HAVE_LINUX_VM_SOCKETS_H
+
+#undef HAVE_NETDB_H
+
+#undef HAVE_OPENSSL
+#undef HAVE_SSL_SET_TLSEXT_HOST_NAME
+#undef HAVE_DTLS_CLIENT_METHOD
+#undef HAVE_ALPN_SUPPORT
+
+#undef HAVE_EPOLL
+#undef HAVE_POLL
+#undef HAVE_KQUEUE
+
+#undef HAVE_PCAP_SET_IMMEDIATE_MODE
diff --git a/nsock/include/nsock_winconfig.h b/nsock/include/nsock_winconfig.h
new file mode 100644
index 0000000..88ff5f4
--- /dev/null
+++ b/nsock/include/nsock_winconfig.h
@@ -0,0 +1,70 @@
+
+/***************************************************************************
+ * nsock_winconfig.h -- Since the Windows port is currently eschewing *
+ * autoconf-style configure scripts, nsock_winconfig.h contains the *
+ * platform-specific definitions for Windows and is used as a replacement *
+ * for config.h *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+#ifndef NSOCK_WINCONFIG_H
+#define NSOCK_WINCONFIG_H
+
+#ifndef DISABLE_NSOCK_PCAP
+#define HAVE_PCAP 1
+#endif
+
+/* Need this for _WIN32_WINNT below */
+#include <nbase.h>
+ /* WSAPoll() isn't available before Vista */
+#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
+#define HAVE_POLL 1
+#define HAVE_IOCP 1
+#endif
+
+#endif /* NSOCK_WINCONFIG_H */
diff --git a/nsock/nsock.vcxproj b/nsock/nsock.vcxproj
new file mode 100644
index 0000000..3ff0b9a
--- /dev/null
+++ b/nsock/nsock.vcxproj
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="DebugNoPcap|Win32">
+ <Configuration>DebugNoPcap</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="ReleaseNoPcap|Win32">
+ <Configuration>ReleaseNoPcap</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Static|Win32">
+ <Configuration>Static</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{F8D6D1E3-D4EA-402C-98AA-168E5309BAF4}</ProjectGuid>
+ <RootNamespace>nsock</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseNoPcap|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugNoPcap|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Static|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseNoPcap|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugNoPcap|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Static|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Debug\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\</OutDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Static|Win32'">.\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Release\</IntDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Static|Win32'">Release\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='DebugNoPcap|Win32'">$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='DebugNoPcap|Win32'">$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='ReleaseNoPcap|Win32'">$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='ReleaseNoPcap|Win32'">$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\nbase\;include;..\..\nmap-mswin32-aux\Npcap\Include;..\mswin32;..\;..\..\nmap-mswin32-aux\OpenSSL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <CompileAs>CompileAsCpp</CompileAs>
+ </ClCompile>
+ <Lib>
+ <OutputFile>$(OutDir)nsock.lib</OutputFile>
+ </Lib>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalOptions>/D "_CRT_SECURE_NO_DEPRECATE" %(AdditionalOptions)</AdditionalOptions>
+ <AdditionalIncludeDirectories>..\nbase\;include;..\..\nmap-mswin32-aux\Npcap\Include;..\mswin32;..\;..\..\nmap-mswin32-aux\OpenSSL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <CompileAs>CompileAsCpp</CompileAs>
+ </ClCompile>
+ <Lib>
+ <OutputFile>$(OutDir)nsock.lib</OutputFile>
+ <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
+ </Lib>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Static|Win32'">
+ <ClCompile>
+ <AdditionalOptions>/D "_CRT_SECURE_NO_DEPRECATE" %(AdditionalOptions)</AdditionalOptions>
+ <AdditionalIncludeDirectories>..\nbase\;include;..\..\nmap-mswin32-aux\Npcap\Include;..\mswin32;..\;..\..\nmap-mswin32-aux\OpenSSL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_LIB;%(PreprocessorDefinitions);DISABLE_NSOCK_PCAP</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <CompileAs>CompileAsCpp</CompileAs>
+ </ClCompile>
+ <Lib>
+ <OutputFile>$(OutDir)nsock.lib</OutputFile>
+ </Lib>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugNoPcap|Win32'">
+ <ClCompile>
+ <AdditionalOptions>/D "DISABLE_NSOCK_PCAP" %(AdditionalOptions)</AdditionalOptions>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\nbase\;include;..\..\nmap-mswin32-aux\Npcap\Include;..\mswin32;..\;..\..\nmap-mswin32-aux\OpenSSL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <CompileAs>CompileAsCpp</CompileAs>
+ </ClCompile>
+ <Lib>
+ <OutputFile>$(OutDir)nsock.lib</OutputFile>
+ </Lib>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseNoPcap|Win32'">
+ <ClCompile>
+ <AdditionalOptions>/D "_CRT_SECURE_NO_DEPRECATE"
+/D "DISABLE_NSOCK_PCAP" %(AdditionalOptions)</AdditionalOptions>
+ <AdditionalIncludeDirectories>..\nbase\;include;..\..\nmap-mswin32-aux\Npcap\Include;..\mswin32;..\;..\..\nmap-mswin32-aux\OpenSSL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <CompileAs>CompileAsCpp</CompileAs>
+ </ClCompile>
+ <Lib>
+ <OutputFile>$(OutDir)nsock.lib</OutputFile>
+ </Lib>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="src\engine_epoll.c" />
+ <ClCompile Include="src\engine_iocp.c" />
+ <ClCompile Include="src\engine_kqueue.c" />
+ <ClCompile Include="src\engine_poll.c" />
+ <ClCompile Include="src\engine_select.c" />
+ <ClCompile Include="src\error.c" />
+ <ClCompile Include="src\filespace.c" />
+ <ClCompile Include="src\gh_heap.c" />
+ <ClCompile Include="src\netutils.c" />
+ <ClCompile Include="src\nsock_connect.c" />
+ <ClCompile Include="src\nsock_core.c" />
+ <ClCompile Include="src\nsock_engines.c" />
+ <ClCompile Include="src\nsock_event.c" />
+ <ClCompile Include="src\nsock_iod.c" />
+ <ClCompile Include="src\nsock_log.c" />
+ <ClCompile Include="src\nsock_pcap.c" />
+ <ClCompile Include="src\nsock_pool.c" />
+ <ClCompile Include="src\nsock_proxy.c" />
+ <ClCompile Include="src\nsock_read.c" />
+ <ClCompile Include="src\nsock_ssl.c" />
+ <ClCompile Include="src\nsock_timers.c" />
+ <ClCompile Include="src\nsock_write.c" />
+ <ClCompile Include="src\proxy_http.c" />
+ <ClCompile Include="src\proxy_socks4.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\error.h" />
+ <ClInclude Include="src\filespace.h" />
+ <ClInclude Include="src\gh_heap.h" />
+ <ClInclude Include="src\gh_list.h" />
+ <ClInclude Include="src\netutils.h" />
+ <ClInclude Include="include\nsock.h" />
+ <ClInclude Include="src\nsock_internal.h" />
+ <ClInclude Include="src\nsock_log.h" />
+ <ClInclude Include="src\nsock_pcap.h" />
+ <ClInclude Include="src\nsock_proxy.h" />
+ <ClInclude Include="src\nsock_ssl.h" />
+ <ClInclude Include="include\nsock_winconfig.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\nbase\nbase.vcxproj">
+ <Project>{b630c8f7-3138-43e8-89ed-78742fa2ac5f}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/nsock/src/Makefile.in b/nsock/src/Makefile.in
new file mode 100644
index 0000000..569d999
--- /dev/null
+++ b/nsock/src/Makefile.in
@@ -0,0 +1,97 @@
+NSOCK_VERSION = 0.02
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+sbindir = @sbindir@
+mandir = @mandir@
+srcdir = @srcdir@
+datarootdir = @datarootdir@
+
+CC = @CC@
+AR = ar
+RANLIB = @RANLIB@
+CCOPT =
+DEFS = @DEFS@ -DNSOCK_VERSION=\"$(NSOCK_VERSION)\"
+# With GCC, add extra security checks to source code.
+DEFS += -D_FORTIFY_SOURCE=2
+INCLS = -I../include
+CFLAGS = @CFLAGS@ $(CCOPT)
+# CFLAGS = -g -Wall $(DEFS) $(INCLS)
+CPPFLAGS = @CPPFLAGS@ $(DEFS) $(INCLS)
+STATIC =
+SHTOOL = ./shtool
+INSTALL = $(SHTOOL) install
+MAKEDEPEND = @MAKEDEPEND@
+RPMTDIR=$(HOME)/rpmdir
+NBASEDIR=@NBASEDIR@
+NSOCKTESTDIR=@NSOCKTESTDIR@
+
+TARGET = libnsock.a
+
+SRCS = error.c filespace.c gh_heap.c nsock_connect.c nsock_core.c \
+ nsock_iod.c nsock_read.c nsock_timers.c nsock_write.c \
+ nsock_ssl.c nsock_event.c nsock_pool.c netutils.c nsock_pcap.c \
+ nsock_engines.c engine_select.c engine_epoll.c engine_kqueue.c \
+ engine_poll.c nsock_proxy.c nsock_log.c proxy_http.c proxy_socks4.c
+
+OBJS = error.o filespace.o gh_heap.o nsock_connect.o nsock_core.o \
+ nsock_iod.o nsock_read.o nsock_timers.o nsock_write.o \
+ nsock_ssl.o nsock_event.o nsock_pool.o netutils.o nsock_pcap.o \
+ nsock_engines.o engine_select.o engine_epoll.o engine_kqueue.o \
+ engine_poll.o nsock_proxy.o nsock_log.o proxy_http.o proxy_socks4.o
+
+DEPS = error.h filespace.h gh_list.h nsock_internal.h netutils.h nsock_pcap.h \
+ nsock_log.h nsock_proxy.h gh_heap.h ../include/nsock.h \
+ $(NBASEDIR)/libnbase.a
+
+.c.o:
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
+
+all: $(TARGET)
+
+$(TARGET): $(DEPS) $(OBJS)
+ rm -f $@
+ $(AR) cr $@ $(OBJS)
+ $(RANLIB) $@
+
+$(NBASEDIR)/libnbase.a: $(NBASEDIR)/Makefile
+ cd $(NBASEDIR) && $(MAKE)
+
+clean-test:
+ cd $(NSOCKTESTDIR) && $(MAKE) clean
+
+clean: clean-test
+ rm -f $(OBJS) $(TARGET)
+
+distclean: clean
+ rm -f Makefile makefile.dep config.log config.status ../include/nsock_config.h $(NSOCKTESTDIR)/Makefile
+
+depend:
+ $(MAKEDEPEND) $(INCLS) -s "# DO NOT DELETE" -- $(DEFS) -- $(SRCS)
+
+check:
+ cd $(NSOCKTESTDIR) && $(MAKE) && ./run_tests.sh
+
+${srcdir}/configure: configure.ac
+ cd ${srcdir} && autoconf
+
+# autoheader might not change config.h.in, so touch a stamp file.
+${srcdir}/config.h.in: stamp-h.in
+${srcdir}/stamp-h.in: configure.ac acconfig.h \
+ config.h.top config.h.bot
+ cd ${srcdir} && autoheader
+ echo timestamp > ${srcdir}/stamp-h.in
+
+config.h: stamp-h
+stamp-h: config.h.in config.status
+ ./config.status
+
+Makefile: Makefile.in config.status
+ ./config.status
+
+config.status: configure
+ ./config.status --recheck
+
+makefile.dep:
+ $(CC) -MM $(CPPFLAGS) $(SRCS) > $@
+-include makefile.dep
diff --git a/nsock/src/acinclude.m4 b/nsock/src/acinclude.m4
new file mode 100644
index 0000000..fc09664
--- /dev/null
+++ b/nsock/src/acinclude.m4
@@ -0,0 +1,119 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_have_epoll.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_HAVE_EPOLL([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# AX_HAVE_EPOLL_PWAIT([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# DESCRIPTION
+#
+# This macro determines whether the system supports the epoll I/O event
+# interface. A neat usage example would be:
+#
+# AX_HAVE_EPOLL(
+# [AX_CONFIG_FEATURE_ENABLE(epoll)],
+# [AX_CONFIG_FEATURE_DISABLE(epoll)])
+# AX_CONFIG_FEATURE(
+# [epoll], [This platform supports epoll(7)],
+# [HAVE_EPOLL], [This platform supports epoll(7).])
+#
+# The epoll interface was added to the Linux kernel in version 2.5.45, and
+# the macro verifies that a kernel newer than this is installed. This
+# check is somewhat unreliable if <linux/version.h> doesn't match the
+# running kernel, but it is necessary regardless, because glibc comes with
+# stubs for the epoll_create(), epoll_wait(), etc. that allow programs to
+# compile and link even if the kernel is too old; the problem would then
+# be detected only at runtime.
+#
+# Linux kernel version 2.6.19 adds the epoll_pwait() call in addition to
+# epoll_wait(). The availability of that function can be tested with the
+# second macro. Generally speaking, it is safe to assume that
+# AX_HAVE_EPOLL would succeed if AX_HAVE_EPOLL_PWAIT has, but not the
+# other way round.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Peter Simons <simons@cryp.to>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 10
+
+AC_DEFUN([AX_HAVE_EPOLL], [dnl
+ ax_have_epoll_cppflags="${CPPFLAGS}"
+ AC_CHECK_HEADER([linux/version.h], [CPPFLAGS="${CPPFLAGS} -DHAVE_LINUX_VERSION_H"])
+ AC_MSG_CHECKING([for Linux epoll(7) interface])
+ AC_CACHE_VAL([ax_cv_have_epoll], [dnl
+ AC_LINK_IFELSE([dnl
+ AC_LANG_PROGRAM([dnl
+#include <sys/epoll.h>
+#ifdef HAVE_LINUX_VERSION_H
+# include <linux/version.h>
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45)
+# error linux kernel version is too old to have epoll
+# endif
+#endif
+], [dnl
+int fd, rc;
+struct epoll_event ev;
+fd = epoll_create(128);
+rc = epoll_wait(fd, &ev, 1, 0);])],
+ [ax_cv_have_epoll=yes],
+ [ax_cv_have_epoll=no])])
+ CPPFLAGS="${ax_have_epoll_cppflags}"
+ AS_IF([test "${ax_cv_have_epoll}" = "yes"],
+ [AC_MSG_RESULT([yes])
+$1],[AC_MSG_RESULT([no])
+$2])
+])dnl
+
+AC_DEFUN([AX_HAVE_EPOLL_PWAIT], [dnl
+ ax_have_epoll_cppflags="${CPPFLAGS}"
+ AC_CHECK_HEADER([linux/version.h],
+ [CPPFLAGS="${CPPFLAGS} -DHAVE_LINUX_VERSION_H"])
+ AC_MSG_CHECKING([for Linux epoll(7) interface with signals extension])
+ AC_CACHE_VAL([ax_cv_have_epoll_pwait], [dnl
+ AC_LINK_IFELSE([dnl
+ AC_LANG_PROGRAM([dnl
+#ifdef HAVE_LINUX_VERSION_H
+# include <linux/version.h>
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+# error linux kernel version is too old to have epoll_pwait
+# endif
+#endif
+#include <sys/epoll.h>
+#include <signal.h>
+], [dnl
+int fd, rc;
+struct epoll_event ev;
+fd = epoll_create(128);
+rc = epoll_wait(fd, &ev, 1, 0);
+rc = epoll_pwait(fd, &ev, 1, 0, (sigset_t const *)(0));])],
+ [ax_cv_have_epoll_pwait=yes],
+ [ax_cv_have_epoll_pwait=no])])
+ CPPFLAGS="${ax_have_epoll_cppflags}"
+ AS_IF([test "${ax_cv_have_epoll_pwait}" = "yes"],
+ [AC_MSG_RESULT([yes])
+$1],[AC_MSG_RESULT([no])
+$2])
+])dnl
+
+AC_DEFUN([AX_HAVE_POLL], [dnl
+ AC_MSG_CHECKING([for poll(2)])
+ AC_CACHE_VAL([ax_cv_have_poll], [dnl
+ AC_LINK_IFELSE([dnl
+ AC_LANG_PROGRAM(
+ [#include <poll.h>],
+ [int rc; rc = poll((struct pollfd *)(0), 0, 0);])],
+ [ax_cv_have_poll=yes],
+ [ax_cv_have_poll=no])])
+ AS_IF([test "${ax_cv_have_poll}" = "yes"],
+ [AC_MSG_RESULT([yes])
+$1],[AC_MSG_RESULT([no])
+$2])
+])dnl
diff --git a/nsock/src/aclocal.m4 b/nsock/src/aclocal.m4
new file mode 100644
index 0000000..e798741
--- /dev/null
+++ b/nsock/src/aclocal.m4
@@ -0,0 +1,15 @@
+# generated automatically by aclocal 1.11.6 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
+# Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_include([acinclude.m4])
diff --git a/nsock/src/configure b/nsock/src/configure
new file mode 100755
index 0000000..2bf7194
--- /dev/null
+++ b/nsock/src/configure
@@ -0,0 +1,6298 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="nsock_core.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+NSOCKTESTDIR
+NBASEDIR
+LIBNBASE_LIBS
+OPENSSL_LIBS
+RANLIB
+LIBPCAP_LIBS
+EGREP
+GREP
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_localdirs
+with_libpcap
+with_openssl
+with_libnbase
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-localdirs Explicitly ask compiler to use /usr/local/{include,libs} if they exist
+ --with-libpcap=DIR Look for pcap headers in DIR/include.
+ --with-libpcap=included Always use version included with Nmap
+ --without-libpcap Disable pcap functions.
+ --with-openssl=DIR Use optional openssl libs and includes from
+ [DIR]/lib/ and [DIR]/include/openssl/)
+ --with-libnbase=DIR Look for nbase include/libs in DIR
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+if test "${top_nmap_srcdir+set}" != set; then
+ top_nmap_srcdir=../..
+ export top_nmap_srcdir
+fi
+
+ac_config_files="$ac_config_files Makefile ../tests/Makefile"
+
+
+ac_config_headers="$ac_config_headers ../include/nsock_config.h"
+
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+
+
+
+
+case "$host" in
+ *alpha-dec-osf*)
+
+$as_echo "#define DEC 1" >>confdefs.h
+
+ ;;
+ *-netbsd* | *-knetbsd*-gnu)
+
+$as_echo "#define NETBSD 1" >>confdefs.h
+
+ ;;
+ *-openbsd*)
+
+$as_echo "#define OPENBSD 1" >>confdefs.h
+
+ ;;
+ *-sgi-irix5*)
+ $as_echo "#define IRIX 1" >>confdefs.h
+
+ ;;
+ *-sgi-irix6*)
+ $as_echo "#define IRIX 1" >>confdefs.h
+
+ ;;
+ *-hpux*)
+
+$as_echo "#define HPUX 1" >>confdefs.h
+
+ ;;
+ *-solaris2.1[1-9]*)
+ $as_echo "#define SOLARIS 1" >>confdefs.h
+
+ # Solaris 11 and later use BPF packet capture rather than DLPI.
+
+$as_echo "#define SOLARIS_BPF_PCAP_CAPTURE 1" >>confdefs.h
+
+ ;;
+ *-solaris2.0*)
+ $as_echo "#define SOLARIS 1" >>confdefs.h
+
+ ;;
+ *-solaris2.[1-9][0-9]*)
+ $as_echo "#define SOLARIS 1" >>confdefs.h
+
+ ;;
+ *-solaris2.1*)
+ $as_echo "#define SOLARIS 1" >>confdefs.h
+
+ ;;
+ *-solaris2.2*)
+ $as_echo "#define SOLARIS 1" >>confdefs.h
+
+ ;;
+ *-solaris2.3*)
+ $as_echo "#define SOLARIS 1" >>confdefs.h
+
+ ;;
+ *-solaris2.4*)
+ $as_echo "#define SOLARIS 1" >>confdefs.h
+
+ ;;
+ *-solaris2.5.1)
+ $as_echo "#define SOLARIS 1" >>confdefs.h
+
+ ;;
+ *-solaris*)
+ $as_echo "#define SOLARIS 1" >>confdefs.h
+
+ ;;
+ *-sunos4*)
+
+$as_echo "#define SUNOS 1" >>confdefs.h
+
+ ;;
+ *-linux*)
+
+$as_echo "#define LINUX 1" >>confdefs.h
+
+ ;;
+ *-freebsd* | *-kfreebsd*-gnu | *-dragonfly*)
+
+$as_echo "#define FREEBSD 1" >>confdefs.h
+
+ ;;
+ *-bsdi*)
+
+$as_echo "#define BSDI 1" >>confdefs.h
+
+ ;;
+ *-apple-darwin*)
+
+$as_echo "#define MACOSX 1" >>confdefs.h
+
+ ;;
+esac
+
+
+
+# Check whether --with-localdirs was given.
+if test "${with_localdirs+set}" = set; then :
+ withval=$with_localdirs; case "$with_localdirs" in
+ yes)
+ user_localdirs=1
+ ;;
+ no)
+ user_localdirs=0
+ ;;
+ esac
+
+else
+ user_localdirs=0
+fi
+
+
+if test "$user_localdirs" = 1; then
+ if test -d /usr/local/lib; then
+ LDFLAGS="$LDFLAGS -L/usr/local/lib"
+ fi
+ if test -d /usr/local/include; then
+ CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+ fi
+fi
+
+have_libpcap=no
+
+# By default, search for pcap library
+test "${with_libpcap+set}" != "set" && with_libpcap=yes
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+# Check whether --with-libpcap was given.
+if test "${with_libpcap+set}" = set; then :
+ withval=$with_libpcap; case "$with_libpcap" in
+ yes)
+ ac_fn_c_check_header_mongrel "$LINENO" "pcap.h" "ac_cv_header_pcap_h" "$ac_includes_default"
+if test "x$ac_cv_header_pcap_h" = xyes; then :
+
+ have_libpcap=yes
+ LIBPCAP_LIBS=-lpcap
+fi
+
+
+ ;;
+ included)
+ have_libpcap=no
+ ;;
+ no)
+ ;;
+ *)
+ _cppflags=$CPPFLAGS
+ _ldflags=$LDFLAGS
+
+ CPPFLAGS="-I$with_libpcap/include $CPPFLAGS"
+ LDFLAGS="-L$with_libpcap/lib $LDFLAGS"
+
+ ac_fn_c_check_header_mongrel "$LINENO" "pcap.h" "ac_cv_header_pcap_h" "$ac_includes_default"
+if test "x$ac_cv_header_pcap_h" = xyes; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_create in -lpcap" >&5
+$as_echo_n "checking for pcap_create in -lpcap... " >&6; }
+if ${ac_cv_lib_pcap_pcap_create+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpcap $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pcap_create ();
+int
+main ()
+{
+return pcap_create ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_pcap_pcap_create=yes
+else
+ ac_cv_lib_pcap_pcap_create=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcap_pcap_create" >&5
+$as_echo "$ac_cv_lib_pcap_pcap_create" >&6; }
+if test "x$ac_cv_lib_pcap_pcap_create" = xyes; then :
+ have_libpcap=yes
+ LIBPCAP_LIBS=-lpcap
+ LIBPCAP_INC=$with_libpcap/include
+ LIBPCAP_LIB=$with_libpcap/lib
+fi
+
+fi
+
+
+
+ LDFLAGS=$_ldflags
+ CPPFLAGS=$_cppflags
+ ;;
+ esac
+
+fi
+
+
+if test "$with_libpcap" != "no" -a "$have_libpcap" = "no"; then
+ LIBPCAP_INC=${top_nmap_srcdir}/libpcap
+ LIBPCAP_LIB=${top_nmap_srcdir}/libpcap
+ LIBPCAP_LIBS=${LIBPCAP_LIB}/libpcap.a
+ have_libpcap=yes
+
+$as_echo "#define HAVE_PCAP_SET_IMMEDIATE_MODE 1" >>confdefs.h
+
+else
+ # link with -lpcap for the purposes of this test
+ LIBS_OLD="$LIBS"
+ LIBS="$LIBS -lpcap"
+ for ac_func in pcap_set_immediate_mode
+do :
+ ac_fn_c_check_func "$LINENO" "pcap_set_immediate_mode" "ac_cv_func_pcap_set_immediate_mode"
+if test "x$ac_cv_func_pcap_set_immediate_mode" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_PCAP_SET_IMMEDIATE_MODE 1
+_ACEOF
+
+fi
+done
+
+ # Restore libs
+ LIBS="$LIBS_OLD"
+fi
+
+if test "$have_libpcap" != "no"; then
+
+$as_echo "#define HAVE_PCAP 1" >>confdefs.h
+
+ if test "${LIBPCAP_INC+set}" = "set"; then
+ CPPFLAGS="-I$LIBPCAP_INC $CPPFLAGS"
+ LDFLAGS="-L$LIBPCAP_LIB $LDFLAGS"
+ fi
+fi
+
+
+ ax_have_epoll_cppflags="${CPPFLAGS}"
+ ac_fn_c_check_header_mongrel "$LINENO" "linux/version.h" "ac_cv_header_linux_version_h" "$ac_includes_default"
+if test "x$ac_cv_header_linux_version_h" = xyes; then :
+ CPPFLAGS="${CPPFLAGS} -DHAVE_LINUX_VERSION_H"
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux epoll(7) interface" >&5
+$as_echo_n "checking for Linux epoll(7) interface... " >&6; }
+ if ${ax_cv_have_epoll+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+ #include <sys/epoll.h>
+#ifdef HAVE_LINUX_VERSION_H
+# include <linux/version.h>
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45)
+# error linux kernel version is too old to have epoll
+# endif
+#endif
+
+int
+main ()
+{
+int fd, rc;
+struct epoll_event ev;
+fd = epoll_create(128);
+rc = epoll_wait(fd, &ev, 1, 0);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ax_cv_have_epoll=yes
+else
+ ax_cv_have_epoll=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+ CPPFLAGS="${ax_have_epoll_cppflags}"
+ if test "${ax_cv_have_epoll}" = "yes"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_EPOLL 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for poll(2)" >&5
+$as_echo_n "checking for poll(2)... " >&6; }
+ if ${ax_cv_have_poll+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+ #include <poll.h>
+int
+main ()
+{
+int rc; rc = poll((struct pollfd *)(0), 0, 0);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ax_cv_have_poll=yes
+else
+ ax_cv_have_poll=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+ if test "${ax_cv_have_poll}" = "yes"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_POLL 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+
+for ac_func in kqueue kevent
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ $as_echo "#define HAVE_KQUEUE 1" >>confdefs.h
+
+fi
+done
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ if test -n "$GCC"; then
+ CFLAGS="$CFLAGS -Wall "
+ fi
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+
+
+ac_fn_c_check_func "$LINENO" "gethostent" "ac_cv_func_gethostent"
+if test "x$ac_cv_func_gethostent" = xyes; then :
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostent in -lnsl" >&5
+$as_echo_n "checking for gethostent in -lnsl... " >&6; }
+if ${ac_cv_lib_nsl_gethostent+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostent ();
+int
+main ()
+{
+return gethostent ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_nsl_gethostent=yes
+else
+ ac_cv_lib_nsl_gethostent=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostent" >&5
+$as_echo "$ac_cv_lib_nsl_gethostent" >&6; }
+if test "x$ac_cv_lib_nsl_gethostent" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNSL 1
+_ACEOF
+
+ LIBS="-lnsl $LIBS"
+
+fi
+
+fi
+
+ac_fn_c_check_func "$LINENO" "setsockopt" "ac_cv_func_setsockopt"
+if test "x$ac_cv_func_setsockopt" = xyes; then :
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setsockopt in -lsocket" >&5
+$as_echo_n "checking for setsockopt in -lsocket... " >&6; }
+if ${ac_cv_lib_socket_setsockopt+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char setsockopt ();
+int
+main ()
+{
+return setsockopt ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_socket_setsockopt=yes
+else
+ ac_cv_lib_socket_setsockopt=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_setsockopt" >&5
+$as_echo "$ac_cv_lib_socket_setsockopt" >&6; }
+if test "x$ac_cv_lib_socket_setsockopt" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+ LIBS="-lsocket $LIBS"
+
+fi
+
+fi
+
+
+ac_fn_c_check_func "$LINENO" "nanosleep" "ac_cv_func_nanosleep"
+if test "x$ac_cv_func_nanosleep" = xyes; then :
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nanosleep in -lposix4" >&5
+$as_echo_n "checking for nanosleep in -lposix4... " >&6; }
+if ${ac_cv_lib_posix4_nanosleep+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lposix4 $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char nanosleep ();
+int
+main ()
+{
+return nanosleep ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_posix4_nanosleep=yes
+else
+ ac_cv_lib_posix4_nanosleep=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix4_nanosleep" >&5
+$as_echo "$ac_cv_lib_posix4_nanosleep" >&6; }
+if test "x$ac_cv_lib_posix4_nanosleep" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPOSIX4 1
+_ACEOF
+
+ LIBS="-lposix4 $LIBS"
+
+fi
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+for ac_header in net/bpf.h sys/ioctl.h sys/un.h netdb.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in linux/vm_sockets.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "linux/vm_sockets.h" "ac_cv_header_linux_vm_sockets_h" "#include <sys/socket.h>
+"
+if test "x$ac_cv_header_linux_vm_sockets_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LINUX_VM_SOCKETS_H 1
+_ACEOF
+
+fi
+
+done
+
+
+# We test whether they specified openssl desires explicitly
+use_openssl="yes"
+specialssldir=""
+
+# Check whether --with-openssl was given.
+if test "${with_openssl+set}" = set; then :
+ withval=$with_openssl; case "$with_openssl" in
+ yes)
+ ;;
+ no)
+ use_openssl="no"
+ ;;
+ *)
+ specialssldir="$with_openssl"
+ CPPFLAGS="$CPPFLAGS -I$with_openssl/include"
+ LDFLAGS="$LDFLAGS -L$with_openssl/lib"
+ ;;
+ esac
+
+fi
+
+
+# If they didn't specify it, we try to find it
+if test "$use_openssl" = "yes" -a -z "$specialssldir"; then
+ ac_fn_c_check_header_mongrel "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default"
+if test "x$ac_cv_header_openssl_ssl_h" = xyes; then :
+
+else
+ use_openssl="no"
+ if test "$with_openssl" = "yes"; then
+ as_fn_error $? "OpenSSL was explicitly requested but openssl/ssl.h was not found. Try the --with-openssl=DIR argument to give the location of OpenSSL or run configure with --without-openssl." "$LINENO" 5
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Failed to find openssl/ssl.h so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument" >&5
+$as_echo "$as_me: WARNING: Failed to find openssl/ssl.h so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument" >&2;}
+
+fi
+
+
+
+# use_openssl="yes" given explicitly in next 2 rules to avoid adding lib to $LIBS
+ if test "$use_openssl" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BIO_int_ctrl in -lcrypto" >&5
+$as_echo_n "checking for BIO_int_ctrl in -lcrypto... " >&6; }
+if ${ac_cv_lib_crypto_BIO_int_ctrl+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char BIO_int_ctrl ();
+int
+main ()
+{
+return BIO_int_ctrl ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_crypto_BIO_int_ctrl=yes
+else
+ ac_cv_lib_crypto_BIO_int_ctrl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_BIO_int_ctrl" >&5
+$as_echo "$ac_cv_lib_crypto_BIO_int_ctrl" >&6; }
+if test "x$ac_cv_lib_crypto_BIO_int_ctrl" = xyes; then :
+ use_openssl="yes"
+else
+ use_openssl="no"
+ if test "$with_openssl" = "yes"; then
+ as_fn_error $? "OpenSSL was explicitly requested but libcrypto was not found. Try the --with-openssl=DIR argument to give the location of OpenSSL or run configure with --without-openssl." "$LINENO" 5
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Failed to find libcrypto so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument" >&5
+$as_echo "$as_me: WARNING: Failed to find libcrypto so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument" >&2;}
+
+fi
+
+ fi
+
+ if test "$use_openssl" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_new in -lssl" >&5
+$as_echo_n "checking for SSL_new in -lssl... " >&6; }
+if ${ac_cv_lib_ssl_SSL_new+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl -lcrypto $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char SSL_new ();
+int
+main ()
+{
+return SSL_new ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ssl_SSL_new=yes
+else
+ ac_cv_lib_ssl_SSL_new=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_new" >&5
+$as_echo "$ac_cv_lib_ssl_SSL_new" >&6; }
+if test "x$ac_cv_lib_ssl_SSL_new" = xyes; then :
+ use_openssl="yes"
+else
+ use_openssl="no"
+ if test "$with_openssl" = "yes"; then
+ as_fn_error $? "OpenSSL was explicitly requested but libssl was not found. Try the --with-openssl=DIR argument to give the location of OpenSSL or run configure with --without-openssl." "$LINENO" 5
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Failed to find libssl so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument" >&5
+$as_echo "$as_me: WARNING: Failed to find libssl so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument" >&2;}
+fi
+
+ fi
+fi
+
+# OpenSSL requires dlopen on some platforms
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5
+$as_echo_n "checking for library containing dlopen... " >&6; }
+if ${ac_cv_search_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' dl; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_dlopen=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_dlopen+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_dlopen+:} false; then :
+
+else
+ ac_cv_search_dlopen=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5
+$as_echo "$ac_cv_search_dlopen" >&6; }
+ac_res=$ac_cv_search_dlopen
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+
+OPENSSL_LIBS=
+if test "$use_openssl" = "yes"; then
+
+$as_echo "#define HAVE_OPENSSL 1" >>confdefs.h
+
+ OPENSSL_LIBS="-lssl -lcrypto"
+ LIBS_TMP="$LIBS"
+ LIBS="$OPENSSL_LIBS $LIBS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_set_tlsext_host_name" >&5
+$as_echo_n "checking for SSL_set_tlsext_host_name... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <openssl/ssl.h>
+int
+main ()
+{
+SSL_set_tlsext_host_name(NULL, NULL)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };
+$as_echo "#define HAVE_SSL_SET_TLSEXT_HOST_NAME 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DTLS_client_method" >&5
+$as_echo_n "checking for DTLS_client_method... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <openssl/ssl.h>
+int
+main ()
+{
+DTLS_client_method()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };
+$as_echo "#define HAVE_DTLS_CLIENT_METHOD 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_set_alpn_protos" >&5
+$as_echo_n "checking for SSL_set_alpn_protos... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <openssl/ssl.h>
+int
+main ()
+{
+SSL_set_alpn_protos(NULL, NULL, 0)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };
+$as_echo "#define HAVE_ALPN_SUPPORT 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$LIBS_TMP"
+
+fi
+
+
+
+
+
+# Check whether --with-libnbase was given.
+if test "${with_libnbase+set}" = set; then :
+ withval=$with_libnbase; case "$with_libnbase" in
+ yes)
+ ;;
+ *)
+ NBASEDIR="$with_libnbase"
+ ;;
+ esac
+else
+ NBASEDIR="${top_nmap_srcdir}/nbase"
+
+fi
+
+
+NSOCKTESTDIR="../tests"
+
+LDFLAGS="$LDFLAGS -L$NBASEDIR"
+CPPFLAGS="$CPPFLAGS -I$NBASEDIR"
+LIBNBASE_LIBS="$LIBS -lnbase"
+
+
+
+
+
+
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "../tests/Makefile") CONFIG_FILES="$CONFIG_FILES ../tests/Makefile" ;;
+ "../include/nsock_config.h") CONFIG_HEADERS="$CONFIG_HEADERS ../include/nsock_config.h" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+ ;;
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/nsock/src/configure.ac b/nsock/src/configure.ac
new file mode 100644
index 0000000..1f035cf
--- /dev/null
+++ b/nsock/src/configure.ac
@@ -0,0 +1,317 @@
+# Require autoconf 2.13 -*- mode: fundamental; -*-
+
+# Because nsock is usually distributed with Nmap, the necessary files
+# config.guess, config.guess, and install-sh are not distributed with
+# nbase. Rather they are gotten from Nmap.
+
+AC_PREREQ(2.13)
+
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(nsock_core.c)
+
+dnl Find the Nmap source for nbase, etc.
+if test "${top_nmap_srcdir+set}" != set; then
+ top_nmap_srcdir=../..
+ export top_nmap_srcdir
+fi
+
+dnl Generate these files
+AC_CONFIG_FILES([Makefile ../tests/Makefile])
+
+dnl use nsock_config.h instad of -D macros
+AC_CONFIG_HEADER(../include/nsock_config.h)
+
+dnl Host specific hacks
+AC_CANONICAL_HOST
+
+AH_TEMPLATE(SOLARIS, [Sun/Oracle Solaris])
+AH_TEMPLATE(IRIX, [IRIX])
+
+case "$host" in
+ *alpha-dec-osf*)
+ AC_DEFINE(DEC, 1, [DEC Alpha])
+ ;;
+ *-netbsd* | *-knetbsd*-gnu)
+ AC_DEFINE(NETBSD, 1, [NetBSD])
+ ;;
+ *-openbsd*)
+ AC_DEFINE(OPENBSD, 1, [OpenBSD])
+ ;;
+ *-sgi-irix5*)
+ AC_DEFINE(IRIX)
+ ;;
+ *-sgi-irix6*)
+ AC_DEFINE(IRIX)
+ ;;
+ *-hpux*)
+ AC_DEFINE(HPUX, 1, [HP-UX])
+ ;;
+ *-solaris2.1[[1-9]]*)
+ AC_DEFINE(SOLARIS)
+ # Solaris 11 and later use BPF packet capture rather than DLPI.
+ AC_DEFINE(SOLARIS_BPF_PCAP_CAPTURE, 1, [BPF packet capture on Solaris])
+ ;;
+ *-solaris2.0*)
+ AC_DEFINE(SOLARIS)
+ ;;
+ *-solaris2.[[1-9]][[0-9]]*)
+ AC_DEFINE(SOLARIS)
+ ;;
+ *-solaris2.1*)
+ AC_DEFINE(SOLARIS)
+ ;;
+ *-solaris2.2*)
+ AC_DEFINE(SOLARIS)
+ ;;
+ *-solaris2.3*)
+ AC_DEFINE(SOLARIS)
+ ;;
+ *-solaris2.4*)
+ AC_DEFINE(SOLARIS)
+ ;;
+ *-solaris2.5.1)
+ AC_DEFINE(SOLARIS)
+ ;;
+ *-solaris*)
+ AC_DEFINE(SOLARIS)
+ ;;
+ *-sunos4*)
+ AC_DEFINE(SUNOS, 1, [SunOS 4])
+ ;;
+ *-linux*)
+ AC_DEFINE(LINUX, 1, [Linux])
+ ;;
+ *-freebsd* | *-kfreebsd*-gnu | *-dragonfly*)
+ AC_DEFINE(FREEBSD, 1, [FreeBSD])
+ ;;
+ *-bsdi*)
+ AC_DEFINE(BSDI, 1, [BSD/OS])
+ ;;
+ *-apple-darwin*)
+ AC_DEFINE(MACOSX, 1, [Apple OS X])
+ ;;
+esac
+
+
+AC_ARG_WITH(localdirs,
+ [ --with-localdirs Explicitly ask compiler to use /usr/local/{include,libs} if they exist ],
+ [ case "$with_localdirs" in
+ yes)
+ user_localdirs=1
+ ;;
+ no)
+ user_localdirs=0
+ ;;
+ esac
+ ],
+ [ user_localdirs=0 ] )
+
+if test "$user_localdirs" = 1; then
+ if test -d /usr/local/lib; then
+ LDFLAGS="$LDFLAGS -L/usr/local/lib"
+ fi
+ if test -d /usr/local/include; then
+ CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+ fi
+fi
+
+dnl Check whether libpcap is already available
+have_libpcap=no
+
+# By default, search for pcap library
+test "${with_libpcap+set}" != "set" && with_libpcap=yes
+
+AC_ARG_WITH(libpcap,
+AC_HELP_STRING([--with-libpcap=DIR], [Look for pcap headers in DIR/include.])
+AC_HELP_STRING([--with-libpcap=included], [Always use version included with Nmap])
+AC_HELP_STRING([--without-libpcap], [Disable pcap functions.]),
+[ case "$with_libpcap" in
+ yes)
+ AC_CHECK_HEADER(pcap.h,[
+ have_libpcap=yes
+ LIBPCAP_LIBS=-lpcap ])
+ ;;
+ included)
+ have_libpcap=no
+ ;;
+ no)
+ ;;
+ *)
+ _cppflags=$CPPFLAGS
+ _ldflags=$LDFLAGS
+
+ CPPFLAGS="-I$with_libpcap/include $CPPFLAGS"
+ LDFLAGS="-L$with_libpcap/lib $LDFLAGS"
+
+ AC_CHECK_HEADER(pcap.h,[
+ AC_CHECK_LIB(pcap, pcap_create,
+ [have_libpcap=yes
+ LIBPCAP_LIBS=-lpcap
+ LIBPCAP_INC=$with_libpcap/include
+ LIBPCAP_LIB=$with_libpcap/lib])])
+
+ LDFLAGS=$_ldflags
+ CPPFLAGS=$_cppflags
+ ;;
+ esac]
+)
+
+if test "$with_libpcap" != "no" -a "$have_libpcap" = "no"; then
+ LIBPCAP_INC=${top_nmap_srcdir}/libpcap
+ LIBPCAP_LIB=${top_nmap_srcdir}/libpcap
+ LIBPCAP_LIBS=${LIBPCAP_LIB}/libpcap.a
+ have_libpcap=yes
+ AC_DEFINE(HAVE_PCAP_SET_IMMEDIATE_MODE, 1, [Included libpcap has pcap_set_immediate_mode])
+else
+ # link with -lpcap for the purposes of this test
+ LIBS_OLD="$LIBS"
+ LIBS="$LIBS -lpcap"
+ AC_CHECK_FUNCS([pcap_set_immediate_mode])
+ # Restore libs
+ LIBS="$LIBS_OLD"
+fi
+
+if test "$have_libpcap" != "no"; then
+ AC_DEFINE(HAVE_PCAP, 1, [libpcap is available])
+ if test "${LIBPCAP_INC+set}" = "set"; then
+ CPPFLAGS="-I$LIBPCAP_INC $CPPFLAGS"
+ LDFLAGS="-L$LIBPCAP_LIB $LDFLAGS"
+ fi
+fi
+AC_SUBST(LIBPCAP_LIBS)
+
+AX_HAVE_EPOLL([AC_DEFINE(HAVE_EPOLL, 1, [epoll is available])], )
+AX_HAVE_POLL([AC_DEFINE(HAVE_POLL, 1, [poll is available])], )
+AC_CHECK_FUNCS(kqueue kevent, [AC_DEFINE(HAVE_KQUEUE)], )
+
+dnl Checks for programs.
+AC_PROG_CC
+ if test -n "$GCC"; then
+ CFLAGS="$CFLAGS -Wall "
+ fi
+AC_PROG_RANLIB
+dnl AC_PROG_INSTALL
+dnl AC_PATH_PROG(MAKEDEPEND, makedepend)
+
+dnl Checks for libraries.
+dnl AC_CHECK_LIB(m, pow)
+
+dnl If any socket libraries needed
+AC_CHECK_FUNC(gethostent, , AC_CHECK_LIB(nsl, gethostent))
+AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt))
+
+dnl need posix4/nanosleep for solaris 2.4
+AC_CHECK_FUNC(nanosleep, , AC_CHECK_LIB(posix4, nanosleep))
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(net/bpf.h sys/ioctl.h sys/un.h netdb.h)
+AC_CHECK_HEADERS([linux/vm_sockets.h], , , [#include <sys/socket.h>])
+
+# We test whether they specified openssl desires explicitly
+use_openssl="yes"
+specialssldir=""
+AC_ARG_WITH(openssl,
+AC_HELP_STRING([--with-openssl=DIR],[Use optional openssl libs and includes from [DIR]/lib/ and [DIR]/include/openssl/)]),
+[ case "$with_openssl" in
+ yes)
+ ;;
+ no)
+ use_openssl="no"
+ ;;
+ *)
+ specialssldir="$with_openssl"
+ CPPFLAGS="$CPPFLAGS -I$with_openssl/include"
+ LDFLAGS="$LDFLAGS -L$with_openssl/lib"
+ ;;
+ esac]
+)
+
+# If they didn't specify it, we try to find it
+if test "$use_openssl" = "yes" -a -z "$specialssldir"; then
+ AC_CHECK_HEADER(openssl/ssl.h,,
+ [ use_openssl="no"
+ if test "$with_openssl" = "yes"; then
+ AC_MSG_ERROR([OpenSSL was explicitly requested but openssl/ssl.h was not found. Try the --with-openssl=DIR argument to give the location of OpenSSL or run configure with --without-openssl.])
+ fi
+ AC_MSG_WARN([Failed to find openssl/ssl.h so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument])
+ ])
+
+# use_openssl="yes" given explicitly in next 2 rules to avoid adding lib to $LIBS
+ if test "$use_openssl" = "yes"; then
+ AC_CHECK_LIB(crypto, BIO_int_ctrl,
+ [ use_openssl="yes"],
+ [ use_openssl="no"
+ if test "$with_openssl" = "yes"; then
+ AC_MSG_ERROR([OpenSSL was explicitly requested but libcrypto was not found. Try the --with-openssl=DIR argument to give the location of OpenSSL or run configure with --without-openssl.])
+ fi
+ AC_MSG_WARN([Failed to find libcrypto so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument])
+ ])
+ fi
+
+ if test "$use_openssl" = "yes"; then
+ AC_CHECK_LIB(ssl, SSL_new,
+ [ use_openssl="yes" ],
+ [ use_openssl="no"
+ if test "$with_openssl" = "yes"; then
+ AC_MSG_ERROR([OpenSSL was explicitly requested but libssl was not found. Try the --with-openssl=DIR argument to give the location of OpenSSL or run configure with --without-openssl.])
+ fi
+ AC_MSG_WARN([Failed to find libssl so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument]) ],
+ [ -lcrypto ])
+ fi
+fi
+
+# OpenSSL requires dlopen on some platforms
+AC_SEARCH_LIBS(dlopen, dl)
+
+OPENSSL_LIBS=
+if test "$use_openssl" = "yes"; then
+ AC_DEFINE(HAVE_OPENSSL, 1, [openssl is available])
+ OPENSSL_LIBS="-lssl -lcrypto"
+ LIBS_TMP="$LIBS"
+ LIBS="$OPENSSL_LIBS $LIBS"
+ AC_MSG_CHECKING([for SSL_set_tlsext_host_name])
+ AC_TRY_LINK([#include <openssl/ssl.h>], [SSL_set_tlsext_host_name(NULL, NULL)],
+ [AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_SSL_SET_TLSEXT_HOST_NAME, 1, [SSL_set_tlsext_host_name available])],
+ [AC_MSG_RESULT([no])])
+ AC_MSG_CHECKING([for DTLS_client_method])
+ AC_TRY_LINK([#include <openssl/ssl.h>], [DTLS_client_method()],
+ [AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_DTLS_CLIENT_METHOD, 1, [DTLS_client_method available])],
+ [AC_MSG_RESULT([no])])
+ AC_MSG_CHECKING([for SSL_set_alpn_protos])
+ AC_TRY_LINK([#include <openssl/ssl.h>], [SSL_set_alpn_protos(NULL, NULL, 0)],
+ [AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_ALPN_SUPPORT, 1, [SSL ALPN protos support])],
+ [AC_MSG_RESULT([no])])
+ LIBS="$LIBS_TMP"
+
+fi
+
+AC_SUBST(OPENSSL_LIBS)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+
+AC_ARG_WITH(libnbase,
+[ --with-libnbase=DIR Look for nbase include/libs in DIR],
+[ case "$with_libnbase" in
+ yes)
+ ;;
+ *)
+ NBASEDIR="$with_libnbase"
+ ;;
+ esac],
+NBASEDIR="${top_nmap_srcdir}/nbase"
+)
+
+NSOCKTESTDIR="../tests"
+
+LDFLAGS="$LDFLAGS -L$NBASEDIR"
+CPPFLAGS="$CPPFLAGS -I$NBASEDIR"
+LIBNBASE_LIBS="$LIBS -lnbase"
+
+AC_SUBST(LIBNBASE_LIBS)
+AC_SUBST(NBASEDIR)
+AC_SUBST(NSOCKTESTDIR)
+
+AC_SUBST(CFLAGS)
+
+AC_OUTPUT()
diff --git a/nsock/src/engine_epoll.c b/nsock/src/engine_epoll.c
new file mode 100644
index 0000000..1bc285c
--- /dev/null
+++ b/nsock/src/engine_epoll.c
@@ -0,0 +1,354 @@
+/***************************************************************************
+ * engine_epoll.c -- epoll(7) based IO engine. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "nsock_config.h"
+#endif
+
+#if HAVE_EPOLL
+
+#include <sys/epoll.h>
+#include <errno.h>
+
+#include "nsock_internal.h"
+#include "nsock_log.h"
+
+#if HAVE_PCAP
+#include "nsock_pcap.h"
+#endif
+
+#define INITIAL_EV_COUNT 128
+
+#define EPOLL_R_FLAGS (EPOLLIN | EPOLLPRI)
+#define EPOLL_W_FLAGS EPOLLOUT
+
+/* EPOLLRDHUP was introduced later and might be unavailable on older systems. */
+#ifndef EPOLLRDHUP
+ #define EPOLLRDHUP 0
+#endif
+#define EPOLL_X_FLAGS (EPOLLERR | EPOLLRDHUP| EPOLLHUP)
+
+
+/* --- ENGINE INTERFACE PROTOTYPES --- */
+static int epoll_init(struct npool *nsp);
+static void epoll_destroy(struct npool *nsp);
+static int epoll_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev);
+static int epoll_iod_unregister(struct npool *nsp, struct niod *iod);
+static int epoll_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr);
+static int epoll_loop(struct npool *nsp, int msec_timeout);
+
+extern struct io_operations posix_io_operations;
+
+/* ---- ENGINE DEFINITION ---- */
+struct io_engine engine_epoll = {
+ "epoll",
+ epoll_init,
+ epoll_destroy,
+ epoll_iod_register,
+ epoll_iod_unregister,
+ epoll_iod_modify,
+ epoll_loop,
+ &posix_io_operations
+};
+
+
+/* --- INTERNAL PROTOTYPES --- */
+static void iterate_through_event_lists(struct npool *nsp, int evcount);
+
+/* defined in nsock_core.c */
+void process_iod_events(struct npool *nsp, struct niod *nsi, int ev);
+void process_event(struct npool *nsp, gh_list_t *evlist, struct nevent *nse, int ev);
+void process_expired_events(struct npool *nsp);
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+int pcap_read_on_nonselect(struct npool *nsp);
+#endif
+#endif
+
+/* defined in nsock_event.c */
+void update_first_events(struct nevent *nse);
+
+
+extern struct timeval nsock_tod;
+
+
+/*
+ * Engine specific data structure
+ */
+struct epoll_engine_info {
+ /* file descriptor corresponding to our epoll instance */
+ int epfd;
+ /* number of epoll_events we can deal with */
+ int evlen;
+ /* list of epoll events, resized if necessary (when polling over large numbers of IODs) */
+ struct epoll_event *events;
+};
+
+
+int epoll_init(struct npool *nsp) {
+ struct epoll_engine_info *einfo;
+
+ einfo = (struct epoll_engine_info *)safe_malloc(sizeof(struct epoll_engine_info));
+
+ einfo->epfd = epoll_create(10); /* argument is ignored */
+ einfo->evlen = INITIAL_EV_COUNT;
+ einfo->events = (struct epoll_event *)safe_malloc(einfo->evlen * sizeof(struct epoll_event));
+
+ nsp->engine_data = (void *)einfo;
+
+ return 1;
+}
+
+void epoll_destroy(struct npool *nsp) {
+ struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data;
+
+ assert(einfo != NULL);
+ close(einfo->epfd);
+ free(einfo->events);
+ free(einfo);
+}
+
+int epoll_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev) {
+ int sd;
+ struct epoll_event epev;
+ struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data;
+
+ assert(!IOD_PROPGET(iod, IOD_REGISTERED));
+
+ iod->watched_events = ev;
+
+ memset(&epev, 0x00, sizeof(struct epoll_event));
+ epev.events = EPOLLET;
+ epev.data.ptr = (void *)iod;
+
+ if (ev & EV_READ)
+ epev.events |= EPOLL_R_FLAGS;
+ if (ev & EV_WRITE)
+ epev.events |= EPOLL_W_FLAGS;
+
+ sd = nsock_iod_get_sd(iod);
+ if (epoll_ctl(einfo->epfd, EPOLL_CTL_ADD, sd, &epev) < 0)
+ fatal("Unable to register IOD #%lu: %s", iod->id, strerror(errno));
+
+ IOD_PROPSET(iod, IOD_REGISTERED);
+ return 1;
+}
+
+int epoll_iod_unregister(struct npool *nsp, struct niod *iod) {
+ iod->watched_events = EV_NONE;
+
+ /* some IODs can be unregistered here if they're associated to an event that was
+ * immediately completed */
+ if (IOD_PROPGET(iod, IOD_REGISTERED)) {
+ struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data;
+ int sd;
+
+ sd = nsock_iod_get_sd(iod);
+ epoll_ctl(einfo->epfd, EPOLL_CTL_DEL, sd, NULL);
+
+ IOD_PROPCLR(iod, IOD_REGISTERED);
+ }
+ return 1;
+}
+
+int epoll_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr) {
+ int sd;
+ struct epoll_event epev;
+ int new_events;
+ struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data;
+
+ assert((ev_set & ev_clr) == 0);
+ assert(IOD_PROPGET(iod, IOD_REGISTERED));
+
+ memset(&epev, 0x00, sizeof(struct epoll_event));
+ epev.events = EPOLLET;
+ epev.data.ptr = (void *)iod;
+
+ new_events = iod->watched_events;
+ new_events |= ev_set;
+ new_events &= ~ev_clr;
+
+ if (new_events == iod->watched_events)
+ return 1; /* nothing to do */
+
+ iod->watched_events = new_events;
+
+ /* regenerate the current set of events for this IOD */
+ if (iod->watched_events & EV_READ)
+ epev.events |= EPOLL_R_FLAGS;
+ if (iod->watched_events & EV_WRITE)
+ epev.events |= EPOLL_W_FLAGS;
+
+ sd = nsock_iod_get_sd(iod);
+
+ if (epoll_ctl(einfo->epfd, EPOLL_CTL_MOD, sd, &epev) < 0)
+ fatal("Unable to update events for IOD #%lu: %s", iod->id, strerror(errno));
+
+ return 1;
+}
+
+int epoll_loop(struct npool *nsp, int msec_timeout) {
+ int results_left = 0;
+ int event_msecs; /* msecs before an event goes off */
+ int combined_msecs;
+ int sock_err = 0;
+ unsigned int iod_count;
+ struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data;
+
+ assert(msec_timeout >= -1);
+
+ if (nsp->events_pending == 0)
+ return 0; /* No need to wait on 0 events ... */
+
+
+ iod_count = gh_list_count(&nsp->active_iods);
+ if (iod_count > einfo->evlen) {
+ einfo->evlen = iod_count * 2;
+ einfo->events = (struct epoll_event *)safe_realloc(einfo->events, einfo->evlen * sizeof(struct epoll_event));
+ }
+
+ do {
+ struct nevent *nse;
+
+ nsock_log_debug_all("wait for events");
+
+ nse = next_expirable_event(nsp);
+ if (!nse)
+ event_msecs = -1; /* None of the events specified a timeout */
+ else
+ event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod));
+
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+ /* Force a low timeout when capturing packets on systems where
+ * the pcap descriptor is not select()able. */
+ if (gh_list_count(&nsp->pcap_read_events) > 0)
+ if (event_msecs > PCAP_POLL_INTERVAL)
+ event_msecs = PCAP_POLL_INTERVAL;
+#endif
+#endif
+
+ /* We cast to unsigned because we want -1 to be very high (since it means no
+ * timeout) */
+ combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout);
+
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+ /* do non-blocking read on pcap devices that doesn't support select()
+ * If there is anything read, just leave this loop. */
+ if (pcap_read_on_nonselect(nsp)) {
+ /* okay, something was read. */
+ } else
+#endif
+#endif
+ {
+ results_left = epoll_wait(einfo->epfd, einfo->events, einfo->evlen, combined_msecs);
+ if (results_left == -1)
+ sock_err = socket_errno();
+ }
+
+ gettimeofday(&nsock_tod, NULL); /* Due to epoll delay */
+ } while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */
+
+ if (results_left == -1 && sock_err != EINTR) {
+ nsock_log_error("nsock_loop error %d: %s", sock_err, socket_strerror(sock_err));
+ nsp->errnum = sock_err;
+ return -1;
+ }
+
+ iterate_through_event_lists(nsp, results_left);
+
+ return 1;
+}
+
+
+/* ---- INTERNAL FUNCTIONS ---- */
+static inline int get_evmask(struct epoll_engine_info *einfo, int n) {
+ int evmask = EV_NONE;
+
+ if (einfo->events[n].events & EPOLL_R_FLAGS)
+ evmask |= EV_READ;
+ if (einfo->events[n].events & EPOLL_W_FLAGS)
+ evmask |= EV_WRITE;
+ if (einfo->events[n].events & EPOLL_X_FLAGS)
+ evmask |= EV_EXCEPT;
+
+ return evmask;
+}
+
+/* Iterate through all the event lists (such as connect_events, read_events,
+ * timer_events, etc) and take action for those that have completed (due to
+ * timeout, i/o, etc) */
+void iterate_through_event_lists(struct npool *nsp, int evcount) {
+ struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data;
+ int n;
+
+ for (n = 0; n < evcount; n++) {
+ struct niod *nsi = (struct niod *)einfo->events[n].data.ptr;
+
+ assert(nsi);
+
+ /* process all the pending events for this IOD */
+ process_iod_events(nsp, nsi, get_evmask(einfo, n));
+
+ if (nsi->state == NSIOD_STATE_DELETED) {
+ gh_list_remove(&nsp->active_iods, &nsi->nodeq);
+ gh_list_prepend(&nsp->free_iods, &nsi->nodeq);
+ }
+ }
+
+ /* iterate through timers and expired events */
+ process_expired_events(nsp);
+}
+
+#endif /* HAVE_EPOLL */
+
diff --git a/nsock/src/engine_iocp.c b/nsock/src/engine_iocp.c
new file mode 100644
index 0000000..b1d4302
--- /dev/null
+++ b/nsock/src/engine_iocp.c
@@ -0,0 +1,788 @@
+/***************************************************************************
+ * engine_iocp.c -- I/O Completion Ports based IO engine. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#if WIN32
+#include "nsock_winconfig.h"
+#endif
+
+#if HAVE_IOCP
+
+#include <Winsock2.h>
+#include <Mswsock.h>
+
+#include "nsock_internal.h"
+#include "nsock_log.h"
+
+#if HAVE_PCAP
+#include "nsock_pcap.h"
+#endif
+
+
+/* --- ENGINE INTERFACE PROTOTYPES --- */
+static int iocp_init(struct npool *nsp);
+static void iocp_destroy(struct npool *nsp);
+static int iocp_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev);
+static int iocp_iod_unregister(struct npool *nsp, struct niod *iod);
+static int iocp_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr);
+static int iocp_loop(struct npool *nsp, int msec_timeout);
+
+int iocp_iod_connect(struct npool *nsp, int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+int iocp_iod_read(struct npool *nsp, int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
+int iocp_iod_write(struct npool *nsp, int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
+
+struct io_operations iocp_io_operations = {
+ iocp_iod_connect,
+ iocp_iod_read,
+ iocp_iod_write
+};
+
+/* ---- ENGINE DEFINITION ---- */
+struct io_engine engine_iocp = {
+ "iocp",
+ iocp_init,
+ iocp_destroy,
+ iocp_iod_register,
+ iocp_iod_unregister,
+ iocp_iod_modify,
+ iocp_loop,
+ &iocp_io_operations
+};
+
+/*
+* Engine specific data structure
+*/
+struct iocp_engine_info {
+ /* The handle to the Completion Port*/
+ HANDLE iocp;
+
+ /* We put the current eov to be processed here in order to be retrieved by nsock_core */
+ struct extended_overlapped *eov;
+
+ /* The overlapped_entry list used to retrieve completed packets from the port */
+ OVERLAPPED_ENTRY *eov_list;
+ unsigned long capacity;
+
+ /* How many Completion Packets we actually retreieved */
+ unsigned long entries_removed;
+
+ gh_list_t active_eovs;
+ gh_list_t free_eovs;
+};
+
+struct extended_overlapped {
+ /* Overlapped structure used for overlapped operations */
+ OVERLAPPED ov;
+
+ /* Did we get an error when we initiated the operation?
+ Put the error code here and post it to the main loop */
+ int err;
+
+ /* The event may have expired and was recycled, we can't trust
+ a pointer to the nevent structure to tell us the real nevent */
+ nsock_event_id nse_id;
+
+ /* A pointer to the event */
+ struct nevent *nse;
+
+ /* Needed for WSARecv/WSASend */
+ WSABUF wsabuf;
+
+ /* This is the buffer we will read data in */
+ char *readbuf;
+
+ /* The struct npool keeps track of EOVs that have been allocated so that it
+ * can destroy them if the msp is deleted. This pointer makes it easy to
+ * remove this struct extended_overlapped from the allocated list when necessary */
+ gh_lnode_t nodeq;
+};
+
+/* --- INTERNAL PROTOTYPES --- */
+static void iterate_through_event_lists(struct npool *nsp);
+static void iterate_through_pcap_events(struct npool *nsp);
+static void terminate_overlapped_event(struct npool *nsp, struct nevent *nse);
+static void initiate_overlapped_event(struct npool *nsp, struct nevent *nse);
+static int get_overlapped_result(struct npool *nsp, int fd, const void *buffer, size_t count);
+static void force_operation(struct npool *nsp, struct nevent *nse);
+static void free_eov(struct npool *nsp, struct extended_overlapped *eov);
+static int map_faulty_errors(int err);
+
+/* defined in nsock_core.c */
+void process_iod_events(struct npool *nsp, struct niod *nsi, int ev);
+void process_event(struct npool *nsp, gh_list_t *evlist, struct nevent *nse, int ev);
+void process_expired_events(struct npool *nsp);
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+int pcap_read_on_nonselect(struct npool *nsp);
+#endif
+#endif
+
+/* defined in nsock_event.c */
+void update_first_events(struct nevent *nse);
+
+
+extern struct timeval nsock_tod;
+
+int iocp_init(struct npool *nsp) {
+ struct iocp_engine_info *iinfo;
+
+ iinfo = (struct iocp_engine_info *)safe_malloc(sizeof(struct iocp_engine_info));
+
+ gh_list_init(&iinfo->active_eovs);
+ gh_list_init(&iinfo->free_eovs);
+
+ iinfo->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0);
+ iinfo->capacity = 10;
+ iinfo->eov = NULL;
+ iinfo->entries_removed = 0;
+ iinfo->eov_list = (OVERLAPPED_ENTRY *)safe_malloc(iinfo->capacity * sizeof(OVERLAPPED_ENTRY));
+ nsp->engine_data = (void *)iinfo;
+
+ return 1;
+}
+
+void iocp_destroy(struct npool *nsp) {
+ struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data;
+
+ assert(iinfo != NULL);
+
+ struct extended_overlapped *eov;
+ gh_lnode_t *current;
+
+ while ((current = gh_list_pop(&iinfo->active_eovs))) {
+ eov = container_of(current, struct extended_overlapped, nodeq);
+ if (eov->readbuf) {
+ free(eov->readbuf);
+ eov->readbuf = NULL;
+ }
+ free(eov);
+ }
+
+ while ((current = gh_list_pop(&iinfo->free_eovs))) {
+ eov = container_of(current, struct extended_overlapped, nodeq);
+ free(eov);
+ }
+
+ gh_list_free(&iinfo->active_eovs);
+ gh_list_free(&iinfo->free_eovs);
+
+ CloseHandle(iinfo->iocp);
+ free(iinfo->eov_list);
+
+ free(iinfo);
+}
+
+int iocp_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev) {
+ struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data;
+ HANDLE result;
+
+ assert(!IOD_PROPGET(iod, IOD_REGISTERED));
+ iod->watched_events = ev;
+ result = CreateIoCompletionPort((HANDLE)iod->sd, iinfo->iocp, NULL, 0);
+ assert(result);
+
+ IOD_PROPSET(iod, IOD_REGISTERED);
+
+ initiate_overlapped_event(nsp, nse);
+
+ return 1;
+}
+
+/* Sadly a socket can't be unassociated with a completion port */
+int iocp_iod_unregister(struct npool *nsp, struct niod *iod) {
+
+ if (IOD_PROPGET(iod, IOD_REGISTERED)) {
+ /* Nuke all uncompleted operations on that iod */
+ CancelIo((HANDLE)iod->sd);
+ IOD_PROPCLR(iod, IOD_REGISTERED);
+ }
+
+ return 1;
+}
+
+int iocp_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr) {
+ int new_events;
+ struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data;
+
+ assert((ev_set & ev_clr) == 0);
+ assert(IOD_PROPGET(iod, IOD_REGISTERED));
+
+ new_events = iod->watched_events;
+ new_events |= ev_set;
+ new_events &= ~ev_clr;
+
+ if (ev_set != EV_NONE)
+ initiate_overlapped_event(nsp, nse);
+ else if (ev_clr != EV_NONE)
+ terminate_overlapped_event(nsp, nse);
+
+ if (new_events == iod->watched_events)
+ return 1; /* nothing to do */
+
+ iod->watched_events = new_events;
+
+ return 1;
+}
+
+int iocp_loop(struct npool *nsp, int msec_timeout) {
+ int event_msecs; /* msecs before an event goes off */
+ int combined_msecs;
+ int sock_err = 0;
+ BOOL bRet;
+ unsigned long total_events;
+ struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data;
+
+ assert(msec_timeout >= -1);
+
+ if (nsp->events_pending == 0)
+ return 0; /* No need to wait on 0 events ... */
+
+
+ struct nevent *nse;
+
+ /* Make sure the preallocated space for the retrieved events is big enough */
+ total_events = gh_list_count(&nsp->connect_events) + gh_list_count(&nsp->read_events) + gh_list_count(&nsp->write_events);
+ if (iinfo->capacity < total_events) {
+ iinfo->capacity *= 2;
+ iinfo->eov_list = (OVERLAPPED_ENTRY *)safe_realloc(iinfo->eov_list, iinfo->capacity * sizeof(OVERLAPPED_ENTRY));
+ }
+
+ nsock_log_debug_all("wait for events");
+
+ nse = next_expirable_event(nsp);
+ if (!nse)
+ event_msecs = -1; /* None of the events specified a timeout */
+ else
+ event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod));
+
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+ /* Force a low timeout when capturing packets on systems where
+ * the pcap descriptor is not select()able. */
+ if (gh_list_count(&nsp->pcap_read_events) > 0)
+ if (event_msecs > PCAP_POLL_INTERVAL)
+ event_msecs = PCAP_POLL_INTERVAL;
+#endif
+#endif
+
+ /* We cast to unsigned because we want -1 to be very high (since it means no
+ * timeout) */
+ combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout);
+
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+ /* do non-blocking read on pcap devices that doesn't support select()
+ * If there is anything read, just leave this loop. */
+ if (pcap_read_on_nonselect(nsp)) {
+ /* okay, something was read. */
+ gettimeofday(&nsock_tod, NULL);
+ iterate_through_pcap_events(nsp);
+ }
+ else
+#endif
+#endif
+ {
+ /* It is mandatory these values are reset before calling GetQueuedCompletionStatusEx */
+ iinfo->entries_removed = 0;
+ memset(iinfo->eov_list, 0, iinfo->capacity * sizeof(OVERLAPPED_ENTRY));
+ bRet = GetQueuedCompletionStatusEx(iinfo->iocp, iinfo->eov_list, iinfo->capacity, &iinfo->entries_removed, combined_msecs, FALSE);
+
+ gettimeofday(&nsock_tod, NULL); /* Due to iocp delay */
+ if (!bRet) {
+ sock_err = socket_errno();
+ if (!iinfo->eov && sock_err != WAIT_TIMEOUT) {
+ nsock_log_error("nsock_loop error %d: %s", sock_err, socket_strerror(sock_err));
+ nsp->errnum = sock_err;
+ return -1;
+ }
+ }
+ }
+
+ iterate_through_event_lists(nsp);
+
+ return 1;
+}
+
+
+/* ---- INTERNAL FUNCTIONS ---- */
+
+#if HAVE_PCAP
+/* Iterate through pcap events separately, since these are not tracked in iocp_engine_info */
+void iterate_through_pcap_events(struct npool *nsp) {
+ gh_lnode_t *current, *next, *last;
+
+ last = gh_list_last_elem(&nsp->active_iods);
+
+ for (current = gh_list_first_elem(&nsp->active_iods);
+ current != NULL && gh_lnode_prev(current) != last;
+ current = next) {
+ struct niod *nsi = container_of(current, struct niod, nodeq);
+
+ if (nsi->pcap && nsi->state != NSIOD_STATE_DELETED && nsi->events_pending)
+ {
+ process_iod_events(nsp, nsi, EV_READ);
+ }
+
+ next = gh_lnode_next(current);
+ if (nsi->state == NSIOD_STATE_DELETED) {
+ gh_list_remove(&nsp->active_iods, current);
+ gh_list_prepend(&nsp->free_iods, current);
+ }
+ }
+}
+#endif
+
+/* Iterate through all the event lists (such as connect_events, read_events,
+* timer_events, etc) and take action for those that have completed (due to
+* timeout, i/o, etc) */
+void iterate_through_event_lists(struct npool *nsp) {
+ struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data;
+
+ for (unsigned long i = 0; i < iinfo->entries_removed; i++) {
+
+ iinfo->eov = (struct extended_overlapped *)iinfo->eov_list[i].lpOverlapped;
+ /* We can't rely on iinfo->entries_removed to tell us the real number of
+ * events to process */
+ if (!iinfo->eov || !iinfo->eov->nse)
+ continue;
+
+ /* We check if this is from a cancelled operation */
+ if (iinfo->eov->nse->id != iinfo->eov->nse_id ||
+ iinfo->eov->nse->event_done) {
+ free_eov(nsp, iinfo->eov);
+ iinfo->eov = NULL;
+ continue;
+ }
+
+ if (!HasOverlappedIoCompleted((OVERLAPPED *)iinfo->eov))
+ continue;
+
+ struct niod *nsi = iinfo->eov->nse->iod;
+ struct nevent *nse = iinfo->eov->nse;
+ gh_list_t *evlist = NULL;
+ int ev = 0;
+
+ switch (nse->type) {
+ case NSE_TYPE_CONNECT:
+ case NSE_TYPE_CONNECT_SSL:
+ ev = EV_READ;
+ evlist = &nsp->connect_events;
+ break;
+ case NSE_TYPE_READ:
+ ev = EV_READ;
+ evlist = &nsp->read_events;
+ break;
+ case NSE_TYPE_WRITE:
+ ev = EV_WRITE;
+ evlist = &nsp->write_events;
+ break;
+ }
+
+ /* Setting the connect error for nsock_core to get in handle_connect_result */
+ if (nse->type == NSE_TYPE_CONNECT || nse->type == NSE_TYPE_CONNECT_SSL) {
+ setsockopt(nse->iod->sd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0);
+ DWORD dwRes;
+ if (!GetOverlappedResult((HANDLE)nse->iod->sd, (LPOVERLAPPED)iinfo->eov, &dwRes, FALSE)) {
+ int err = map_faulty_errors(socket_errno());
+ if (err)
+ setsockopt(nse->iod->sd, SOL_SOCKET, SO_ERROR, (char *)&err, sizeof(err));
+ }
+ }
+
+ process_event(nsp, evlist, nse, ev);
+
+ if (nse->event_done) {
+ /* event is done, remove it from the event list and update IOD pointers
+ * to the first events of each kind */
+ update_first_events(nse);
+ gh_list_remove(evlist, &nse->nodeq_io);
+ gh_list_append(&nsp->free_events, &nse->nodeq_io);
+
+ if (nse->timeout.tv_sec)
+ gh_heap_remove(&nsp->expirables, &nse->expire);
+ } else
+ initiate_overlapped_event(nsp, nse);
+
+ if (nsi->state == NSIOD_STATE_DELETED) {
+ gh_list_remove(&nsp->active_iods, &nsi->nodeq);
+ gh_list_prepend(&nsp->free_iods, &nsi->nodeq);
+ }
+
+ iinfo->eov = NULL;
+ }
+
+ /* iterate through timers and expired events */
+ process_expired_events(nsp);
+}
+
+static int errcode_is_failure(int err) {
+#ifndef WIN32
+ return err != EINTR && err != EAGAIN && err != EBUSY;
+#else
+ return err != EINTR && err != EAGAIN && err != WSA_IO_PENDING && err != ERROR_NETNAME_DELETED;
+#endif
+}
+
+static int map_faulty_errors(int err) {
+ /* This actually happens https://svn.boost.org/trac/boost/ticket/10744 */
+ switch (err) {
+ case ERROR_NETWORK_UNREACHABLE: return WSAENETUNREACH;
+ case ERROR_HOST_UNREACHABLE: return WSAEHOSTUNREACH;
+ case ERROR_CONNECTION_REFUSED: return WSAECONNREFUSED;
+ case ERROR_SEM_TIMEOUT: return WSAETIMEDOUT;
+ }
+ return err;
+}
+
+static struct extended_overlapped *new_eov(struct npool *nsp, struct nevent *nse) {
+ struct extended_overlapped *eov;
+ gh_lnode_t *lnode;
+ struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data;
+
+ lnode = gh_list_pop(&iinfo->free_eovs);
+ if (!lnode)
+ eov = (struct extended_overlapped *)safe_malloc(sizeof(struct extended_overlapped));
+ else
+ eov = container_of(lnode, struct extended_overlapped, nodeq);
+
+ memset(eov, 0, sizeof(struct extended_overlapped));
+ nse->eov = eov;
+ eov->nse = nse;
+ eov->nse_id = nse->id;
+ eov->err = 0;
+ gh_list_prepend(&iinfo->active_eovs, &eov->nodeq);
+
+ /* Make the read buffer equal to the size of the buffer in do_actual_read() */
+ if (nse->type == NSE_TYPE_READ && !eov->readbuf && !nse->iod->ssl)
+ eov->readbuf = (char*)safe_malloc(READ_BUFFER_SZ * sizeof(char));
+
+ return eov;
+}
+
+/* This needs to be called after getting the overlapped event in */
+static void free_eov(struct npool *nsp, struct extended_overlapped *eov) {
+ struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data;
+ struct nevent *nse = eov->nse;
+
+ gh_list_remove(&iinfo->active_eovs, &eov->nodeq);
+
+ if (eov->readbuf) {
+ free(eov->readbuf);
+ eov->readbuf = NULL;
+ }
+
+ gh_list_prepend(&iinfo->free_eovs, &eov->nodeq);
+
+ eov->nse = NULL;
+ if (nse)
+ nse->eov = NULL;
+}
+
+
+static void call_connect_overlapped(struct npool *nsp, struct nevent *nse) {
+ BOOL ok;
+ DWORD numBytes = 0;
+ int one = 1;
+ SOCKET sock = nse->iod->sd;
+ GUID guid = WSAID_CONNECTEX;
+ struct sockaddr_in addr;
+ LPFN_CONNECTEX ConnectExPtr = NULL;
+ struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nse->iod->nsp->engine_data;
+ struct extended_overlapped *eov = new_eov(nsp, nse);
+ int ret;
+ struct sockaddr_storage *ss = &nse->iod->peer;
+ size_t sslen = nse->iod->peerlen;
+
+ if (nse->iod->lastproto != IPPROTO_TCP) {
+ if (connect(sock, (struct sockaddr *)ss, sslen) == -1) {
+ int err = socket_errno();
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_ERROR;
+ nse->errnum = err;
+ } else {
+ force_operation(nsp, nse);
+ }
+ return;
+ }
+
+ ret = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ (void*)&guid, sizeof(guid), (void*)&ConnectExPtr, sizeof(ConnectExPtr),
+ &numBytes, NULL, NULL);
+ if (ret)
+ fatal("Error initiating event type(%d)", nse->type);
+
+ ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, sizeof(one));
+ if (ret == -1) {
+ int err = socket_errno();
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_ERROR;
+ nse->errnum = err;
+ return;
+ }
+
+ /* ConnectEx doesn't automatically bind the socket */
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_port = 0;
+ if (!nse->iod->locallen) {
+ ret = bind(sock, (SOCKADDR*)&addr, sizeof(addr));
+ if (ret) {
+ int err = socket_errno();
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_ERROR;
+ nse->errnum = err;
+ return;
+ }
+ }
+
+ ok = ConnectExPtr(sock, (SOCKADDR*)ss, sslen, NULL, 0, NULL, (LPOVERLAPPED)eov);
+ if (!ok) {
+ int err = socket_errno();
+ if (err != ERROR_IO_PENDING) {
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_ERROR;
+ nse->errnum = err;
+ }
+ }
+}
+
+static void call_read_overlapped(struct nevent *nse) {
+ DWORD flags = 0;
+ int err = 0;
+ struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nse->iod->nsp->engine_data;
+
+ struct extended_overlapped *eov = new_eov(nse->iod->nsp, nse);
+
+ eov->wsabuf.buf = eov->readbuf;
+ eov->wsabuf.len = READ_BUFFER_SZ;
+
+ err = WSARecvFrom(nse->iod->sd, &eov->wsabuf, 1, NULL, &flags,
+ (struct sockaddr *)&nse->iod->peer, (LPINT)&nse->iod->peerlen, (LPOVERLAPPED)eov, NULL);
+ if (err) {
+ err = socket_errno();
+ if (errcode_is_failure(err)) {
+ // WSARecvFrom with overlapped I/O may generate ERROR_PORT_UNREACHABLE on ICMP error.
+ // We'll translate that so Nsock-using software doesn't have to know about it.
+ eov->err = (err == ERROR_PORT_UNREACHABLE ? ECONNREFUSED : err);
+ /* Send the error to the main loop to be picked up by the appropriate handler */
+ BOOL bRet = PostQueuedCompletionStatus(iinfo->iocp, -1, (ULONG_PTR)nse->iod, (LPOVERLAPPED)eov);
+ if (!bRet)
+ fatal("Error initiating event type(%d)", nse->type);
+ }
+ }
+}
+
+static void call_write_overlapped(struct nevent *nse) {
+ int err;
+ char *str;
+ int bytesleft;
+ struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nse->iod->nsp->engine_data;
+
+ struct extended_overlapped *eov = new_eov(nse->iod->nsp, nse);
+
+ str = fs_str(&nse->iobuf) + nse->writeinfo.written_so_far;
+ bytesleft = fs_length(&nse->iobuf) - nse->writeinfo.written_so_far;
+
+ eov->wsabuf.buf = str;
+ eov->wsabuf.len = bytesleft;
+
+ if (nse->writeinfo.dest.ss_family == AF_UNSPEC)
+ err = WSASend(nse->iod->sd, &eov->wsabuf, 1, NULL, 0, (LPWSAOVERLAPPED)eov, NULL);
+ else
+ err = WSASendTo(nse->iod->sd, &eov->wsabuf, 1, NULL, 0,
+ (struct sockaddr *)&nse->writeinfo.dest, (int)nse->writeinfo.destlen,
+ (LPWSAOVERLAPPED)eov, NULL);
+ if (err) {
+ err = socket_errno();
+ if (errcode_is_failure(err)) {
+ eov->err = err;
+ /* Send the error to the main loop to be picked up by the appropriate handler */
+ BOOL bRet = PostQueuedCompletionStatus(iinfo->iocp, -1, (ULONG_PTR)nse->iod, (LPOVERLAPPED)eov);
+ if (!bRet)
+ fatal("Error initiating event type(%d)", nse->type);
+ }
+ }
+}
+
+/* Anything that isn't an overlapped operation uses this to get processed by the main loop */
+static void force_operation(struct npool *nsp, struct nevent *nse) {
+ BOOL bRet;
+ struct extended_overlapped *eov;
+
+ struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data;
+ eov = new_eov(nse->iod->nsp, nse);
+
+ bRet = PostQueuedCompletionStatus(iinfo->iocp, 0, (ULONG_PTR)nse->iod, (LPOVERLAPPED)eov);
+ if (!bRet)
+ fatal("Error initiating event type(%d)", nse->type);
+}
+
+/* Either initiate a I/O read or force a SSL_read */
+static void initiate_read(struct npool *nsp, struct nevent *nse) {
+ if (!nse->iod->ssl)
+ call_read_overlapped(nse);
+ else
+ force_operation(nsp, nse);
+}
+
+/* Either initiate a I/O write or force a SSL_write */
+static void initiate_write(struct npool *nsp, struct nevent *nse) {
+ if (!nse->iod->ssl)
+ call_write_overlapped(nse);
+ else
+ force_operation(nsp, nse);
+}
+
+/* Force a PCAP read */
+static void initiate_pcap_read(struct npool *nsp, struct nevent *nse) {
+ force_operation(nsp, nse);
+}
+
+static void initiate_connect(struct npool *nsp, struct nevent *nse) {
+ int sslconnect_inprogress = 0;
+ struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data;
+
+#if HAVE_OPENSSL
+ sslconnect_inprogress = nse->type == NSE_TYPE_CONNECT_SSL && nse->iod &&
+ (nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ ||
+ nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE);
+#endif
+
+ if (sslconnect_inprogress)
+ force_operation(nsp, nse);
+ else
+ call_connect_overlapped(nsp, nse);
+}
+
+/* Start the overlapped I/O operation */
+static void initiate_overlapped_event(struct npool *nsp, struct nevent *nse) {
+ if (nse->eov)
+ terminate_overlapped_event(nsp, nse);
+
+ switch (nse->type) {
+ case NSE_TYPE_CONNECT:
+ case NSE_TYPE_CONNECT_SSL:
+ initiate_connect(nsp, nse);
+ break;
+ case NSE_TYPE_READ:
+ initiate_read(nsp, nse);
+ break;
+ case NSE_TYPE_WRITE:
+ initiate_write(nsp, nse);
+ break;
+#if HAVE_PCAP
+ case NSE_TYPE_PCAP_READ:
+ initiate_pcap_read(nsp, nse);
+ break;
+#endif
+ default: fatal("Event type(%d) not supported by engine IOCP\n", nse->type);
+ }
+}
+
+/* Terminate an overlapped I/O operation that expired */
+static void terminate_overlapped_event(struct npool *nsp, struct nevent *nse) {
+ bool eov_done = true;
+
+ if (nse->eov) {
+ if (!HasOverlappedIoCompleted((LPOVERLAPPED)nse->eov)) {
+ CancelIoEx((HANDLE)nse->iod->sd, (LPOVERLAPPED)nse->eov);
+ eov_done = false;
+ }
+
+ if (eov_done)
+ free_eov(nsp, nse->eov);
+ }
+}
+
+/* Retrieve the amount of bytes transferred or set the appropriate error */
+static int get_overlapped_result(struct npool *nsp, int fd, const void *buffer, size_t count) {
+ char *buf = (char *)buffer;
+ DWORD dwRes = 0;
+ int err;
+ struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data;
+
+ struct extended_overlapped *eov = iinfo->eov;
+ struct nevent *nse = eov->nse;
+
+ /* If the operation failed at initialization, set the error for nsock_core.c to see */
+ if (eov->err) {
+ SetLastError(map_faulty_errors(eov->err));
+ return -1;
+ }
+
+ if (!GetOverlappedResult((HANDLE)fd, (LPOVERLAPPED)eov, &dwRes, FALSE)) {
+ err = socket_errno();
+ if (errcode_is_failure(err)) {
+ SetLastError(map_faulty_errors(err));
+ return -1;
+ }
+ }
+
+ if (nse->type == NSE_TYPE_READ && buf)
+ memcpy(buf, eov->wsabuf.buf, dwRes);
+
+ return dwRes;
+}
+
+int iocp_iod_connect(struct npool *nsp, int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
+ return 0;
+}
+
+int iocp_iod_read(struct npool *nsp, int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) {
+ return get_overlapped_result(nsp, sockfd, buf, len);
+}
+
+int iocp_iod_write(struct npool *nsp, int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) {
+ return get_overlapped_result(nsp, sockfd, buf, len);
+}
+
+#endif /* HAVE_IOCP */
diff --git a/nsock/src/engine_kqueue.c b/nsock/src/engine_kqueue.c
new file mode 100644
index 0000000..aa992bb
--- /dev/null
+++ b/nsock/src/engine_kqueue.c
@@ -0,0 +1,368 @@
+/***************************************************************************
+ * engine_kqueue.c -- BSD kqueue(2) based IO engine. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "nsock_config.h"
+#endif
+
+#if HAVE_KQUEUE
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include "nsock_internal.h"
+#include "nsock_log.h"
+
+#if HAVE_PCAP
+#include "nsock_pcap.h"
+#endif
+
+#define INITIAL_EV_COUNT 128
+
+
+/* --- ENGINE INTERFACE PROTOTYPES --- */
+static int kqueue_init(struct npool *nsp);
+static void kqueue_destroy(struct npool *nsp);
+static int kqueue_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev);
+static int kqueue_iod_unregister(struct npool *nsp, struct niod *iod);
+static int kqueue_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr);
+static int kqueue_loop(struct npool *nsp, int msec_timeout);
+
+extern struct io_operations posix_io_operations;
+
+/* ---- ENGINE DEFINITION ---- */
+struct io_engine engine_kqueue = {
+ "kqueue",
+ kqueue_init,
+ kqueue_destroy,
+ kqueue_iod_register,
+ kqueue_iod_unregister,
+ kqueue_iod_modify,
+ kqueue_loop,
+ &posix_io_operations
+};
+
+
+/* --- INTERNAL PROTOTYPES --- */
+static void iterate_through_event_lists(struct npool *nsp, int evcount);
+
+/* defined in nsock_core.c */
+void process_iod_events(struct npool *nsp, struct niod *nsi, int ev);
+void process_event(struct npool *nsp, gh_list_t *evlist, struct nevent *nse, int ev);
+void process_expired_events(struct npool *nsp);
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+int pcap_read_on_nonselect(struct npool *nsp);
+#endif
+#endif
+
+/* defined in nsock_event.c */
+void update_first_events(struct nevent *nse);
+
+
+extern struct timeval nsock_tod;
+
+
+/*
+ * Engine specific data structure
+ */
+struct kqueue_engine_info {
+ int kqfd;
+ int maxfd;
+ size_t evlen;
+ struct kevent *events;
+};
+
+
+int kqueue_init(struct npool *nsp) {
+ struct kqueue_engine_info *kinfo;
+
+ kinfo = (struct kqueue_engine_info *)safe_malloc(sizeof(struct kqueue_engine_info));
+
+ kinfo->kqfd = kqueue();
+ kinfo->maxfd = -1;
+ kinfo->evlen = INITIAL_EV_COUNT;
+ kinfo->events = (struct kevent *)safe_malloc(INITIAL_EV_COUNT * sizeof(struct kevent));
+
+ nsp->engine_data = (void *)kinfo;
+
+ return 1;
+}
+
+void kqueue_destroy(struct npool *nsp) {
+ struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data;
+
+ assert(kinfo != NULL);
+ close(kinfo->kqfd);
+ free(kinfo->events);
+ free(kinfo);
+}
+
+int kqueue_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev) {
+ struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data;
+
+ assert(!IOD_PROPGET(iod, IOD_REGISTERED));
+
+ IOD_PROPSET(iod, IOD_REGISTERED);
+ iod->watched_events = EV_NONE;
+
+ kqueue_iod_modify(nsp, iod, nse, ev, EV_NONE);
+
+ if (nsock_iod_get_sd(iod) > kinfo->maxfd)
+ kinfo->maxfd = nsock_iod_get_sd(iod);
+
+ return 1;
+}
+
+int kqueue_iod_unregister(struct npool *nsp, struct niod *iod) {
+ struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data;
+
+ /* some IODs can be unregistered here if they're associated to an event that was
+ * immediately completed */
+ if (IOD_PROPGET(iod, IOD_REGISTERED)) {
+ kqueue_iod_modify(nsp, iod, NULL, EV_NONE, EV_READ|EV_WRITE);
+ IOD_PROPCLR(iod, IOD_REGISTERED);
+
+ if (nsock_iod_get_sd(iod) == kinfo->maxfd)
+ kinfo->maxfd--;
+ }
+ iod->watched_events = EV_NONE;
+ return 1;
+}
+
+#define EV_SETFLAG(_set, _ev) (((_set) & (_ev)) ? (EV_ADD|EV_ENABLE) : (EV_ADD|EV_DISABLE))
+
+int kqueue_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr) {
+ struct kevent kev[2];
+ int new_events, i;
+ struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data;
+
+ assert((ev_set & ev_clr) == 0);
+ assert(IOD_PROPGET(iod, IOD_REGISTERED));
+
+ new_events = iod->watched_events;
+ new_events |= ev_set;
+ new_events &= ~ev_clr;
+
+ if (new_events == iod->watched_events)
+ return 1; /* nothing to do */
+
+ i = 0;
+ if ((ev_set ^ ev_clr) & EV_READ) {
+ EV_SET(&kev[i], nsock_iod_get_sd(iod), EVFILT_READ, EV_SETFLAG(ev_set, EV_READ), 0, 0, (void *)iod);
+ i++;
+ }
+ if ((ev_set ^ ev_clr) & EV_WRITE) {
+ EV_SET(&kev[i], nsock_iod_get_sd(iod), EVFILT_WRITE, EV_SETFLAG(ev_set, EV_WRITE), 0, 0, (void *)iod);
+ i++;
+ }
+
+ if (i > 0 && kevent(kinfo->kqfd, kev, i, NULL, 0, NULL) < 0)
+ fatal("Unable to update events for IOD #%lu: %s", iod->id, strerror(errno));
+
+ iod->watched_events = new_events;
+ return 1;
+}
+
+int kqueue_loop(struct npool *nsp, int msec_timeout) {
+ int results_left = 0;
+ int event_msecs; /* msecs before an event goes off */
+ int combined_msecs;
+ struct timespec ts, *ts_p;
+ int sock_err = 0;
+ struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data;
+
+ assert(msec_timeout >= -1);
+
+ if (nsp->events_pending == 0)
+ return 0; /* No need to wait on 0 events ... */
+
+
+ if (gh_list_count(&nsp->active_iods) > kinfo->evlen) {
+ kinfo->evlen = gh_list_count(&nsp->active_iods) * 2;
+ kinfo->events = (struct kevent *)safe_realloc(kinfo->events, kinfo->evlen * sizeof(struct kevent));
+ }
+
+ do {
+ struct nevent *nse;
+
+ nsock_log_debug_all("wait for events");
+
+ nse = next_expirable_event(nsp);
+ if (!nse)
+ event_msecs = -1; /* None of the events specified a timeout */
+ else
+ event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod));
+
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+ /* Force a low timeout when capturing packets on systems where
+ * the pcap descriptor is not select()able. */
+ if (gh_list_count(&nsp->pcap_read_events) > 0)
+ if (event_msecs > PCAP_POLL_INTERVAL)
+ event_msecs = PCAP_POLL_INTERVAL;
+#endif
+#endif
+
+ /* We cast to unsigned because we want -1 to be very high (since it means no
+ * timeout) */
+ combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout);
+
+ /* Set up the timeval pointer we will give to kevent() */
+ memset(&ts, 0, sizeof(struct timespec));
+ if (combined_msecs >= 0) {
+ ts.tv_sec = combined_msecs / 1000;
+ ts.tv_nsec = (combined_msecs % 1000) * 1000000L;
+ ts_p = &ts;
+ } else {
+ ts_p = NULL;
+ }
+
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+ /* do non-blocking read on pcap devices that doesn't support select()
+ * If there is anything read, just leave this loop. */
+ if (pcap_read_on_nonselect(nsp)) {
+ /* okay, something was read. */
+ } else
+#endif
+#endif
+ {
+ results_left = kevent(kinfo->kqfd, NULL, 0, kinfo->events, kinfo->evlen, ts_p);
+ if (results_left == -1)
+ sock_err = socket_errno();
+ }
+
+ gettimeofday(&nsock_tod, NULL); /* Due to kevent delay */
+ } while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */
+
+ if (results_left == -1 && sock_err != EINTR) {
+ nsock_log_error("nsock_loop error %d: %s", sock_err, socket_strerror(sock_err));
+ nsp->errnum = sock_err;
+ return -1;
+ }
+
+ iterate_through_event_lists(nsp, results_left);
+
+ return 1;
+}
+
+
+/* ---- INTERNAL FUNCTIONS ---- */
+
+static inline int get_evmask(struct niod *nsi, const struct kevent *kev) {
+ int evmask = EV_NONE;
+
+ /* generate the corresponding event mask with nsock event flags */
+ if (kev->flags & EV_ERROR) {
+ evmask |= EV_EXCEPT;
+
+ if (kev->data == EPIPE && (nsi->watched_events & EV_READ))
+ evmask |= EV_READ;
+ } else {
+ switch (kev->filter) {
+ case EVFILT_READ:
+ evmask |= EV_READ;
+ break;
+
+ case EVFILT_WRITE:
+ evmask |= EV_WRITE;
+ break;
+
+ default:
+ fatal("Unsupported filter value: %d\n", (int)kev->filter);
+ }
+ }
+ return evmask;
+}
+
+/* Iterate through all the event lists (such as connect_events, read_events,
+ * timer_events, etc) and take action for those that have completed (due to
+ * timeout, i/o, etc) */
+void iterate_through_event_lists(struct npool *nsp, int evcount) {
+ int n;
+ struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data;
+ struct niod *nsi;
+
+ for (n = 0; n < evcount; n++) {
+ struct kevent *kev = &kinfo->events[n];
+
+ nsi = (struct niod *)kev->udata;
+
+ /* process all the pending events for this IOD */
+ process_iod_events(nsp, nsi, get_evmask(nsi, kev));
+
+ IOD_PROPSET(nsi, IOD_PROCESSED);
+ }
+
+ for (n = 0; n < evcount; n++) {
+ struct kevent *kev = &kinfo->events[n];
+
+ nsi = (struct niod *)kev->udata;
+
+ if (nsi->state == NSIOD_STATE_DELETED) {
+ if (IOD_PROPGET(nsi, IOD_PROCESSED)) {
+ IOD_PROPCLR(nsi, IOD_PROCESSED);
+ gh_list_remove(&nsp->active_iods, &nsi->nodeq);
+ gh_list_prepend(&nsp->free_iods, &nsi->nodeq);
+ }
+ }
+ }
+
+ /* iterate through timers and expired events */
+ process_expired_events(nsp);
+}
+
+#endif /* HAVE_KQUEUE */
+
diff --git a/nsock/src/engine_poll.c b/nsock/src/engine_poll.c
new file mode 100644
index 0000000..5a2262a
--- /dev/null
+++ b/nsock/src/engine_poll.c
@@ -0,0 +1,429 @@
+/***************************************************************************
+ * engine_poll.c -- poll(2) based IO engine. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifndef WIN32
+/* Allow the use of POLLRDHUP, if available. */
+#define _GNU_SOURCE
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "nsock_config.h"
+#elif WIN32
+#include "nsock_winconfig.h"
+#endif
+
+#if HAVE_POLL
+
+#include <errno.h>
+
+#ifndef WIN32
+#include <poll.h>
+#else
+#include <Winsock2.h>
+#endif /* ^WIN32 */
+
+#include "nsock_internal.h"
+#include "nsock_log.h"
+
+#if HAVE_PCAP
+#include "nsock_pcap.h"
+#endif
+
+#define EV_LIST_INIT_SIZE 1024
+
+#ifdef WIN32
+ #define Poll WSAPoll
+ #define POLLFD WSAPOLLFD
+#else
+ #define Poll poll
+ #define POLLFD struct pollfd
+#endif
+
+#ifdef WIN32
+ #define POLL_R_FLAGS (POLLIN)
+#else
+ #define POLL_R_FLAGS (POLLIN | POLLPRI)
+#endif /* WIN32 */
+
+#define POLL_W_FLAGS POLLOUT
+#ifdef POLLRDHUP
+ #define POLL_X_FLAGS (POLLERR | POLLHUP | POLLRDHUP)
+#else
+ /* POLLRDHUP was introduced later and might be unavailable on older systems. */
+ #define POLL_X_FLAGS (POLLERR | POLLHUP)
+#endif /* POLLRDHUP */
+
+extern struct io_operations posix_io_operations;
+
+/* --- ENGINE INTERFACE PROTOTYPES --- */
+static int poll_init(struct npool *nsp);
+static void poll_destroy(struct npool *nsp);
+static int poll_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev);
+static int poll_iod_unregister(struct npool *nsp, struct niod *iod);
+static int poll_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr);
+static int poll_loop(struct npool *nsp, int msec_timeout);
+
+
+/* ---- ENGINE DEFINITION ---- */
+struct io_engine engine_poll = {
+ "poll",
+ poll_init,
+ poll_destroy,
+ poll_iod_register,
+ poll_iod_unregister,
+ poll_iod_modify,
+ poll_loop,
+ &posix_io_operations
+};
+
+
+/* --- INTERNAL PROTOTYPES --- */
+static void iterate_through_event_lists(struct npool *nsp);
+
+/* defined in nsock_core.c */
+void process_iod_events(struct npool *nsp, struct niod *nsi, int ev);
+void process_event(struct npool *nsp, gh_list_t *evlist, struct nevent *nse, int ev);
+void process_expired_events(struct npool *nsp);
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+int pcap_read_on_nonselect(struct npool *nsp);
+#endif
+#endif
+
+/* defined in nsock_event.c */
+void update_first_events(struct nevent *nse);
+
+
+extern struct timeval nsock_tod;
+
+
+/*
+ * Engine specific data structure
+ */
+struct poll_engine_info {
+ int capacity;
+ int max_fd;
+ /* index of the highest poll event */
+ POLLFD *events;
+};
+
+
+
+static inline int lower_max_fd(struct poll_engine_info *pinfo) {
+ do {
+ pinfo->max_fd--;
+ } while (pinfo->max_fd >= 0 && pinfo->events[pinfo->max_fd].fd == -1);
+
+ return pinfo->max_fd;
+}
+
+static inline int evlist_grow(struct poll_engine_info *pinfo) {
+ int i;
+
+ i = pinfo->capacity;
+
+ if (pinfo->capacity == 0) {
+ pinfo->capacity = EV_LIST_INIT_SIZE;
+ pinfo->events = (POLLFD *)safe_malloc(sizeof(POLLFD) * pinfo->capacity);
+ } else {
+ pinfo->capacity *= 2;
+ pinfo->events = (POLLFD *)safe_realloc(pinfo->events, sizeof(POLLFD) * pinfo->capacity);
+ }
+
+ while (i < pinfo->capacity) {
+ pinfo->events[i].fd = -1;
+ pinfo->events[i].events = 0;
+ pinfo->events[i].revents = 0;
+ i++;
+ }
+ return pinfo->capacity;
+}
+
+
+int poll_init(struct npool *nsp) {
+ struct poll_engine_info *pinfo;
+
+ pinfo = (struct poll_engine_info *)safe_malloc(sizeof(struct poll_engine_info));
+ pinfo->capacity = 0;
+ pinfo->max_fd = -1;
+ evlist_grow(pinfo);
+
+ nsp->engine_data = (void *)pinfo;
+
+ return 1;
+}
+
+void poll_destroy(struct npool *nsp) {
+ struct poll_engine_info *pinfo = (struct poll_engine_info *)nsp->engine_data;
+
+ assert(pinfo != NULL);
+ free(pinfo->events);
+ free(pinfo);
+}
+
+int poll_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev) {
+ struct poll_engine_info *pinfo = (struct poll_engine_info *)nsp->engine_data;
+ int sd;
+
+ assert(!IOD_PROPGET(iod, IOD_REGISTERED));
+
+ iod->watched_events = ev;
+
+ sd = nsock_iod_get_sd(iod);
+ while (pinfo->capacity < sd + 1)
+ evlist_grow(pinfo);
+
+ pinfo->events[sd].fd = sd;
+ pinfo->events[sd].events = 0;
+ pinfo->events[sd].revents = 0;
+
+ pinfo->max_fd = MAX(pinfo->max_fd, sd);
+
+ if (ev & EV_READ)
+ pinfo->events[sd].events |= POLL_R_FLAGS;
+ if (ev & EV_WRITE)
+ pinfo->events[sd].events |= POLL_W_FLAGS;
+#ifndef WIN32
+ if (ev & EV_EXCEPT)
+ pinfo->events[sd].events |= POLL_X_FLAGS;
+#endif
+
+ IOD_PROPSET(iod, IOD_REGISTERED);
+ return 1;
+}
+
+int poll_iod_unregister(struct npool *nsp, struct niod *iod) {
+ iod->watched_events = EV_NONE;
+
+ /* some IODs can be unregistered here if they're associated to an event that was
+ * immediately completed */
+ if (IOD_PROPGET(iod, IOD_REGISTERED)) {
+ struct poll_engine_info *pinfo = (struct poll_engine_info *)nsp->engine_data;
+ int sd;
+
+ sd = nsock_iod_get_sd(iod);
+ pinfo->events[sd].fd = -1;
+ pinfo->events[sd].events = 0;
+ pinfo->events[sd].revents = 0;
+
+ if (pinfo->max_fd == sd)
+ lower_max_fd(pinfo);
+
+ IOD_PROPCLR(iod, IOD_REGISTERED);
+ }
+ return 1;
+}
+
+int poll_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr) {
+ int sd;
+ int new_events;
+ struct poll_engine_info *pinfo = (struct poll_engine_info *)nsp->engine_data;
+
+ assert((ev_set & ev_clr) == 0);
+ assert(IOD_PROPGET(iod, IOD_REGISTERED));
+
+ new_events = iod->watched_events;
+ new_events |= ev_set;
+ new_events &= ~ev_clr;
+
+ if (new_events == iod->watched_events)
+ return 1; /* nothing to do */
+
+ iod->watched_events = new_events;
+
+ sd = nsock_iod_get_sd(iod);
+
+ pinfo->events[sd].fd = sd;
+ pinfo->events[sd].events = 0;
+
+ /* regenerate the current set of events for this IOD */
+ if (iod->watched_events & EV_READ)
+ pinfo->events[sd].events |= POLL_R_FLAGS;
+ if (iod->watched_events & EV_WRITE)
+ pinfo->events[sd].events |= POLL_W_FLAGS;
+
+ return 1;
+}
+
+int poll_loop(struct npool *nsp, int msec_timeout) {
+ int results_left = 0;
+ int event_msecs; /* msecs before an event goes off */
+ int combined_msecs;
+ int sock_err = 0;
+ struct poll_engine_info *pinfo = (struct poll_engine_info *)nsp->engine_data;
+
+ assert(msec_timeout >= -1);
+
+ if (nsp->events_pending == 0)
+ return 0; /* No need to wait on 0 events ... */
+
+ do {
+ struct nevent *nse;
+
+ nsock_log_debug_all("wait for events");
+
+ nse = next_expirable_event(nsp);
+ if (!nse)
+ event_msecs = -1; /* None of the events specified a timeout */
+ else
+ event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod));
+
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+ /* Force a low timeout when capturing packets on systems where
+ * the pcap descriptor is not select()able. */
+ if (gh_list_count(&nsp->pcap_read_events) > 0)
+ if (event_msecs > PCAP_POLL_INTERVAL)
+ event_msecs = PCAP_POLL_INTERVAL;
+#endif
+#endif
+
+ /* We cast to unsigned because we want -1 to be very high (since it means no
+ * timeout) */
+ combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout);
+
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+ /* do non-blocking read on pcap devices that doesn't support select()
+ * If there is anything read, just leave this loop. */
+ if (pcap_read_on_nonselect(nsp)) {
+ /* okay, something was read. */
+ } else
+#endif
+#endif
+ {
+ results_left = Poll(pinfo->events, pinfo->max_fd + 1, combined_msecs);
+ if (results_left == -1)
+ sock_err = socket_errno();
+ }
+
+ gettimeofday(&nsock_tod, NULL); /* Due to poll delay */
+ } while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */
+
+ if (results_left == -1 && sock_err != EINTR) {
+#ifdef WIN32
+ for (int i = 0; sock_err != EINVAL || i <= pinfo->max_fd; i++) {
+ if (sock_err != EINVAL || pinfo->events[i].fd != -1) {
+#endif
+ nsock_log_error("nsock_loop error %d: %s", sock_err, socket_strerror(sock_err));
+ nsp->errnum = sock_err;
+ return -1;
+#ifdef WIN32
+ }
+ }
+#endif
+ }
+
+ iterate_through_event_lists(nsp);
+
+ return 1;
+}
+
+
+/* ---- INTERNAL FUNCTIONS ---- */
+
+static inline int get_evmask(struct npool *nsp, struct niod *nsi) {
+ struct poll_engine_info *pinfo = (struct poll_engine_info *)nsp->engine_data;
+ int sd, evmask = EV_NONE;
+ POLLFD *pev;
+
+ if (nsi->state != NSIOD_STATE_DELETED
+ && nsi->events_pending
+ && IOD_PROPGET(nsi, IOD_REGISTERED)) {
+
+#if HAVE_PCAP
+ if (nsi->pcap)
+ sd = ((mspcap *)nsi->pcap)->pcap_desc;
+ else
+#endif
+ sd = nsi->sd;
+
+ assert(sd < pinfo->capacity);
+ pev = &pinfo->events[sd];
+
+ if (pev->revents & POLL_R_FLAGS)
+ evmask |= EV_READ;
+ if (pev->revents & POLL_W_FLAGS)
+ evmask |= EV_WRITE;
+ if (pev->events && (pev->revents & POLL_X_FLAGS))
+ evmask |= EV_EXCEPT;
+ }
+ return evmask;
+}
+
+/* Iterate through all the event lists (such as connect_events, read_events,
+ * timer_events, etc) and take action for those that have completed (due to
+ * timeout, i/o, etc) */
+void iterate_through_event_lists(struct npool *nsp) {
+ gh_lnode_t *current, *next, *last;
+
+ last = gh_list_last_elem(&nsp->active_iods);
+
+ for (current = gh_list_first_elem(&nsp->active_iods);
+ current != NULL && gh_lnode_prev(current) != last;
+ current = next) {
+ struct niod *nsi = container_of(current, struct niod, nodeq);
+
+ process_iod_events(nsp, nsi, get_evmask(nsp, nsi));
+
+ next = gh_lnode_next(current);
+ if (nsi->state == NSIOD_STATE_DELETED) {
+ gh_list_remove(&nsp->active_iods, current);
+ gh_list_prepend(&nsp->free_iods, current);
+ }
+ }
+
+ /* iterate through timers and expired events */
+ process_expired_events(nsp);
+}
+
+#endif /* HAVE_POLL */
diff --git a/nsock/src/engine_select.c b/nsock/src/engine_select.c
new file mode 100644
index 0000000..edf1b3d
--- /dev/null
+++ b/nsock/src/engine_select.c
@@ -0,0 +1,395 @@
+/***************************************************************************
+ * engine_select.c -- select(2) based IO engine. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifndef WIN32
+#include <sys/select.h>
+#endif
+
+#include <errno.h>
+
+#include "nsock_internal.h"
+#include "nsock_log.h"
+
+#if HAVE_PCAP
+#include "nsock_pcap.h"
+#endif
+
+extern struct io_operations posix_io_operations;
+
+
+/* --- ENGINE INTERFACE PROTOTYPES --- */
+static int select_init(struct npool *nsp);
+static void select_destroy(struct npool *nsp);
+static int select_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev);
+static int select_iod_unregister(struct npool *nsp, struct niod *iod);
+static int select_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr);
+static int select_loop(struct npool *nsp, int msec_timeout);
+
+
+/* ---- ENGINE DEFINITION ---- */
+struct io_engine engine_select = {
+ "select",
+ select_init,
+ select_destroy,
+ select_iod_register,
+ select_iod_unregister,
+ select_iod_modify,
+ select_loop,
+ &posix_io_operations
+};
+
+
+/* --- INTERNAL PROTOTYPES --- */
+static void iterate_through_event_lists(struct npool *nsp);
+
+/* defined in nsock_core.c */
+void process_event(struct npool *nsp, gh_list_t *evlist, struct nevent *nse, int ev);
+void process_iod_events(struct npool *nsp, struct niod *nsi, int ev);
+void process_expired_events(struct npool *nsp);
+
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+int pcap_read_on_nonselect(struct npool *nsp);
+#endif
+#endif
+
+/* defined in nsock_event.c */
+void update_first_events(struct nevent *nse);
+
+
+extern struct timeval nsock_tod;
+
+
+/*
+ * Engine specific data structure
+ */
+struct select_engine_info {
+ /* Descriptors which have pending READ events */
+ fd_set fds_master_r;
+
+ /* Descriptors we are trying to WRITE to */
+ fd_set fds_master_w;
+
+ /* Looking for exceptional events -- used with connect */
+ fd_set fds_master_x;
+
+ /* For keeping track of the select results */
+ fd_set fds_results_r, fds_results_w, fds_results_x;
+
+ /* The highest sd we have set in any of our fd_set's (max_sd + 1 is used in
+ * select() calls). Note that it can be -1, when there are no valid sockets */
+ int max_sd;
+};
+
+
+int select_init(struct npool *nsp) {
+ struct select_engine_info *sinfo;
+
+ sinfo = (struct select_engine_info *)safe_malloc(sizeof(struct select_engine_info));
+
+ FD_ZERO(&sinfo->fds_master_r);
+ FD_ZERO(&sinfo->fds_master_w);
+ FD_ZERO(&sinfo->fds_master_x);
+
+ sinfo->max_sd = -1;
+
+ nsp->engine_data = (void *)sinfo;
+
+ return 1;
+}
+
+void select_destroy(struct npool *nsp) {
+ assert(nsp->engine_data != NULL);
+ free(nsp->engine_data);
+}
+
+int select_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev) {
+ assert(!IOD_PROPGET(iod, IOD_REGISTERED));
+
+ iod->watched_events = ev;
+ select_iod_modify(nsp, iod, nse, ev, EV_NONE);
+ IOD_PROPSET(iod, IOD_REGISTERED);
+ return 1;
+}
+
+int select_iod_unregister(struct npool *nsp, struct niod *iod) {
+ struct select_engine_info *sinfo = (struct select_engine_info *)nsp->engine_data;
+
+ iod->watched_events = EV_NONE;
+
+ /* some IODs can be unregistered here if they're associated to an event that was
+ * immediately completed */
+ if (IOD_PROPGET(iod, IOD_REGISTERED)) {
+#if HAVE_PCAP
+ if (iod->pcap) {
+ int sd = ((mspcap *)iod->pcap)->pcap_desc;
+ if (sd >= 0) {
+ checked_fd_clr(sd, &sinfo->fds_master_r);
+ checked_fd_clr(sd, &sinfo->fds_results_r);
+ }
+ } else
+#endif
+ {
+ checked_fd_clr(iod->sd, &sinfo->fds_master_r);
+ checked_fd_clr(iod->sd, &sinfo->fds_master_w);
+ checked_fd_clr(iod->sd, &sinfo->fds_master_x);
+ checked_fd_clr(iod->sd, &sinfo->fds_results_r);
+ checked_fd_clr(iod->sd, &sinfo->fds_results_w);
+ checked_fd_clr(iod->sd, &sinfo->fds_results_x);
+ }
+
+ if (sinfo->max_sd == iod->sd)
+ sinfo->max_sd--;
+
+ IOD_PROPCLR(iod, IOD_REGISTERED);
+ }
+ return 1;
+}
+
+int select_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr) {
+ int sd;
+ struct select_engine_info *sinfo = (struct select_engine_info *)nsp->engine_data;
+
+ assert((ev_set & ev_clr) == 0);
+
+ iod->watched_events |= ev_set;
+ iod->watched_events &= ~ev_clr;
+
+ ev_set |= EV_EXCEPT;
+ ev_clr &= ~EV_EXCEPT;
+
+ sd = nsock_iod_get_sd(iod);
+
+ /* -- set events -- */
+ if (ev_set & EV_READ)
+ checked_fd_set(sd, &sinfo->fds_master_r);
+
+ if (ev_set & EV_WRITE)
+ checked_fd_set(sd, &sinfo->fds_master_w);
+
+ if (ev_set & EV_EXCEPT)
+ checked_fd_set(sd, &sinfo->fds_master_x);
+
+ /* -- clear events -- */
+ if (ev_clr & EV_READ)
+ checked_fd_clr(sd, &sinfo->fds_master_r);
+
+ if (ev_clr & EV_WRITE)
+ checked_fd_clr(sd, &sinfo->fds_master_w);
+
+ if (ev_clr & EV_EXCEPT)
+ checked_fd_clr(sd, &sinfo->fds_master_x);
+
+
+ /* -- update max_sd -- */
+ if (ev_set != EV_NONE)
+ sinfo->max_sd = MAX(sinfo->max_sd, sd);
+ else if (ev_clr != EV_NONE && iod->events_pending == 1 && (sinfo->max_sd == sd))
+ sinfo->max_sd--;
+
+ return 1;
+}
+
+int select_loop(struct npool *nsp, int msec_timeout) {
+ int results_left = 0;
+ int event_msecs; /* msecs before an event goes off */
+ int combined_msecs;
+ int sock_err = 0;
+ struct timeval select_tv;
+ struct timeval *select_tv_p;
+ struct select_engine_info *sinfo = (struct select_engine_info *)nsp->engine_data;
+
+ assert(msec_timeout >= -1);
+
+ if (nsp->events_pending == 0)
+ return 0; /* No need to wait on 0 events ... */
+
+ do {
+ struct nevent *nse;
+
+ nsock_log_debug_all("wait for events");
+
+ nse = next_expirable_event(nsp);
+ if (!nse)
+ event_msecs = -1; /* None of the events specified a timeout */
+ else
+ event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod));
+
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+ /* Force a low timeout when capturing packets on systems where
+ * the pcap descriptor is not select()able. */
+ if (gh_list_count(&nsp->pcap_read_events))
+ if (event_msecs > PCAP_POLL_INTERVAL)
+ event_msecs = PCAP_POLL_INTERVAL;
+#endif
+#endif
+
+ /* We cast to unsigned because we want -1 to be very high (since it means no
+ * timeout) */
+ combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout);
+
+ /* Set up the timeval pointer we will give to select() */
+ memset(&select_tv, 0, sizeof(select_tv));
+ if (combined_msecs > 0) {
+ select_tv.tv_sec = combined_msecs / 1000;
+ select_tv.tv_usec = (combined_msecs % 1000) * 1000;
+ select_tv_p = &select_tv;
+ } else if (combined_msecs == 0) {
+ /* we want the tv_sec and tv_usec to be zero but they already are from bzero */
+ select_tv_p = &select_tv;
+ } else {
+ assert(combined_msecs == -1);
+ select_tv_p = NULL;
+ }
+
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+ /* do non-blocking read on pcap devices that doesn't support select()
+ * If there is anything read, just leave this loop. */
+ if (pcap_read_on_nonselect(nsp)) {
+ /* okay, something was read. */
+ } else
+#endif
+#endif
+ {
+ /* Set up the descriptors for select */
+ sinfo->fds_results_r = sinfo->fds_master_r;
+ sinfo->fds_results_w = sinfo->fds_master_w;
+ sinfo->fds_results_x = sinfo->fds_master_x;
+
+ results_left = fselect(sinfo->max_sd + 1, &sinfo->fds_results_r,
+ &sinfo->fds_results_w, &sinfo->fds_results_x, select_tv_p);
+
+ if (results_left == -1)
+ sock_err = socket_errno();
+ }
+
+ gettimeofday(&nsock_tod, NULL); /* Due to select delay */
+ } while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */
+
+ if (results_left == -1 && sock_err != EINTR) {
+ nsock_log_error("nsock_loop error %d: %s", sock_err, socket_strerror(sock_err));
+ nsp->errnum = sock_err;
+ return -1;
+ }
+
+ iterate_through_event_lists(nsp);
+
+ return 1;
+}
+
+
+/* ---- INTERNAL FUNCTIONS ---- */
+
+static inline int get_evmask(const struct npool *nsp, const struct niod *nsi) {
+ struct select_engine_info *sinfo = (struct select_engine_info *)nsp->engine_data;
+ int sd, evmask;
+
+ evmask = EV_NONE;
+
+#if HAVE_PCAP
+#ifndef PCAP_CAN_DO_SELECT
+ if (nsi->pcap) {
+ /* Always assume readable for a non-blocking read. We can't check checked_fd_isset
+ because we don't have a pcap_desc. */
+ evmask |= EV_READ;
+ return evmask;
+ }
+#endif
+#endif
+
+#if HAVE_PCAP
+ if (nsi->pcap)
+ sd = ((mspcap *)nsi->pcap)->pcap_desc;
+ else
+#endif
+ sd = nsi->sd;
+
+ assert(sd >= 0);
+
+ if (checked_fd_isset(sd, &sinfo->fds_results_r))
+ evmask |= EV_READ;
+ if (checked_fd_isset(sd, &sinfo->fds_results_w))
+ evmask |= EV_WRITE;
+ if (checked_fd_isset(sd, &sinfo->fds_results_x))
+ evmask |= EV_EXCEPT;
+
+ return evmask;
+}
+
+/* Iterate through all the event lists (such as connect_events, read_events,
+ * timer_events, etc) and take action for those that have completed (due to
+ * timeout, i/o, etc) */
+void iterate_through_event_lists(struct npool *nsp) {
+ gh_lnode_t *current, *next, *last;
+
+ last = gh_list_last_elem(&nsp->active_iods);
+
+ for (current = gh_list_first_elem(&nsp->active_iods);
+ current != NULL && gh_lnode_prev(current) != last;
+ current = next) {
+ struct niod *nsi = container_of(current, struct niod, nodeq);
+
+ if (nsi->state != NSIOD_STATE_DELETED && nsi->events_pending)
+ process_iod_events(nsp, nsi, get_evmask(nsp, nsi));
+
+ next = gh_lnode_next(current);
+ if (nsi->state == NSIOD_STATE_DELETED) {
+ gh_list_remove(&nsp->active_iods, current);
+ gh_list_prepend(&nsp->free_iods, current);
+ }
+ }
+
+ /* iterate through timers and expired events */
+ process_expired_events(nsp);
+}
diff --git a/nsock/src/error.c b/nsock/src/error.c
new file mode 100644
index 0000000..c7ecf98
--- /dev/null
+++ b/nsock/src/error.c
@@ -0,0 +1,85 @@
+/***************************************************************************
+ * error.c -- a few simple routines for dealing with errors (quitting, *
+ * printing error messages, etc. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include "error.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+void fatal(char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ fflush(stdout);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+
+ exit(1);
+}
+
+void pfatal(char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ fflush(stdout);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ": ");
+ perror("");
+ fprintf(stderr, "\n");
+ va_end(ap);
+
+ exit(1);
+}
+
diff --git a/nsock/src/error.h b/nsock/src/error.h
new file mode 100644
index 0000000..48a7684
--- /dev/null
+++ b/nsock/src/error.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+ * error.h -- a few simple routines for dealing with errors (quitting, *
+ * printing error messages, etc. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifndef ERROR_H
+#define ERROR_H
+
+#ifdef HAVE_CONFIG_H
+#include "nsock_config.h"
+#include "nbase_config.h"
+#endif
+
+#ifdef WIN32
+#include "nbase_winconfig.h"
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if defined(__GNUC__)
+#define NORETURN __attribute__((noreturn))
+#elif defined(_MSC_VER)
+#define NORETURN __declspec(noreturn)
+#else
+#define NORETURN
+#endif
+
+NORETURN void fatal(char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+NORETURN void pfatal(char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+#endif /* ERROR_H */
diff --git a/nsock/src/filespace.c b/nsock/src/filespace.c
new file mode 100644
index 0000000..f4d5638
--- /dev/null
+++ b/nsock/src/filespace.c
@@ -0,0 +1,114 @@
+/***************************************************************************
+ * filespace.c -- a simple mechanism for storing dynamic amounts of data *
+ * in a simple to use, and quick to append-to structure. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include "nsock_internal.h"
+#include "filespace.h"
+
+#include <string.h>
+
+#define FS_INITSIZE_DEFAULT 1024
+
+
+/* Assumes space for fs has already been allocated */
+int filespace_init(struct filespace *fs, int initial_size) {
+ memset(fs, 0, sizeof(struct filespace));
+ if (initial_size == 0)
+ initial_size = FS_INITSIZE_DEFAULT;
+
+ fs->current_alloc = initial_size;
+ fs->str = (char *)safe_malloc(fs->current_alloc);
+ fs->str[0] = '\0';
+ fs->pos = fs->str;
+ return 0;
+}
+
+int fs_free(struct filespace *fs) {
+ if (fs->str)
+ free(fs->str);
+
+ fs->current_alloc = fs->current_size = 0;
+ fs->pos = fs->str = NULL;
+ return 0;
+}
+
+/* Concatenate a string to the end of a filespace */
+int fs_cat(struct filespace *fs, const char *str, int len) {
+ if (len < 0)
+ return -1;
+
+ if (len == 0)
+ return 0;
+
+ if (fs->current_alloc - fs->current_size < len + 2) {
+ char *tmpstr;
+
+ fs->current_alloc = (int)(fs->current_alloc * 1.4 + 1);
+ fs->current_alloc += 100 + len;
+
+ tmpstr = (char *)safe_malloc(fs->current_alloc);
+ memcpy(tmpstr, fs->str, fs->current_size);
+
+ fs->pos = (fs->pos - fs->str) + tmpstr;
+
+ if (fs->str)
+ free(fs->str);
+
+ fs->str = tmpstr;
+ }
+ memcpy(fs->str + fs->current_size, str, len);
+
+ fs->current_size += len;
+ fs->str[fs->current_size] = '\0';
+ return 0;
+}
+
diff --git a/nsock/src/filespace.h b/nsock/src/filespace.h
new file mode 100644
index 0000000..cc44a9a
--- /dev/null
+++ b/nsock/src/filespace.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+ * filespace.h -- a simple mechanism for storing dynamic amounts of data *
+ * in a simple to use, and quick to append-to structure. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifndef FILESPACE_H
+#define FILESPACE_H
+
+#ifdef HAVE_CONFIG_H
+#include "nsock_config.h"
+#include "nbase_config.h"
+#endif
+
+#ifdef WIN32
+#include "nbase_winconfig.h"
+#endif
+
+#include <stdlib.h>
+#include <stdarg.h>
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+
+struct filespace {
+ int current_size;
+ int current_alloc;
+
+ /* Current position in the filespace */
+ char *pos;
+ char *str;
+};
+
+
+static inline int fs_length(const struct filespace *fs) {
+ return fs->current_size;
+}
+
+static inline char *fs_str(const struct filespace *fs) {
+ return fs->str;
+}
+
+
+int filespace_init(struct filespace *fs, int initial_size);
+
+int fs_free(struct filespace *fs);
+
+int fs_cat(struct filespace *fs, const char *str, int len);
+
+#endif /* FILESPACE_H */
+
diff --git a/nsock/src/gh_heap.c b/nsock/src/gh_heap.c
new file mode 100644
index 0000000..2176574
--- /dev/null
+++ b/nsock/src/gh_heap.c
@@ -0,0 +1,250 @@
+/***************************************************************************
+ * gh_heap.c -- heap based priority queue. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "nsock_config.h"
+#include "nbase_config.h"
+#endif
+
+#ifdef WIN32
+#include "nbase_winconfig.h"
+#endif
+
+#include <nbase.h>
+#include "gh_heap.h"
+
+#define GH_SLOTS 128
+
+
+static gh_hnode_t **hnode_ptr(gh_heap_t *heap, unsigned int index) {
+ assert(index <= heap->count);
+ gh_hnode_t **ptr = &(heap->slots[index]);
+ assert(index == heap->count || (*ptr)->index == index);
+ return ptr;
+}
+
+gh_hnode_t *gh_heap_find(gh_heap_t *heap, unsigned int index) {
+ if (index >= heap->count)
+ return NULL;
+
+ return *hnode_ptr(heap, index);
+}
+
+static int hnode_up(gh_heap_t *heap, gh_hnode_t *hnode)
+{
+ unsigned int cur_idx = hnode->index;
+ gh_hnode_t **cur_ptr = hnode_ptr(heap, cur_idx);
+ unsigned int parent_idx;
+ gh_hnode_t **parent_ptr;
+ int action = 0;
+
+ assert(*cur_ptr == hnode);
+
+ while (cur_idx > 0) {
+ parent_idx = (cur_idx - 1) >> 1;
+
+ parent_ptr = hnode_ptr(heap, parent_idx);
+
+ if (heap->cmp_op(*parent_ptr, hnode))
+ break;
+
+ (*parent_ptr)->index = cur_idx;
+ *cur_ptr = *parent_ptr;
+ cur_ptr = parent_ptr;
+ cur_idx = parent_idx;
+ action = 1;
+ }
+
+ hnode->index = cur_idx;
+ *cur_ptr = hnode;
+
+ return action;
+}
+
+static int hnode_down(gh_heap_t *heap, gh_hnode_t *hnode)
+{
+ unsigned int count = heap->count;
+ unsigned int ch1_idx, ch2_idx, cur_idx;
+ gh_hnode_t **ch1_ptr, **ch2_ptr, **cur_ptr;
+ gh_hnode_t *ch1, *ch2;
+ int action = 0;
+
+ cur_idx = hnode->index;
+ cur_ptr = hnode_ptr(heap, cur_idx);
+ assert(*cur_ptr == hnode);
+
+ while (cur_idx < count) {
+ ch1_idx = (cur_idx << 1) + 1;
+ if (ch1_idx >= count)
+ break;
+
+ ch1_ptr = hnode_ptr(heap, ch1_idx);
+ ch1 = *ch1_ptr;
+
+ ch2_idx = ch1_idx + 1;
+ if (ch2_idx < count) {
+ ch2_ptr = hnode_ptr(heap, ch2_idx);
+ ch2 = *ch2_ptr;
+
+ if (heap->cmp_op(ch2, ch1)) {
+ ch1_idx = ch2_idx;
+ ch1_ptr = ch2_ptr;
+ ch1 = ch2;
+ }
+ }
+
+ assert(ch1->index == ch1_idx);
+
+ if (heap->cmp_op(hnode, ch1))
+ break;
+
+ ch1->index = cur_idx;
+ *cur_ptr = ch1;
+ cur_ptr = ch1_ptr;
+ cur_idx = ch1_idx;
+ action = 1;
+ }
+
+ hnode->index = cur_idx;
+ *cur_ptr = hnode;
+
+ return action;
+}
+
+static int heap_grow(gh_heap_t *heap) {
+ int newsize;
+
+ /* Do we really need to grow? */
+ assert(heap->count == heap->highwm);
+
+ newsize = heap->count + GH_SLOTS;
+ heap->slots = (gh_hnode_t **)safe_realloc(heap->slots,
+ newsize * sizeof(gh_hnode_t *));
+ heap->highwm += GH_SLOTS;
+ memset(heap->slots + heap->count, 0, GH_SLOTS * sizeof(gh_hnode_t *));
+ return 0;
+}
+
+int gh_heap_init(gh_heap_t *heap, gh_heap_cmp_t cmp_op) {
+ int rc;
+
+ if (!cmp_op)
+ return -1;
+
+ heap->cmp_op = cmp_op;
+ heap->count = 0;
+ heap->highwm = 0;
+ heap->slots = NULL;
+
+ rc = heap_grow(heap);
+ if (rc)
+ gh_heap_free(heap);
+
+ return rc;
+}
+
+void gh_heap_free(gh_heap_t *heap) {
+ if (heap->highwm) {
+ assert(heap->slots);
+ free(heap->slots);
+ }
+ memset(heap, 0, sizeof(gh_heap_t));
+}
+
+int gh_heap_push(gh_heap_t *heap, gh_hnode_t *hnode) {
+ gh_hnode_t **new_ptr;
+ unsigned int new_index = heap->count;
+
+ assert(!gh_hnode_is_valid(hnode));
+
+ if (new_index == heap->highwm)
+ heap_grow(heap);
+
+ hnode->index = new_index;
+ new_ptr = hnode_ptr(heap, new_index);
+ assert(*new_ptr == NULL);
+ heap->count++;
+ *new_ptr = hnode;
+
+ hnode_up(heap, hnode);
+ return 0;
+}
+
+int gh_heap_remove(gh_heap_t *heap, gh_hnode_t *hnode)
+{
+ unsigned int count = heap->count;
+ unsigned int cur_idx = hnode->index;
+ gh_hnode_t **cur_ptr;
+ gh_hnode_t *last;
+
+ assert(gh_hnode_is_valid(hnode));
+ assert(cur_idx < count);
+
+ cur_ptr = hnode_ptr(heap, cur_idx);
+ assert(*cur_ptr == hnode);
+
+ count--;
+ last = *hnode_ptr(heap, count);
+ heap->count = count;
+ if (last != hnode)
+ {
+ last->index = cur_idx;
+ *cur_ptr = last;
+ if (!hnode_up(heap, *cur_ptr))
+ hnode_down(heap, *cur_ptr);
+ }
+
+ gh_hnode_invalidate(hnode);
+ cur_ptr = hnode_ptr(heap, count);
+ *cur_ptr = NULL;
+ return 0;
+}
diff --git a/nsock/src/gh_heap.h b/nsock/src/gh_heap.h
new file mode 100644
index 0000000..0e67d9c
--- /dev/null
+++ b/nsock/src/gh_heap.h
@@ -0,0 +1,143 @@
+/***************************************************************************
+ * gh_heap.h -- heap based priority queues. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifndef GH_HEAP_H
+#define GH_HEAP_H
+
+#ifdef HAVE_CONFIG_H
+#include "nsock_config.h"
+#include "nbase_config.h"
+#endif
+
+#ifdef WIN32
+#include "nbase_winconfig.h"
+#endif
+
+#include "error.h"
+#include <assert.h>
+
+
+#if !defined(container_of)
+#include <stddef.h>
+
+#define container_of(ptr, type, member) \
+ ((type *)((char *)(ptr) - offsetof(type, member)))
+#endif
+
+
+typedef struct {
+ unsigned int index;
+} gh_hnode_t;
+
+/* POISON value, set heap node index to this value to indicate that the node is
+ * inactive (not part of a heap) */
+#define GH_HEAP_GUARD 0x19890721
+
+/* Node comparison function.
+ * Here lies all the intelligence of the tree.
+ * Return 1 if hnode1 < hnode2, 0 otherwise. */
+typedef int (*gh_heap_cmp_t)(gh_hnode_t *hnode1, gh_hnode_t *hnode2);
+
+
+typedef struct gh_heap {
+ gh_heap_cmp_t cmp_op;
+ unsigned int count;
+ unsigned int highwm;
+ gh_hnode_t **slots;
+} gh_heap_t;
+
+
+int gh_heap_init(gh_heap_t *heap, gh_heap_cmp_t cmp_op);
+
+void gh_heap_free(gh_heap_t *heap);
+
+int gh_heap_push(gh_heap_t *heap, gh_hnode_t *node);
+
+int gh_heap_remove(gh_heap_t *heap, gh_hnode_t *node);
+
+gh_hnode_t *gh_heap_find(gh_heap_t *heap, unsigned int index);
+
+
+static inline gh_hnode_t *gh_heap_min(gh_heap_t *heap) {
+ if (heap->count == 0)
+ return NULL;
+
+ return gh_heap_find(heap, 0);
+}
+
+static inline gh_hnode_t *gh_heap_pop(gh_heap_t *heap) {
+ gh_hnode_t *hnode;
+
+ hnode = gh_heap_find(heap, 0);
+ if (hnode != NULL)
+ gh_heap_remove(heap, hnode);
+
+ return hnode;
+}
+
+static inline size_t gh_heap_count(gh_heap_t *heap) {
+ return heap->count;
+}
+
+static inline int gh_heap_is_empty(gh_heap_t *heap) {
+ return heap->count == 0;
+}
+
+static inline void gh_hnode_invalidate(gh_hnode_t *node) {
+ node->index = GH_HEAP_GUARD;
+}
+
+static inline int gh_hnode_is_valid(const gh_hnode_t *node) {
+ return (node && node->index != GH_HEAP_GUARD);
+}
+
+#endif /* GH_HEAP_H */
diff --git a/nsock/src/gh_list.h b/nsock/src/gh_list.h
new file mode 100644
index 0000000..32f383e
--- /dev/null
+++ b/nsock/src/gh_list.h
@@ -0,0 +1,296 @@
+/***************************************************************************
+ * gh_list.h -- a simple doubly-linked list implementation. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifndef GH_LIST_H
+#define GH_LIST_H
+
+#ifdef HAVE_CONFIG_H
+#include "nsock_config.h"
+#include "nbase_config.h"
+#endif
+
+#ifdef WIN32
+#include "nbase_winconfig.h"
+#endif
+
+#include "error.h"
+#include <assert.h>
+
+#define GH_LIST_MAGIC 0xBADFACE
+#ifndef GH_LIST_PARANOID
+#define GH_LIST_PARANOID 0
+#endif
+
+
+typedef struct gh_list_node {
+ struct gh_list_node *next;
+ struct gh_list_node *prev;
+} gh_lnode_t;
+
+typedef struct gh_list {
+ /* Number of elements in the list */
+ unsigned int count;
+ gh_lnode_t *first;
+ gh_lnode_t *last;
+} gh_list_t;
+
+
+/* That one's an efficiency killer but it should reveal
+ * any inconsistency in nsock's lists management. To be
+ * called on every list we get and return. */
+static inline void paranoid_list_check(gh_list_t *list) {
+#if GH_LIST_PARANOID
+ switch (list->count) {
+ case 0:
+ assert(list->first == NULL);
+ assert(list->last == NULL);
+ break;
+
+ case 1:
+ assert(list->first);
+ assert(list->last);
+ assert(list->first == list->last);
+ break;
+
+ default:
+ assert(list->first);
+ assert(list->last);
+ assert(list->first != list->last);
+ break;
+ }
+#endif
+}
+
+static inline int gh_list_init(gh_list_t *newlist) {
+ newlist->count = 0;
+ newlist->first = NULL;
+ newlist->last = NULL;
+ return 0;
+}
+
+static inline int gh_list_append(gh_list_t *list, gh_lnode_t *lnode) {
+ gh_lnode_t *oldlast;
+
+ paranoid_list_check(list);
+
+ oldlast = list->last;
+ if (oldlast)
+ oldlast->next = lnode;
+
+ lnode->prev = oldlast;
+ lnode->next = NULL;
+
+ list->count++;
+ list->last = lnode;
+
+ if (list->count == 1)
+ list->first = lnode;
+
+ paranoid_list_check(list);
+ return 0;
+}
+
+static inline int gh_list_prepend(gh_list_t *list, gh_lnode_t *lnode) {
+ gh_lnode_t *oldfirst;
+
+ paranoid_list_check(list);
+
+ oldfirst = list->first;
+ if (oldfirst)
+ oldfirst->prev = lnode;
+
+ lnode->next = oldfirst;
+ lnode->prev = NULL;
+
+ list->count++;
+ list->first = lnode;
+
+ if (list->count == 1)
+ list->last = lnode;
+
+ paranoid_list_check(list);
+ return 0;
+}
+
+static inline int gh_list_insert_before(gh_list_t *list, gh_lnode_t *before,
+ gh_lnode_t *lnode) {
+ paranoid_list_check(list);
+
+ lnode->prev = before->prev;
+ lnode->next = before;
+
+ if (before->prev)
+ before->prev->next = lnode;
+ else
+ list->first = lnode;
+
+ before->prev = lnode;
+ list->count++;
+
+ paranoid_list_check(list);
+ return 0;
+}
+
+static inline gh_lnode_t *gh_list_pop(gh_list_t *list) {
+ gh_lnode_t *elem;
+
+ paranoid_list_check(list);
+
+ elem = list->first;
+ if (!elem) {
+ paranoid_list_check(list);
+ return NULL;
+ }
+
+ list->first = list->first->next;
+ if (list->first)
+ list->first->prev = NULL;
+
+ list->count--;
+
+ if (list->count < 2)
+ list->last = list->first;
+
+ elem->prev = NULL;
+ elem->next = NULL;
+
+ paranoid_list_check(list);
+ return elem;
+}
+
+static inline int gh_list_remove(gh_list_t *list, gh_lnode_t *lnode) {
+ paranoid_list_check(list);
+
+ if (lnode->prev) {
+ lnode->prev->next = lnode->next;
+ } else {
+ assert(list->first == lnode);
+ list->first = lnode->next;
+ }
+
+ if (lnode->next) {
+ lnode->next->prev = lnode->prev;
+ } else {
+ assert(list->last == lnode);
+ list->last = lnode->prev;
+ }
+
+ lnode->prev = NULL;
+ lnode->next = NULL;
+
+ list->count--;
+
+ paranoid_list_check(list);
+ return 0;
+}
+
+static inline int gh_list_free(gh_list_t *list) {
+ paranoid_list_check(list);
+
+ while (list->count > 0)
+ gh_list_pop(list);
+
+ paranoid_list_check(list);
+ memset(list, 0, sizeof(gh_list_t));
+ return 0;
+}
+
+static inline int gh_list_move_front(gh_list_t *list, gh_lnode_t *lnode) {
+ paranoid_list_check(list);
+ if (list->first == lnode)
+ return 0;
+
+ /* remove element from its current position */
+ lnode->prev->next = lnode->next;
+
+ if (lnode->next) {
+ lnode->next->prev = lnode->prev;
+ } else {
+ assert(list->last == lnode);
+ list->last = lnode->prev;
+ }
+
+ /* add element to the beginning of the list */
+ list->first->prev = lnode;
+ lnode->next = list->first;
+ lnode->prev = NULL;
+ list->first = lnode;
+
+ paranoid_list_check(list);
+ return 0;
+}
+
+/* Take a LIST ELEMENT (not just the data) and return the next one */
+static inline gh_lnode_t *gh_lnode_next(gh_lnode_t *elem) {
+ return elem->next;
+}
+
+/* Same as above but return the previous element */
+static inline gh_lnode_t *gh_lnode_prev(gh_lnode_t *elem) {
+ return elem->prev;
+}
+
+/* Take a LIST (not a list element) and return the first element */
+static inline gh_lnode_t *gh_list_first_elem(gh_list_t *list) {
+ return list->first;
+}
+
+/* Same as above but return the last element */
+static inline gh_lnode_t *gh_list_last_elem(gh_list_t *list) {
+ return list->last;
+}
+
+static inline unsigned int gh_list_count(gh_list_t *list) {
+ return list->count;
+}
+
+#endif /* GH_LIST_H */
diff --git a/nsock/src/netutils.c b/nsock/src/netutils.c
new file mode 100644
index 0000000..4523203
--- /dev/null
+++ b/nsock/src/netutils.c
@@ -0,0 +1,183 @@
+/***************************************************************************
+ * netutils.c -- This contains some useful little network/socket related *
+ * utility functions. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include "netutils.h"
+#include "error.h"
+
+#if WIN32
+#include "Winsock2.h"
+#endif
+
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#if HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
+static int netutils_debugging = 0;
+
+/* maximize the number of file descriptors (including sockets) allowed for this
+ * process and return that maximum value (note -- you better not actually open
+ * this many -- stdin, stdout, other files opened by libraries you use, etc. all
+ * count toward this limit. Leave a little slack */
+rlim_t maximize_fdlimit(void) {
+
+#ifndef WIN32
+ struct rlimit r;
+ static int maxfds_set = 0;
+ static rlim_t maxfds = 0;
+
+ if (maxfds_set)
+ return maxfds;
+
+#ifndef RLIMIT_NOFILE
+ #ifdef RLIMIT_OFILE
+ #define RLIMIT_NOFILE RLIMIT_OFILE
+ #else
+ #error Neither RLIMIT_NOFILE nor RLIMIT_OFILE defined
+ #endif
+#endif
+ if (!getrlimit(RLIMIT_NOFILE, &r)) {
+ maxfds = r.rlim_cur;
+ r.rlim_cur = r.rlim_max;
+ if (!setrlimit(RLIMIT_NOFILE, &r))
+ if (netutils_debugging)
+ perror("setrlimit RLIMIT_NOFILE failed");
+
+ if (!getrlimit(RLIMIT_NOFILE, &r)) {
+ maxfds = r.rlim_cur;
+ }
+ maxfds_set = 1;
+ return maxfds;
+ }
+#endif /* !WIN32 */
+ return 0;
+}
+
+#if HAVE_SYS_UN_H
+ #define PEER_STR_LEN sizeof(((struct sockaddr_un *) 0)->sun_path)
+#else
+ #define PEER_STR_LEN sizeof("[ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]:xxxxx")
+#endif
+
+#if HAVE_SYS_UN_H
+/* Get the UNIX domain socket path or empty string if the address family != AF_UNIX. */
+const char *get_unixsock_path(const struct sockaddr_storage *addr) {
+ struct sockaddr_un *su = (struct sockaddr_un *)addr;
+
+ if (!addr || addr->ss_family != AF_UNIX)
+ return "";
+
+ return (const char *)su->sun_path;
+}
+#endif
+
+static int get_port(const struct sockaddr_storage *ss) {
+ if (ss->ss_family == AF_INET)
+ return ntohs(((struct sockaddr_in *) ss)->sin_port);
+#if HAVE_IPV6
+ else if (ss->ss_family == AF_INET6)
+ return ntohs(((struct sockaddr_in6 *) ss)->sin6_port);
+#endif
+
+ return -1;
+}
+
+static char *get_addr_string(const struct sockaddr_storage *ss, size_t sslen) {
+ static char buffer[PEER_STR_LEN];
+
+#if HAVE_SYS_UN_H
+ if (ss->ss_family == AF_UNIX) {
+ sprintf(buffer, "%s", get_unixsock_path(ss));
+ return buffer;
+ }
+#endif
+
+ sprintf(buffer, "%s:%d", inet_ntop_ez(ss, sslen), get_port(ss));
+ return buffer;
+}
+
+/* Get the peer/host address string.
+ * In case we have support for UNIX domain sockets, function returns
+ * string containing path to UNIX socket if the address family is AF_UNIX,
+ * otherwise it returns string containing "<address>:<port>". */
+char *get_peeraddr_string(const struct niod *iod) {
+ if (iod->peerlen > 0)
+ return get_addr_string(&iod->peer, iod->peerlen);
+ else
+ return "peer unspecified";
+}
+
+/* Get the local bind address string. */
+char *get_localaddr_string(const struct niod *iod) {
+ return get_addr_string(&iod->local, iod->locallen);
+}
diff --git a/nsock/src/netutils.h b/nsock/src/netutils.h
new file mode 100644
index 0000000..893a9f6
--- /dev/null
+++ b/nsock/src/netutils.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+ * netutils.h -- This contains some useful little network/socket related *
+ * utility functions. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifndef NETUTILS_H
+#define NETUTILS_H
+
+#ifdef HAVE_CONFIG_H
+#include "nsock_config.h"
+#include "nbase_config.h"
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include "nsock_internal.h"
+
+#ifdef WIN32
+#include "nbase_winconfig.h"
+/* nbase_winunix.h somehow reason.h to get included */
+#include "nbase_winunix.h"
+#endif
+
+#if HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#else
+#ifndef rlim_t
+#define rlim_t int
+#endif
+#endif
+/* Maximize the number of file descriptors (including sockets) allowed for this
+ * process and return that maximum value (note -- you better not actually open
+ * this many -- stdin, stdout, other files opened by libraries you use, etc. all
+ * count toward this limit. Leave a little slack */
+rlim_t maximize_fdlimit(void);
+
+/* Get the UNIX domain socket path or empty string if the address family != AF_UNIX. */
+const char *get_unixsock_path(const struct sockaddr_storage *addr);
+
+/* Get the peer address string. In case of a Unix domain socket, returns the
+ * path to UNIX socket, otherwise it returns string containing
+ * "<address>:<port>". */
+char *get_peeraddr_string(const struct niod *iod);
+
+/* Get the local bind address string. */
+char *get_localaddr_string(const struct niod *iod);
+
+#endif /* NETUTILS_H */
+
diff --git a/nsock/src/nsock_connect.c b/nsock/src/nsock_connect.c
new file mode 100644
index 0000000..7d2b523
--- /dev/null
+++ b/nsock/src/nsock_connect.c
@@ -0,0 +1,652 @@
+/***************************************************************************
+ * nsock_connect.c -- This contains the functions for requesting TCP *
+ * connections from the nsock parallel socket event library *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include "nsock.h"
+#include "nsock_internal.h"
+#include "nsock_log.h"
+#include "nsock_proxy.h"
+#include "netutils.h"
+
+#include <sys/types.h>
+#include <errno.h>
+#include <string.h>
+
+
+static int mksock_bind_addr(struct npool *ms, struct niod *iod) {
+ int rc;
+ int one = 1;
+
+ rc = setsockopt(iod->sd, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, sizeof(one));
+ if (rc == -1) {
+ int err = socket_errno();
+
+ nsock_log_error("Setting of SO_REUSEADDR failed (#%li): %s (%d)", iod->id,
+ socket_strerror(err), err);
+ }
+
+ nsock_log_info("Binding to %s (IOD #%li)", get_localaddr_string(iod), iod->id);
+ rc = bind(iod->sd, (struct sockaddr *)&iod->local, (int) iod->locallen);
+ if (rc == -1) {
+ int err = socket_errno();
+
+ nsock_log_error("Bind to %s failed (IOD #%li): %s (%d)",
+ get_localaddr_string(iod), iod->id,
+ socket_strerror(err), err);
+ }
+ return 0;
+}
+
+static int mksock_set_ipopts(struct npool *ms, struct niod *iod) {
+ int rc;
+
+ errno = 0;
+ rc = setsockopt(iod->sd, IPPROTO_IP, IP_OPTIONS, (const char *)iod->ipopts,
+ iod->ipoptslen);
+ if (rc == -1) {
+ int err = socket_errno();
+
+ nsock_log_error("Setting of IP options failed (IOD #%li): %s (%d)",
+ iod->id, socket_strerror(err), err);
+ }
+ return 0;
+}
+
+static int mksock_bind_device(struct npool *ms, struct niod *iod) {
+ int rc;
+
+ rc = socket_bindtodevice(iod->sd, ms->device);
+ if (!rc) {
+ int err = socket_errno();
+
+ if (err != EPERM)
+ nsock_log_error("Setting of SO_BINDTODEVICE failed (IOD #%li): %s (%d)",
+ iod->id, socket_strerror(err), err);
+ else
+ nsock_log_debug_all("Setting of SO_BINDTODEVICE failed (IOD #%li): %s (%d)",
+ iod->id, socket_strerror(err), err);
+ }
+ return 0;
+}
+
+static int mksock_set_broadcast(struct npool *ms, struct niod *iod) {
+ int rc;
+ int one = 1;
+
+ rc = setsockopt(iod->sd, SOL_SOCKET, SO_BROADCAST,
+ (const char *)&one, sizeof(one));
+ if (rc == -1) {
+ int err = socket_errno();
+
+ nsock_log_error("Setting of SO_BROADCAST failed (IOD #%li): %s (%d)",
+ iod->id, socket_strerror(err), err);
+ }
+ return 0;
+}
+/* Create the actual socket (nse->iod->sd) underlying the iod. This unblocks the
+ * socket, binds to the localaddr address, sets IP options, and sets the
+ * broadcast flag. Trying to change these functions after making this call will
+ * not have an effect. This function needs to be called before you try to read
+ * or write on the iod. */
+static int nsock_make_socket(struct npool *ms, struct niod *iod, int family, int type, int proto) {
+
+ /* inheritable_socket is from nbase */
+ iod->sd = (int)inheritable_socket(family, type, proto);
+ if (iod->sd == -1) {
+ nsock_log_error("Socket trouble: %s", socket_strerror(socket_errno()));
+ return -1;
+ }
+
+ unblock_socket(iod->sd);
+
+ iod->lastproto = proto;
+
+ if (iod->locallen)
+ mksock_bind_addr(ms, iod);
+
+ if (iod->ipoptslen && family == AF_INET)
+ mksock_set_ipopts(ms, iod);
+
+ if (ms->device)
+ mksock_bind_device(ms, iod);
+
+ if (ms->broadcast && type != SOCK_STREAM)
+ mksock_set_broadcast(ms, iod);
+
+ /* mksock_* functions can raise warnings/errors
+ * but we don't let them stop us for now. */
+ return iod->sd;
+}
+
+int nsock_setup_udp(nsock_pool nsp, nsock_iod ms_iod, int af) {
+ struct npool *ms = (struct npool *)nsp;
+ struct niod *nsi = (struct niod *)ms_iod;
+
+ assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);
+
+ nsock_log_info("UDP unconnected socket (IOD #%li)", nsi->id);
+
+ if (nsock_make_socket(ms, nsi, af, SOCK_DGRAM, IPPROTO_UDP) == -1)
+ return -1;
+
+ return nsi->sd;
+}
+
+/* This does the actual logistics of requesting a connection. It is shared
+ * by nsock_connect_tcp and nsock_connect_ssl, among others */
+void nsock_connect_internal(struct npool *ms, struct nevent *nse, int type, int proto, struct sockaddr_storage *ss, size_t sslen,
+ unsigned int port) {
+
+ struct sockaddr_in *sin;
+#if HAVE_IPV6
+ struct sockaddr_in6 *sin6;
+#endif
+ struct niod *iod = nse->iod;
+
+ if (iod->px_ctx /* proxy enabled */
+ && proto == IPPROTO_TCP /* restrict proxying to TCP connections */
+ && (nse->handler != nsock_proxy_ev_dispatch)) { /* for reentrancy */
+ struct proxy_node *current;
+
+ nsock_log_debug_all("TCP connection request (EID %lu) redirected through proxy chain",
+ (long)nse->id);
+
+ current = iod->px_ctx->px_current;
+ assert(current != NULL);
+
+ memcpy(&iod->px_ctx->target_ss, ss, sslen);
+ iod->px_ctx->target_sslen = sslen;
+ iod->px_ctx->target_port = port;
+
+ ss = &current->ss;
+ sslen = current->sslen;
+ port = current->port;
+
+ iod->px_ctx->target_handler = nse->handler;
+ nse->handler = nsock_proxy_ev_dispatch;
+
+ iod->px_ctx->target_ev_type = nse->type;
+ nse->type = NSE_TYPE_CONNECT;
+ }
+
+ sin = (struct sockaddr_in *)ss;
+#if HAVE_IPV6
+ sin6 = (struct sockaddr_in6 *)ss;
+#endif
+
+ /* Now it is time to actually attempt the connection */
+ if (nsock_make_socket(ms, iod, ss->ss_family, type, proto) == -1) {
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_ERROR;
+ nse->errnum = socket_errno();
+ } else {
+ if (ss->ss_family == AF_INET) {
+ sin->sin_port = htons(port);
+ }
+#if HAVE_IPV6
+ else if (ss->ss_family == AF_INET6) {
+ sin6->sin6_port = htons(port);
+ }
+#endif
+#if HAVE_SYS_UN_H
+ else if (ss->ss_family == AF_UNIX) {
+ /* Nothing more to do for Unix socket */
+ }
+#endif
+#if HAVE_LINUX_VM_SOCKETS_H
+ else if (ss->ss_family == AF_VSOCK) {
+ struct sockaddr_vm *svm = (struct sockaddr_vm *)ss;
+
+ svm->svm_port = port;
+ }
+#endif
+ else {
+ fatal("Unknown address family %d\n", ss->ss_family);
+ }
+
+ assert(sslen <= sizeof(iod->peer));
+ if (&iod->peer != ss)
+ memcpy(&iod->peer, ss, sslen);
+ iod->peerlen = sslen;
+
+ if (ms->engine->io_operations->iod_connect(ms, iod->sd, (struct sockaddr *)ss, sslen) == -1) {
+ int err = socket_errno();
+
+ if ((proto == IPPROTO_UDP) || (err != EINPROGRESS && err != EAGAIN)) {
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_ERROR;
+ nse->errnum = err;
+ }
+ }
+ /* The callback handle_connect_result handles the connection once it completes. */
+ }
+}
+
+#if HAVE_SYS_UN_H
+
+/* Request a UNIX domain sockets connection to the same system (by path to socket).
+ * This function connects to the socket of type SOCK_STREAM. ss should be a
+ * sockaddr_storage, sockaddr_un as appropriate (just like what you would pass to
+ * connect). sslen should be the sizeof the structure you are passing in. */
+nsock_event_id nsock_connect_unixsock_stream(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs,
+ void *userdata, struct sockaddr *saddr, size_t sslen) {
+ struct niod *nsi = (struct niod *)nsiod;
+ struct npool *ms = (struct npool *)nsp;
+ struct nevent *nse;
+ struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;
+
+ assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);
+
+ nse = event_new(ms, NSE_TYPE_CONNECT, nsi, timeout_msecs, handler, userdata);
+ assert(nse);
+
+ nsock_log_info("UNIX domain socket (STREAM) connection requested to %s (IOD #%li) EID %li",
+ get_unixsock_path(ss), nsi->id, nse->id);
+
+ nsock_connect_internal(ms, nse, SOCK_STREAM, 0, ss, sslen, 0);
+ nsock_pool_add_event(ms, nse);
+
+ return nse->id;
+
+}
+
+/* Request a UNIX domain sockets connection to the same system (by path to socket).
+ * This function connects to the socket of type SOCK_DGRAM. ss should be a
+ * sockaddr_storage, sockaddr_un as appropriate (just like what you would pass to
+ * connect). sslen should be the sizeof the structure you are passing in. */
+nsock_event_id nsock_connect_unixsock_datagram(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler,
+ void *userdata, struct sockaddr *saddr, size_t sslen) {
+ struct niod *nsi = (struct niod *)nsiod;
+ struct npool *ms = (struct npool *)nsp;
+ struct nevent *nse;
+ struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;
+
+ assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);
+
+ nse = event_new(ms, NSE_TYPE_CONNECT, nsi, -1, handler, userdata);
+ assert(nse);
+
+ nsock_log_info("UNIX domain socket (DGRAM) connection requested to %s (IOD #%li) EID %li",
+ get_unixsock_path(ss), nsi->id, nse->id);
+
+ nsock_connect_internal(ms, nse, SOCK_DGRAM, 0, ss, sslen, 0);
+ nsock_pool_add_event(ms, nse);
+
+ return nse->id;
+}
+
+#endif /* HAVE_SYS_UN_H */
+
+#if HAVE_LINUX_VM_SOCKETS_H
+/* Request a vsock stream connection to another system. ss should be a
+ * sockaddr_storage or sockaddr_vm, as appropriate (just like what you would
+ * pass to connect). sslen should be the sizeof the structure you are passing
+ * in. */
+nsock_event_id nsock_connect_vsock_stream(nsock_pool nsp, nsock_iod ms_iod,
+ nsock_ev_handler handler,
+ int timeout_msecs, void *userdata,
+ struct sockaddr *saddr, size_t sslen,
+ unsigned int port) {
+ struct niod *nsi = (struct niod *)ms_iod;
+ struct npool *ms = (struct npool *)nsp;
+ struct nevent *nse;
+ struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;
+ struct sockaddr_vm *svm = (struct sockaddr_vm *)saddr;
+
+ assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);
+
+ nse = event_new(ms, NSE_TYPE_CONNECT, nsi, timeout_msecs, handler, userdata);
+ assert(nse);
+
+ nsock_log_info("vsock stream connection requested to %u:%u (IOD #%li) EID %li",
+ svm->svm_cid, port, nsi->id, nse->id);
+
+ /* Do the actual connect() */
+ nsock_connect_internal(ms, nse, SOCK_STREAM, 0, ss, sslen, port);
+ nsock_pool_add_event(ms, nse);
+
+ return nse->id;
+}
+
+/* Request a vsock datagram "connection" to another system. Since this is a
+ * datagram socket, no packets are actually sent. The destination CID and port
+ * are just associated with the nsiod (an actual OS connect() call is made).
+ * You can then use the normal nsock write calls on the socket. There is no
+ * timeout since this call always calls your callback at the next opportunity.
+ * The advantages to having a connected datagram socket (as opposed to just
+ * specifying an address with sendto() are that we can now use a consistent set
+ * of write/read calls for stream and datagram sockets, received packets from
+ * the non-partner are automatically dropped by the OS, and the OS can provide
+ * asynchronous errors (see Unix Network Programming pp224). ss should be a
+ * sockaddr_storage or sockaddr_vm, as appropriate (just like what you would
+ * pass to connect). sslen should be the sizeof the structure you are passing
+ * in. */
+nsock_event_id nsock_connect_vsock_datagram(nsock_pool nsp, nsock_iod nsiod,
+ nsock_ev_handler handler,
+ void *userdata,
+ struct sockaddr *saddr,
+ size_t sslen, unsigned int port) {
+ struct niod *nsi = (struct niod *)nsiod;
+ struct npool *ms = (struct npool *)nsp;
+ struct nevent *nse;
+ struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;
+ struct sockaddr_vm *svm = (struct sockaddr_vm *)saddr;
+
+ assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);
+
+ nse = event_new(ms, NSE_TYPE_CONNECT, nsi, -1, handler, userdata);
+ assert(nse);
+
+ nsock_log_info("vsock dgram connection requested to %u:%u (IOD #%li) EID %li",
+ svm->svm_cid, port, nsi->id, nse->id);
+
+ nsock_connect_internal(ms, nse, SOCK_DGRAM, 0, ss, sslen, port);
+ nsock_pool_add_event(ms, nse);
+
+ return nse->id;
+}
+#endif /* HAVE_LINUX_VM_SOCKETS_H */
+
+/* Request a TCP connection to another system (by IP address). The in_addr is
+ * normal network byte order, but the port number should be given in HOST BYTE
+ * ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as
+ * appropriate (just like what you would pass to connect). sslen should be the
+ * sizeof the structure you are passing in. */
+nsock_event_id nsock_connect_tcp(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
+ void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port) {
+ struct niod *nsi = (struct niod *)ms_iod;
+ struct npool *ms = (struct npool *)nsp;
+ struct nevent *nse;
+ struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;
+
+ assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);
+
+ nse = event_new(ms, NSE_TYPE_CONNECT, nsi, timeout_msecs, handler, userdata);
+ assert(nse);
+
+ nsock_log_info("TCP connection requested to %s:%hu (IOD #%li) EID %li",
+ inet_ntop_ez(ss, sslen), port, nsi->id, nse->id);
+
+ /* Do the actual connect() */
+ nsock_connect_internal(ms, nse, SOCK_STREAM, IPPROTO_TCP, ss, sslen, port);
+ nsock_pool_add_event(ms, nse);
+
+ return nse->id;
+}
+
+/* Request an SCTP association to another system (by IP address). The in_addr
+ * is normal network byte order, but the port number should be given in HOST
+ * BYTE ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as
+ * appropriate (just like what you would pass to connect). sslen should be the
+ * sizeof the structure you are passing in. */
+nsock_event_id nsock_connect_sctp(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
+ void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port) {
+
+ struct niod *nsi = (struct niod *)ms_iod;
+ struct npool *ms = (struct npool *)nsp;
+ struct nevent *nse;
+ struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;
+
+ assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);
+
+ nse = event_new(ms, NSE_TYPE_CONNECT, nsi, timeout_msecs, handler, userdata);
+ assert(nse);
+
+ nsock_log_info("SCTP association requested to %s:%hu (IOD #%li) EID %li",
+ inet_ntop_ez(ss, sslen), port, nsi->id, nse->id);
+
+ /* Do the actual connect() */
+ nsock_connect_internal(ms, nse, SOCK_STREAM, IPPROTO_SCTP, ss, sslen, port);
+ nsock_pool_add_event(ms, nse);
+
+ return nse->id;
+}
+
+/* Request an SSL over TCP/SCTP/UDP connection to another system (by IP address).
+ * The in_addr is normal network byte order, but the port number should be given
+ * in HOST BYTE ORDER. This function will call back only after it has made the
+ * connection AND done the initial SSL negotiation. From that point on, you use
+ * the normal read/write calls and decryption will happen transparently. ss
+ * should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate
+ * (just like what you would pass to connect). sslen should be the sizeof the
+ * structure you are passing in. */
+nsock_event_id nsock_connect_ssl(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs,
+ void *userdata, struct sockaddr *saddr, size_t sslen, int proto, unsigned short port, nsock_ssl_session ssl_session) {
+
+#ifndef HAVE_OPENSSL
+ fatal("nsock_connect_ssl called - but nsock was built w/o SSL support. QUITTING");
+ return (nsock_event_id)0; /* UNREACHED */
+#else
+ struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;
+ struct niod *nsi = (struct niod *)nsiod;
+ struct npool *ms = (struct npool *)nsp;
+ struct nevent *nse;
+
+ if (proto == IPPROTO_UDP)
+ {
+ if (!ms->dtlsctx)
+ nsock_pool_dtls_init(ms, 0);
+ }
+ else
+ {
+ if (!ms->sslctx)
+ nsock_pool_ssl_init(ms, 0);
+ }
+
+ assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);
+
+ nse = event_new(ms, NSE_TYPE_CONNECT_SSL, nsi, timeout_msecs, handler, userdata);
+ assert(nse);
+
+ /* Set our SSL_SESSION so we can benefit from session-id reuse. */
+ /* but not with DTLS; save space in ClientHello message */
+ if (proto != IPPROTO_UDP)
+ nsi_set_ssl_session(nsi, (SSL_SESSION *)ssl_session);
+
+ if (proto == IPPROTO_UDP)
+ nsock_log_info("DTLS connection requested to %s:%hu/udp (IOD #%li) EID %li",
+
+ inet_ntop_ez(ss, sslen), port, nsi->id, nse->id);
+ else
+ nsock_log_info("SSL connection requested to %s:%hu/%s (IOD #%li) EID %li",
+ inet_ntop_ez(ss, sslen), port, (proto == IPPROTO_TCP ? "tcp" : "sctp"),
+ nsi->id, nse->id);
+
+ /* Do the actual connect() */
+ nsock_connect_internal(ms, nse, (proto == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM), proto, ss, sslen, port);
+
+ nsock_pool_add_event(ms, nse);
+
+ return nse->id;
+#endif /* HAVE_OPENSSL */
+}
+
+/* Request ssl connection over already established connection. nsiod must be
+ * socket that is already connected to target using nsock_connect_tcp or
+ * nsock_connect_sctp. All parameters have the same meaning as in
+ * 'nsock_connect_ssl' */
+nsock_event_id nsock_reconnect_ssl(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs,
+ void *userdata, nsock_ssl_session ssl_session) {
+
+#ifndef HAVE_OPENSSL
+ fatal("nsock_reconnect_ssl called - but nsock was built w/o SSL support. QUITTING");
+ return (nsock_event_id) 0; /* UNREACHED */
+#else
+ struct niod *nsi = (struct niod *)nsiod;
+ struct npool *ms = (struct npool *)nsp;
+ struct nevent *nse;
+ /* nsock_reconnect_ssl not supported for DTLS (yet?) */
+ assert(nsi->lastproto != IPPROTO_UDP);
+
+ if (!ms->sslctx)
+ nsock_pool_ssl_init(ms, 0);
+
+ nse = event_new(ms, NSE_TYPE_CONNECT_SSL, nsi, timeout_msecs, handler, userdata);
+ assert(nse);
+
+ /* Set our SSL_SESSION so we can benefit from session-id reuse. */
+ nsi_set_ssl_session(nsi, (SSL_SESSION *)ssl_session);
+
+ nsock_log_info("SSL reconnection requested (IOD #%li) EID %li",
+ nsi->id, nse->id);
+
+ /* Do the actual connect() */
+ nse->event_done = 0;
+ nse->status = NSE_STATUS_SUCCESS;
+ nsock_pool_add_event(ms, nse);
+
+ return nse->id;
+#endif /* HAVE_OPENSSL */
+}
+
+/* Request a UDP "connection" to another system (by IP address). The in_addr is
+ * normal network byte order, but the port number should be given in HOST BYTE
+ * ORDER. Since this is UDP, no packets are actually sent. The destination IP
+ * and port are just associated with the nsiod (an actual OS connect() call is
+ * made). You can then use the normal nsock write calls on the socket. There
+ * is no timeout since this call always calls your callback at the next
+ * opportunity. The advantages to having a connected UDP socket (as opposed to
+ * just specifying an address with sendto() are that we can now use a consistent
+ * set of write/read calls for TCP/UDP, received packets from the non-partner
+ * are automatically dropped by the OS, and the OS can provide asynchronous
+ * errors (see Unix Network Programming pp224). ss should be a
+ * sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate (just like what
+ * you would pass to connect). sslen should be the sizeof the structure you are
+ * passing in. */
+nsock_event_id nsock_connect_udp(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, void *userdata,
+ struct sockaddr *saddr, size_t sslen, unsigned short port) {
+
+ struct niod *nsi = (struct niod *)nsiod;
+ struct npool *ms = (struct npool *)nsp;
+ struct nevent *nse;
+ struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;
+
+ assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);
+
+ nse = event_new(ms, NSE_TYPE_CONNECT, nsi, -1, handler, userdata);
+ assert(nse);
+
+ nsock_log_info("UDP connection requested to %s:%hu (IOD #%li) EID %li",
+ inet_ntop_ez(ss, sslen), port, nsi->id, nse->id);
+
+ nsock_connect_internal(ms, nse, SOCK_DGRAM, IPPROTO_UDP, ss, sslen, port);
+ nsock_pool_add_event(ms, nse);
+
+ return nse->id;
+}
+
+/* Returns that host/port/protocol information for the last communication (or
+ * comm. attempt) this nsi has been involved with. By "involved" with I mean
+ * interactions like establishing (or trying to) a connection or sending a UDP
+ * datagram through an unconnected nsock_iod. AF is the address family (AF_INET
+ * or AF_INET6), Protocl is IPPROTO_TCP or IPPROTO_UDP. Pass NULL for
+ * information you do not need. If ANY of the information you requested is not
+ * available, 0 will be returned and the unavailable sockets are zeroed. If
+ * protocol or af is requested but not available, it will be set to -1 (and 0
+ * returned). The pointers you pass in must be NULL or point to allocated
+ * address space. The sockaddr members should actually be sockaddr_storage,
+ * sockaddr_in6, or sockaddr_in with the socklen of them set appropriately (eg
+ * sizeof(sockaddr_storage) if that is what you are passing). */
+int nsock_iod_get_communication_info(nsock_iod iod, int *protocol, int *af,
+ struct sockaddr *local,
+ struct sockaddr *remote, size_t socklen) {
+ struct niod *nsi = (struct niod *)iod;
+ int ret = 1;
+ struct sockaddr_storage ss;
+ socklen_t slen = sizeof(ss);
+ int res;
+
+ assert(socklen > 0);
+
+ if (nsi->peerlen > 0) {
+ if (remote)
+ memcpy(remote, &(nsi->peer), MIN((unsigned)socklen, nsi->peerlen));
+ if (protocol) {
+ *protocol = nsi->lastproto;
+ if (*protocol == -1) res = 0;
+ }
+ if (af) {
+ *af = nsi->peer.ss_family;
+ }
+ if (local) {
+ if (nsi->sd >= 0) {
+ res = getsockname(nsi->sd, (struct sockaddr *)&ss, &slen);
+ if (res == -1) {
+ memset(local, 0, socklen);
+ ret = 0;
+ } else {
+ assert(slen > 0);
+ memcpy(local, &ss, MIN((unsigned)slen, socklen));
+ }
+ } else {
+ memset(local, 0, socklen);
+ ret = 0;
+ }
+ }
+ } else {
+ if (local || remote || protocol || af)
+ ret = 0;
+
+ if (remote)
+ memset(remote, 0, socklen);
+
+ if (local)
+ memset(local, 0, socklen);
+
+ if (protocol)
+ *protocol = -1;
+
+ if (af)
+ *af = -1;
+ }
+ return ret;
+}
+
diff --git a/nsock/src/nsock_core.c b/nsock/src/nsock_core.c
new file mode 100644
index 0000000..fa2aef6
--- /dev/null
+++ b/nsock/src/nsock_core.c
@@ -0,0 +1,1415 @@
+/***************************************************************************
+ * nsock_core.c -- This contains the core engine routines for the nsock *
+ * parallel socket event library. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include "nsock_internal.h"
+#include "gh_list.h"
+#include "filespace.h"
+#include "nsock_log.h"
+
+#include <assert.h>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "netutils.h"
+
+#if HAVE_PCAP
+#include "nsock_pcap.h"
+#endif
+
+/* Nsock time of day -- we update this at least once per nsock_loop round (and
+ * after most calls that are likely to block). Other nsock files should grab
+ * this */
+struct timeval nsock_tod;
+
+/* Internal function defined in nsock_event.c
+ * Update the nse->iod first events, assuming nse is about to be deleted */
+void update_first_events(struct nevent *nse);
+
+
+
+/* Each iod has a count of pending socket reads, socket writes, and pcap reads.
+ * When a descriptor's count is nonzero, its bit must be set in the appropriate
+ * master fd_set, and when the count is zero the bit must be cleared. What we
+ * are simulating is an fd_set with a counter for each socket instead of just an
+ * on/off switch. The fd_set's bits aren't enough by itself because a descriptor
+ * may for example have two reads pending at once, and the bit must not be
+ * cleared after the first is completed.
+ * The socket_count_* functions return the event to transmit to update_events()
+ */
+int socket_count_zero(struct niod *iod, struct npool *ms) {
+ iod->readsd_count = 0;
+ iod->writesd_count = 0;
+#if HAVE_PCAP
+ iod->readpcapsd_count = 0;
+#endif
+ return nsock_engine_iod_unregister(ms, iod);
+}
+
+static int socket_count_read_inc(struct niod *iod) {
+ assert(iod->readsd_count >= 0);
+ iod->readsd_count++;
+ return EV_READ;
+}
+
+static int socket_count_read_dec(struct niod *iod) {
+ assert(iod->readsd_count > 0);
+ iod->readsd_count--;
+ return (iod->readsd_count == 0) ? EV_READ : EV_NONE;
+}
+
+static int socket_count_write_inc(struct niod *iod) {
+ assert(iod->writesd_count >= 0);
+ iod->writesd_count++;
+ return EV_WRITE;
+}
+
+static int socket_count_write_dec(struct niod *iod) {
+ assert(iod->writesd_count > 0);
+ iod->writesd_count--;
+ return (iod->writesd_count == 0) ? EV_WRITE : EV_NONE;
+}
+
+#if HAVE_PCAP
+static int socket_count_readpcap_inc(struct niod *iod) {
+ assert(iod->readpcapsd_count >= 0);
+ iod->readpcapsd_count++;
+ return EV_READ;
+}
+
+static int socket_count_readpcap_dec(struct niod *iod) {
+ assert(iod->readpcapsd_count > 0);
+ iod->readpcapsd_count--;
+ return (iod->readpcapsd_count == 0) ? EV_READ : EV_NONE;
+}
+#endif
+
+#if HAVE_OPENSSL
+/* Call socket_count_read_dec or socket_count_write_dec on nse->iod depending on
+ * the current value of nse->sslinfo.ssl_desire. */
+static int socket_count_dec_ssl_desire(struct nevent *nse) {
+ assert(nse->iod->ssl != NULL);
+ assert(nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ ||
+ nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE);
+
+ if (nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ)
+ return socket_count_read_dec(nse->iod);
+ else
+ return socket_count_write_dec(nse->iod);
+}
+#endif
+
+static int should_clear_ev_read(const struct niod *iod, int ev_set) {
+ return (ev_set & EV_READ) &&
+#if HAVE_PCAP
+ !iod->readpcapsd_count &&
+#endif
+ !iod->readsd_count;
+}
+
+static int should_clear_ev_write(const struct niod *iod, int ev_set) {
+ return (ev_set & EV_WRITE) && !iod->writesd_count;
+}
+
+/* Update the events that the IO engine should watch for a given IOD.
+ *
+ * ev_inc is a set of events for which the event counters should be increased.
+ * These events will therefore be watched by the IO engine for this IOD.
+ *
+ * ev_dec is a set of events for which the event counters should be decreased.
+ * If this counter reaches zero, the event won't be watched anymore by the
+ * IO engine for this IOD.
+ */
+static void update_events(struct niod * iod, struct npool *ms, struct nevent *nse, int ev_inc, int ev_dec) {
+ int setmask, clrmask, ev_temp;
+
+ /* Filter out events that belong to both sets. */
+ ev_temp = ev_inc ^ ev_dec;
+ ev_inc = ev_inc & ev_temp;
+ ev_dec = ev_dec & ev_temp;
+
+ setmask = ev_inc;
+ clrmask = EV_NONE;
+
+ if (should_clear_ev_read(iod, ev_dec))
+ clrmask |= EV_READ;
+
+ if (should_clear_ev_write(iod, ev_dec))
+ clrmask |= EV_WRITE;
+
+ /* EV_EXCEPT is systematically set and cannot be removed */
+ if (ev_inc & EV_EXCEPT)
+ nsock_log_info("Invalid event set, no need to specify EV_EXCEPT");
+
+ if (ev_dec & EV_EXCEPT)
+ nsock_log_info("Invalid event set, refusing to clear EV_EXCEPT");
+
+ if (!IOD_PROPGET(iod, IOD_REGISTERED)) {
+ assert(clrmask == EV_NONE);
+ nsock_engine_iod_register(ms, iod, nse, setmask);
+ } else {
+ nsock_engine_iod_modify(ms, iod, nse, setmask, clrmask);
+ }
+}
+
+/* Add a new event for a given IOD. nevents are stored in separate event lists
+ * (in the nsock pool) and are grouped by IOD within each list.
+ *
+ * This function appends the event _before_ the first similar event we have for
+ * the given IOD, or append it to the end of the list if no similar event is
+ * already present.
+ *
+ * Note that adding the event before the similar ones is important for
+ * reentrancy, as it will prevent the new event to be processed in the event
+ * loop just after its addition.
+ */
+static int iod_add_event(struct niod *iod, struct nevent *nse) {
+ struct npool *nsp = iod->nsp;
+
+ switch (nse->type) {
+ case NSE_TYPE_CONNECT:
+ case NSE_TYPE_CONNECT_SSL:
+ if (iod->first_connect)
+ gh_list_insert_before(&nsp->connect_events,
+ iod->first_connect, &nse->nodeq_io);
+ else
+ gh_list_append(&nsp->connect_events, &nse->nodeq_io);
+ iod->first_connect = &nse->nodeq_io;
+ break;
+
+ case NSE_TYPE_READ:
+ if (iod->first_read)
+ gh_list_insert_before(&nsp->read_events, iod->first_read, &nse->nodeq_io);
+ else
+ gh_list_append(&nsp->read_events, &nse->nodeq_io);
+ iod->first_read = &nse->nodeq_io;
+ break;
+
+ case NSE_TYPE_WRITE:
+ if (iod->first_write)
+ gh_list_insert_before(&nsp->write_events, iod->first_write, &nse->nodeq_io);
+ else
+ gh_list_append(&nsp->write_events, &nse->nodeq_io);
+ iod->first_write = &nse->nodeq_io;
+ break;
+
+#if HAVE_PCAP
+ case NSE_TYPE_PCAP_READ: {
+ char add_read = 0, add_pcap_read = 0;
+
+#if PCAP_BSD_SELECT_HACK
+ /* BSD hack mode: add event to both read and pcap_read lists */
+ add_read = add_pcap_read = 1;
+#else
+ if (((mspcap *)iod->pcap)->pcap_desc >= 0) {
+ add_read = 1;
+ } else {
+ add_pcap_read = 1;
+ }
+#endif
+ if (add_read) {
+ if (iod->first_read)
+ gh_list_insert_before(&nsp->read_events, iod->first_read, &nse->nodeq_io);
+ else
+ gh_list_append(&nsp->read_events, &nse->nodeq_io);
+ iod->first_read = &nse->nodeq_io;
+ }
+ if (add_pcap_read) {
+ if (iod->first_pcap_read)
+ gh_list_insert_before(&nsp->pcap_read_events, iod->first_pcap_read,
+ &nse->nodeq_pcap);
+ else
+ gh_list_append(&nsp->pcap_read_events, &nse->nodeq_pcap);
+ iod->first_pcap_read = &nse->nodeq_pcap;
+ }
+ break;
+ }
+#endif
+
+ default:
+ fatal("Unknown event type (%d) for IOD #%lu\n", nse->type, iod->id);
+ }
+
+ return 0;
+}
+
+/* A handler function is defined for each of the main event types (read, write,
+ * connect, timer, etc) -- the handler is called when new information is
+ * available for the event. The handler makes any necessary updates to the
+ * event based on any new information available. If the event becomes ready for
+ * delivery, the handler sets nse->event_done and fills out the relevant event
+ * fields (status, errnum) as applicable. The handlers also take care of event
+ * type specific teardown (such as clearing socket descriptors from select/poll
+ * lists). If event_done is not set, the handler will be called again in the
+ * case of more information or an event timeout */
+
+/* The event type handlers -- the first three arguments of each are the same:
+ * struct npool *ms struct nevent *nse -- the event we have new info on enum nse_status --
+ * The reason for the call, usually NSE_STATUS_SUCCESS (which generally means a
+ * successful I/O call or NSE_STATUS_TIMEOUT or NSE_STATUS_CANCELLED
+ *
+ * Some of the event type handlers have other parameters, specific to their
+ * needs. All the handlers can assume that the calling function has checked
+ * that select or poll said their descriptors were readable/writeable (as
+ * appropriate).
+ *
+ * The idea is that each handler will take care of the stuff that is specific
+ * to it and the calling function will handle the stuff that can be generalized
+ * to dispatching/deleting/etc. all events. But the calling function may use
+ * type-specific info to determine whether the handler should be called at all
+ * (to save CPU time). */
+
+/* handle_connect_results assumes that select or poll have already shown the
+ * descriptor to be active */
+void handle_connect_result(struct npool *ms, struct nevent *nse, enum nse_status status) {
+ int optval;
+ socklen_t optlen = sizeof(int);
+ struct niod *iod = nse->iod;
+ assert(iod != NULL);
+#if HAVE_OPENSSL
+ int sslerr;
+ int rc = 0;
+ int sslconnect_inprogress = nse->type == NSE_TYPE_CONNECT_SSL && nse->iod &&
+ (nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ ||
+ nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE);
+ SSL_CTX *sslctx = NULL;
+#else
+ int sslconnect_inprogress = 0;
+#endif
+
+ if (status == NSE_STATUS_TIMEOUT || status == NSE_STATUS_CANCELLED) {
+ nse->status = status;
+ nse->event_done = 1;
+ } else if (sslconnect_inprogress) {
+ /* Do nothing */
+ } else if (status == NSE_STATUS_SUCCESS) {
+ /* First we want to determine whether the socket really is connected */
+ if (getsockopt(iod->sd, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen) != 0)
+ optval = socket_errno(); /* Stupid Solaris */
+
+ if (optval == 0) {
+ nse->status = NSE_STATUS_SUCCESS;
+ }
+ else {
+ nse->status = NSE_STATUS_ERROR;
+ nse->errnum = optval;
+ }
+
+ /* Now special code for the SSL case where the TCP connection was successful. */
+ if (nse->type == NSE_TYPE_CONNECT_SSL &&
+ nse->status == NSE_STATUS_SUCCESS) {
+#if HAVE_OPENSSL
+ sslctx = iod->lastproto == IPPROTO_UDP ? ms->dtlsctx : ms->sslctx;
+ assert(sslctx != NULL);
+ /* Reuse iod->ssl if present. If set, this is the second try at connection
+ without the SSL_OP_NO_SSLv2 option set. */
+ if (iod->ssl == NULL) {
+ iod->ssl = SSL_new(sslctx);
+ if (!iod->ssl)
+ fatal("SSL_new failed: %s", ERR_error_string(ERR_get_error(), NULL));
+ }
+
+#if HAVE_SSL_SET_TLSEXT_HOST_NAME
+ /* Avoid sending SNI extension with DTLS because many servers don't allow
+ * fragmented ClientHello messages. */
+ if (iod->hostname != NULL && iod->lastproto != IPPROTO_UDP) {
+ if (SSL_set_tlsext_host_name(iod->ssl, iod->hostname) != 1)
+ fatal("SSL_set_tlsext_host_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
+ }
+#endif
+
+ /* Associate our new SSL with the connected socket. It will inherit the
+ * non-blocking nature of the sd */
+ if (SSL_set_fd(iod->ssl, iod->sd) != 1)
+ fatal("SSL_set_fd failed: %s", ERR_error_string(ERR_get_error(), NULL));
+
+ /* Event not done -- need to do SSL connect below */
+ nse->sslinfo.ssl_desire = SSL_ERROR_WANT_CONNECT;
+#endif
+ } else {
+ /* This is not an SSL connect (in which case we are always done), or the
+ * TCP connect() underlying the SSL failed (in which case we are also done */
+ nse->event_done = 1;
+ }
+ } else {
+ fatal("Unknown status (%d)", status);
+ }
+
+ /* At this point the TCP connection is done, whether successful or not.
+ * Therefore decrease the read/write listen counts that were incremented in
+ * nsock_pool_add_event. In the SSL case, we may increase one of the counts depending
+ * on whether SSL_connect returns an error of SSL_ERROR_WANT_READ or
+ * SSL_ERROR_WANT_WRITE. In that case we will re-enter this function, but we
+ * don't want to execute this block again. */
+ if (iod->sd != -1 && !sslconnect_inprogress) {
+ int ev = EV_NONE;
+
+ ev |= socket_count_read_dec(iod);
+ ev |= socket_count_write_dec(iod);
+ update_events(iod, ms, nse, EV_NONE, ev);
+ }
+
+#if HAVE_OPENSSL
+ if (nse->type == NSE_TYPE_CONNECT_SSL && !nse->event_done) {
+ /* Lets now start/continue/finish the connect! */
+ if (iod->ssl_session) {
+ rc = SSL_set_session(iod->ssl, iod->ssl_session);
+ if (rc == 0)
+ nsock_log_error("Uh-oh: SSL_set_session() failed - please tell dev@nmap.org");
+ iod->ssl_session = NULL; /* No need for this any more */
+ }
+
+ /* If this is a reinvocation of handle_connect_result, clear out the listen
+ * bits that caused it, based on the previous SSL desire. */
+ if (sslconnect_inprogress) {
+ int ev;
+
+ ev = socket_count_dec_ssl_desire(nse);
+ update_events(iod, ms, nse, EV_NONE, ev);
+ }
+
+ rc = SSL_connect(iod->ssl);
+ if (rc == 1) {
+ /* Woop! Connect is done! */
+ nse->event_done = 1;
+ /* Check that certificate verification was okay, if requested. */
+ if (nsi_ssl_post_connect_verify(iod)) {
+ nse->status = NSE_STATUS_SUCCESS;
+ } else {
+ nsock_log_error("certificate verification error for EID %li: %s",
+ nse->id, ERR_error_string(ERR_get_error(), NULL));
+ nse->status = NSE_STATUS_ERROR;
+ }
+ } else {
+#if SSL_OP_NO_SSLv2 != 0
+ long options = SSL_get_options(iod->ssl);
+#endif
+
+ sslerr = SSL_get_error(iod->ssl, rc);
+ if (sslerr == SSL_ERROR_WANT_READ) {
+ nse->sslinfo.ssl_desire = sslerr;
+ socket_count_read_inc(iod);
+ update_events(iod, ms, nse, EV_READ, EV_NONE);
+ } else if (sslerr == SSL_ERROR_WANT_WRITE) {
+ nse->sslinfo.ssl_desire = sslerr;
+ socket_count_write_inc(iod);
+ update_events(iod, ms, nse, EV_WRITE, EV_NONE);
+#if SSL_OP_NO_SSLv2 != 0
+ } else if (iod->lastproto != IPPROTO_UDP && !(options & SSL_OP_NO_SSLv2)) {
+ /* SSLv2 does not apply to DTLS, so ensure lastproto was not UDP. */
+ int saved_ev;
+
+ /* SSLv3-only and TLSv1-only servers can't be connected to when the
+ * SSL_OP_NO_SSLv2 option is not set, which is the case when the pool
+ * was initialized with nsock_pool_ssl_init_max_speed. Try reconnecting
+ * with SSL_OP_NO_SSLv2. Never downgrade a NO_SSLv2 connection to one
+ * that might use SSLv2. */
+ nsock_log_info("EID %li reconnecting with SSL_OP_NO_SSLv2", nse->id);
+
+ saved_ev = iod->watched_events;
+ nsock_engine_iod_unregister(ms, iod);
+ close(iod->sd);
+ nsock_connect_internal(ms, nse, SOCK_STREAM, iod->lastproto, &iod->peer,
+ iod->peerlen, nsock_iod_get_peerport(iod));
+ nsock_engine_iod_register(ms, iod, nse, saved_ev);
+
+ /* Use SSL_free here because SSL_clear keeps session info, which
+ * doesn't work when changing SSL versions (as we're clearly trying to
+ * do by adding SSL_OP_NO_SSLv2). */
+ SSL_free(iod->ssl);
+ iod->ssl = SSL_new(ms->sslctx);
+ if (!iod->ssl)
+ fatal("SSL_new failed: %s", ERR_error_string(ERR_get_error(), NULL));
+
+ SSL_set_options(iod->ssl, options | SSL_OP_NO_SSLv2);
+ socket_count_read_inc(nse->iod);
+ socket_count_write_inc(nse->iod);
+ update_events(iod, ms, nse, EV_READ|EV_WRITE, EV_NONE);
+ nse->sslinfo.ssl_desire = SSL_ERROR_WANT_CONNECT;
+#endif
+ } else {
+ nsock_log_info("EID %li %s",
+ nse->id, ERR_error_string(ERR_get_error(), NULL));
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_ERROR;
+ nse->errnum = EIO;
+ }
+ }
+ }
+#endif
+}
+
+static int errcode_is_failure(int err) {
+#ifndef WIN32
+ return err != EINTR && err != EAGAIN && err != EBUSY;
+#else
+ return err != EINTR && err != EAGAIN;
+#endif
+}
+
+void handle_write_result(struct npool *ms, struct nevent *nse, enum nse_status status) {
+ int bytesleft;
+ char *str;
+ int res;
+ int err;
+ struct niod *iod = nse->iod;
+
+ if (status == NSE_STATUS_TIMEOUT || status == NSE_STATUS_CANCELLED) {
+ nse->event_done = 1;
+ nse->status = status;
+ } else if (status == NSE_STATUS_SUCCESS) {
+ str = fs_str(&nse->iobuf) + nse->writeinfo.written_so_far;
+ bytesleft = fs_length(&nse->iobuf) - nse->writeinfo.written_so_far;
+ if (nse->writeinfo.written_so_far > 0)
+ assert(bytesleft > 0);
+#if HAVE_OPENSSL
+ if (iod->ssl)
+ res = SSL_write(iod->ssl, str, bytesleft);
+ else
+#endif
+ res = ms->engine->io_operations->iod_write(ms, nse->iod->sd, str, bytesleft, 0, (struct sockaddr *)&nse->writeinfo.dest, (int)nse->writeinfo.destlen);
+ if (res == bytesleft) {
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_SUCCESS;
+ } else if (res >= 0) {
+ nse->writeinfo.written_so_far += res;
+ } else {
+ assert(res == -1);
+ if (iod->ssl) {
+#if HAVE_OPENSSL
+ err = SSL_get_error(iod->ssl, res);
+ if (err == SSL_ERROR_WANT_READ) {
+ int evclr;
+
+ evclr = socket_count_dec_ssl_desire(nse);
+ socket_count_read_inc(iod);
+ update_events(iod, ms, nse, EV_READ, evclr);
+ nse->sslinfo.ssl_desire = err;
+ } else if (err == SSL_ERROR_WANT_WRITE) {
+ int evclr;
+
+ evclr = socket_count_dec_ssl_desire(nse);
+ socket_count_write_inc(iod);
+ update_events(iod, ms, nse, EV_WRITE, evclr);
+ nse->sslinfo.ssl_desire = err;
+ } else {
+ /* Unexpected error */
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_ERROR;
+ nse->errnum = EIO;
+ }
+#endif
+ } else {
+ err = socket_errno();
+ if (errcode_is_failure(err)) {
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_ERROR;
+ nse->errnum = err;
+ }
+ }
+ }
+
+ if (res >= 0)
+ nse->iod->write_count += res;
+ }
+
+ if (nse->event_done && nse->iod->sd != -1) {
+ int ev = EV_NONE;
+
+#if HAVE_OPENSSL
+ if (nse->iod->ssl != NULL)
+ ev |= socket_count_dec_ssl_desire(nse);
+ else
+#endif
+ ev |= socket_count_write_dec(nse->iod);
+ update_events(nse->iod, ms, nse, EV_NONE, ev);
+ }
+}
+
+void handle_timer_result(struct npool *ms, struct nevent *nse, enum nse_status status) {
+ /* Ooh this is a hard job :) */
+ nse->event_done = 1;
+ nse->status = status;
+}
+
+/* Returns -1 if an error, otherwise the number of newly written bytes */
+static int do_actual_read(struct npool *ms, struct nevent *nse) {
+ char buf[READ_BUFFER_SZ];
+ int buflen = 0;
+ struct niod *iod = nse->iod;
+ int err = 0;
+ int max_chunk = NSOCK_READ_CHUNK_SIZE;
+ int startlen = fs_length(&nse->iobuf);
+ int enotsock = 0; /* Did we get ENOTSOCK once? */
+
+ if (nse->readinfo.read_type == NSOCK_READBYTES)
+ max_chunk = nse->readinfo.num;
+
+ if (!iod->ssl) {
+ do {
+ struct sockaddr_storage peer;
+ socklen_t peerlen;
+ peerlen = sizeof(peer);
+
+ if (enotsock) {
+ peer.ss_family = AF_UNSPEC;
+ peerlen = 0;
+ buflen = read(iod->sd, buf, sizeof(buf));
+ }
+ else {
+ buflen = ms->engine->io_operations->iod_read(ms, iod->sd, buf, sizeof(buf), 0, (struct sockaddr *)&peer, &peerlen);
+
+ /* Using recv() was failing, at least on UNIX, for non-network sockets
+ * (i.e. stdin) in this case, a read() is done - as on ENOTSOCK we may
+ * have a non-network socket */
+ if (buflen == -1) {
+ if (socket_errno() == ENOTSOCK) {
+ enotsock = 1;
+ peer.ss_family = AF_UNSPEC;
+ peerlen = 0;
+ buflen = read(iod->sd, buf, sizeof(buf));
+ }
+ }
+ }
+ if (buflen == -1) {
+ err = socket_errno();
+ }
+ else {
+ /* Windows will ignore src_addr and addrlen arguments to recvfrom on TCP
+ * sockets, so peerlen is still sizeof(peer) and peer is junk. Instead,
+ * only set this if it's not already set.
+ */
+ if (peerlen > 0 && iod->peerlen == 0) {
+ assert(peerlen <= sizeof(iod->peer));
+ memcpy(&iod->peer, &peer, peerlen);
+ iod->peerlen = peerlen;
+ }
+ if (buflen > 0) {
+ if (fs_cat(&nse->iobuf, buf, buflen) == -1) {
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_ERROR;
+ nse->errnum = ENOMEM;
+ return -1;
+ }
+
+ /* Sometimes a service just spews and spews data. So we return after a
+ * somewhat large amount to avoid monopolizing resources and avoid DOS
+ * attacks. */
+ if (fs_length(&nse->iobuf) > max_chunk)
+ return fs_length(&nse->iobuf) - startlen;
+
+ /* No good reason to read again if we we were successful in the read but
+ * didn't fill up the buffer. Especially for UDP, where we want to
+ * return only one datagram at a time. The consistency of the above
+ * assignment of iod->peer depends on not consolidating more than one
+ * UDP read buffer. */
+ if (buflen < sizeof(buf))
+ return fs_length(&nse->iobuf) - startlen;
+ }
+ }
+ } while (buflen > 0 || (buflen == -1 && err == EINTR));
+
+ if (buflen == -1) {
+ if (err != EINTR && err != EAGAIN) {
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_ERROR;
+ nse->errnum = err;
+ return -1;
+ }
+ }
+ } else {
+#if HAVE_OPENSSL
+ /* OpenSSL read */
+ while ((buflen = SSL_read(iod->ssl, buf, sizeof(buf))) > 0) {
+
+ if (fs_cat(&nse->iobuf, buf, buflen) == -1) {
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_ERROR;
+ nse->errnum = ENOMEM;
+ return -1;
+ }
+
+ /* Sometimes a service just spews and spews data. So we return
+ * after a somewhat large amount to avoid monopolizing resources
+ * and avoid DOS attacks. */
+ if (fs_length(&nse->iobuf) > max_chunk)
+ return fs_length(&nse->iobuf) - startlen;
+ }
+
+ if (buflen == -1) {
+ err = SSL_get_error(iod->ssl, buflen);
+ if (err == SSL_ERROR_WANT_READ) {
+ int evclr;
+
+ evclr = socket_count_dec_ssl_desire(nse);
+ socket_count_read_inc(iod);
+ update_events(iod, ms, nse, EV_READ, evclr);
+ nse->sslinfo.ssl_desire = err;
+ } else if (err == SSL_ERROR_WANT_WRITE) {
+ int evclr;
+
+ evclr = socket_count_dec_ssl_desire(nse);
+ socket_count_write_inc(iod);
+ update_events(iod, ms, nse, EV_WRITE, evclr);
+ nse->sslinfo.ssl_desire = err;
+ } else {
+ /* Unexpected error */
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_ERROR;
+ nse->errnum = EIO;
+ nsock_log_info("SSL_read() failed for reason %s on NSI %li",
+ ERR_error_string(err, NULL), iod->id);
+ return -1;
+ }
+ }
+#endif /* HAVE_OPENSSL */
+ }
+
+ if (buflen == 0) {
+ nse->event_done = 1;
+ nse->eof = 1;
+ if (fs_length(&nse->iobuf) > 0) {
+ nse->status = NSE_STATUS_SUCCESS;
+ return fs_length(&nse->iobuf) - startlen;
+ } else {
+ nse->status = NSE_STATUS_EOF;
+ return 0;
+ }
+ }
+
+ return fs_length(&nse->iobuf) - startlen;
+}
+
+
+void handle_read_result(struct npool *ms, struct nevent *nse, enum nse_status status) {
+ unsigned int count;
+ char *str;
+ int rc, len;
+ struct niod *iod = nse->iod;
+
+ if (status == NSE_STATUS_TIMEOUT) {
+ nse->event_done = 1;
+ if (fs_length(&nse->iobuf) > 0)
+ nse->status = NSE_STATUS_SUCCESS;
+ else
+ nse->status = NSE_STATUS_TIMEOUT;
+ } else if (status == NSE_STATUS_CANCELLED) {
+ nse->status = status;
+ nse->event_done = 1;
+ } else if (status == NSE_STATUS_SUCCESS) {
+ rc = do_actual_read(ms, nse);
+ /* printf("DBG: Just read %d new bytes%s.\n", rc, iod->ssl? "( SSL!)" : ""); */
+ if (rc > 0) {
+ nse->iod->read_count += rc;
+ /* We decide whether we have read enough to return */
+ switch (nse->readinfo.read_type) {
+ case NSOCK_READ:
+ nse->status = NSE_STATUS_SUCCESS;
+ nse->event_done = 1;
+ break;
+ case NSOCK_READBYTES:
+ if (fs_length(&nse->iobuf) >= nse->readinfo.num) {
+ nse->status = NSE_STATUS_SUCCESS;
+ nse->event_done = 1;
+ }
+ /* else we are not done */
+ break;
+ case NSOCK_READLINES:
+ /* Lets count the number of lines we have ... */
+ count = 0;
+ len = fs_length(&nse->iobuf) -1;
+ str = fs_str(&nse->iobuf);
+ for (count=0; len >= 0; len--) {
+ if (str[len] == '\n') {
+ count++;
+ if ((int)count >= nse->readinfo.num)
+ break;
+ }
+ }
+ if ((int) count >= nse->readinfo.num) {
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_SUCCESS;
+ }
+ /* Else we are not done */
+ break;
+ default:
+ fatal("Unknown operation type (%d)", (int)nse->readinfo.read_type);
+ }
+ }
+ } else {
+ fatal("Unknown status (%d)", status);
+ }
+
+ /* If there are no more reads for this IOD, we are done reading on the socket
+ * so we can take it off the descriptor list ... */
+ if (nse->event_done && iod->sd >= 0) {
+ int ev = EV_NONE;
+
+#if HAVE_OPENSSL
+ if (nse->iod->ssl != NULL)
+ ev |= socket_count_dec_ssl_desire(nse);
+ else
+#endif
+ ev |= socket_count_read_dec(nse->iod);
+ update_events(nse->iod, ms, nse, EV_NONE, ev);
+ }
+}
+
+#if HAVE_PCAP
+void handle_pcap_read_result(struct npool *ms, struct nevent *nse, enum nse_status status) {
+ struct niod *iod = nse->iod;
+ mspcap *mp = (mspcap *)iod->pcap;
+
+ switch (status) {
+ case NSE_STATUS_TIMEOUT:
+ nse->status = NSE_STATUS_TIMEOUT;
+ nse->event_done = 1;
+ break;
+
+ case NSE_STATUS_CANCELLED:
+ nse->status = NSE_STATUS_CANCELLED;
+ nse->event_done = 1;
+ break;
+
+ case NSE_STATUS_SUCCESS:
+ /* check if we already have something read */
+ if (fs_length(&(nse->iobuf)) == 0) {
+ nse->status = NSE_STATUS_TIMEOUT;
+ nse->event_done = 0;
+ } else {
+ nse->status = NSE_STATUS_SUCCESS; /* we have full buffer */
+ nse->event_done = 1;
+ }
+ break;
+
+ default:
+ fatal("Unknown status (%d) for nsock event #%lu", status, nse->id);
+ }
+
+ /* If there are no more read events, we are done reading on the socket so we
+ * can take it off the descriptor list... */
+ if (nse->event_done && mp->pcap_desc >= 0) {
+ int ev;
+
+ ev = socket_count_readpcap_dec(iod);
+ update_events(iod, ms, nse, EV_NONE, ev);
+ }
+}
+
+/* Returns whether something was read */
+int pcap_read_on_nonselect(struct npool *nsp) {
+ gh_lnode_t *current, *next;
+ struct nevent *nse;
+ int ret = 0;
+
+ for (current = gh_list_first_elem(&nsp->pcap_read_events);
+ current != NULL;
+ current = next) {
+ nse = lnode_nevent2(current);
+ if (do_actual_pcap_read(nse) == 1) {
+ /* something received */
+ ret++;
+ break;
+ }
+ next = gh_lnode_next(current);
+ }
+ return ret;
+}
+#endif /* HAVE_PCAP */
+
+/* Here is the all important looping function that tells the event engine to
+ * start up and begin processing events. It will continue until all events have
+ * been delivered (including new ones started from event handlers), or the
+ * msec_timeout is reached, or a major error has occurred. Use -1 if you don't
+ * want to set a maximum time for it to run. A timeout of 0 will return after 1
+ * non-blocking loop. The nsock loop can be restarted again after it returns.
+ * For example you could do a series of 15 second runs, allowing you to do other
+ * stuff between them */
+enum nsock_loopstatus nsock_loop(nsock_pool nsp, int msec_timeout) {
+ struct npool *ms = (struct npool *)nsp;
+ struct timeval loop_timeout;
+ int msecs_left;
+ unsigned long loopnum = 0;
+ enum nsock_loopstatus quitstatus = NSOCK_LOOP_ERROR;
+
+ gettimeofday(&nsock_tod, NULL);
+
+ if (msec_timeout < -1) {
+ ms->errnum = EINVAL;
+ return NSOCK_LOOP_ERROR;
+ }
+ TIMEVAL_MSEC_ADD(loop_timeout, nsock_tod, msec_timeout);
+ msecs_left = msec_timeout;
+
+ if (msec_timeout >= 0)
+ nsock_log_debug("nsock_loop() started (timeout=%dms). %d events pending",
+ msec_timeout, ms->events_pending);
+ else
+ nsock_log_debug("nsock_loop() started (no timeout). %d events pending",
+ ms->events_pending);
+
+ while (1) {
+ if (ms->quit) {
+ /* We've been asked to quit the loop through nsock_loop_quit. */
+ ms->quit = 0;
+ quitstatus = NSOCK_LOOP_QUIT;
+ break;
+ }
+
+ if (ms->events_pending == 0) {
+ /* if no events at all are pending, then none can be created until
+ * we quit nsock_loop() -- so we do that now. */
+ quitstatus = NSOCK_LOOP_NOEVENTS;
+ break;
+ }
+
+ if (msec_timeout >= 0) {
+ msecs_left = MAX(0, TIMEVAL_MSEC_SUBTRACT(loop_timeout, nsock_tod));
+ if (msecs_left == 0 && loopnum > 0) {
+ quitstatus = NSOCK_LOOP_TIMEOUT;
+ break;
+ }
+ }
+
+ if (nsock_engine_loop(ms, msecs_left) == -1) {
+ quitstatus = NSOCK_LOOP_ERROR;
+ break;
+ }
+
+ gettimeofday(&nsock_tod, NULL); /* we do this at end because there is one
+ * at beginning of function */
+ loopnum++;
+ }
+
+ return quitstatus;
+}
+
+void process_event(struct npool *nsp, gh_list_t *evlist, struct nevent *nse, int ev) {
+ int match_r = ev & EV_READ;
+ int match_w = ev & EV_WRITE;
+ int match_x = ev & EV_EXCEPT;
+#if HAVE_OPENSSL
+ int desire_r = 0, desire_w = 0;
+#endif
+
+ nsock_log_debug_all("Processing event %lu (timeout in %ldms, done=%d)",
+ nse->id,
+ (long)TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod),
+ nse->event_done);
+
+ if (!nse->event_done) {
+ switch (nse->type) {
+ case NSE_TYPE_CONNECT:
+ case NSE_TYPE_CONNECT_SSL:
+ if (ev != EV_NONE)
+ handle_connect_result(nsp, nse, NSE_STATUS_SUCCESS);
+ if (event_timedout(nse))
+ handle_connect_result(nsp, nse, NSE_STATUS_TIMEOUT);
+ break;
+
+ case NSE_TYPE_READ:
+#if HAVE_OPENSSL
+ desire_r = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ;
+ desire_w = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE;
+ if (nse->iod->ssl && ((desire_r && match_r) || (desire_w && match_w)))
+ handle_read_result(nsp, nse, NSE_STATUS_SUCCESS);
+ else
+#endif
+ if ((!nse->iod->ssl && match_r) || match_x)
+ handle_read_result(nsp, nse, NSE_STATUS_SUCCESS);
+
+ if (event_timedout(nse))
+ handle_read_result(nsp, nse, NSE_STATUS_TIMEOUT);
+
+ break;
+
+ case NSE_TYPE_WRITE:
+#if HAVE_OPENSSL
+ desire_r = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ;
+ desire_w = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE;
+ if (nse->iod->ssl && ((desire_r && match_r) || (desire_w && match_w)))
+ handle_write_result(nsp, nse, NSE_STATUS_SUCCESS);
+ else
+#endif
+ if ((!nse->iod->ssl && match_w) || match_x)
+ handle_write_result(nsp, nse, NSE_STATUS_SUCCESS);
+
+ if (event_timedout(nse))
+ handle_write_result(nsp, nse, NSE_STATUS_TIMEOUT);
+ break;
+
+ case NSE_TYPE_TIMER:
+ if (event_timedout(nse))
+ handle_timer_result(nsp, nse, NSE_STATUS_SUCCESS);
+ break;
+
+#if HAVE_PCAP
+ case NSE_TYPE_PCAP_READ:{
+ nsock_log_debug_all("PCAP iterating %lu", nse->id);
+
+ if (ev & EV_READ) {
+ /* buffer empty? check it! */
+ if (fs_length(&(nse->iobuf)) == 0)
+ do_actual_pcap_read(nse);
+ }
+
+ /* if already received something */
+ if (fs_length(&(nse->iobuf)) > 0)
+ handle_pcap_read_result(nsp, nse, NSE_STATUS_SUCCESS);
+
+ if (event_timedout(nse))
+ handle_pcap_read_result(nsp, nse, NSE_STATUS_TIMEOUT);
+
+ #if PCAP_BSD_SELECT_HACK
+ /* If event occurred, and we're in BSD_HACK mode, then this event was added
+ * to two queues. read_event and pcap_read_event
+ * Of course we should destroy it only once.
+ * I assume we're now in read_event, so just unlink this event from
+ * pcap_read_event */
+ if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0
+ && nse->event_done
+ && evlist == &nsp->read_events) {
+ /* event is done, list is read_events and we're in BSD_HACK mode.
+ * So unlink event from pcap_read_events */
+ update_first_events(nse);
+ gh_list_remove(&nsp->pcap_read_events, &nse->nodeq_pcap);
+
+ nsock_log_debug_all("PCAP NSE #%lu: Removing event from PCAP_READ_EVENTS",
+ nse->id);
+ }
+ if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0
+ && nse->event_done
+ && evlist == &nsp->pcap_read_events) {
+ update_first_events(nse);
+ gh_list_remove(&nsp->read_events, &nse->nodeq_io);
+ nsock_log_debug_all("PCAP NSE #%lu: Removing event from READ_EVENTS",
+ nse->id);
+ }
+ #endif
+ break;
+ }
+#endif
+ default:
+ fatal("Event has unknown type (%d)", nse->type);
+ }
+ }
+
+ if (nse->event_done) {
+ /* Security sanity check: don't return a functional SSL iod without
+ * setting an SSL data structure. */
+ if (nse->type == NSE_TYPE_CONNECT_SSL && nse->status == NSE_STATUS_SUCCESS)
+ assert(nse->iod->ssl != NULL);
+
+ nsock_log_debug_all("NSE #%lu: Sending event", nse->id);
+
+ /* WooHoo! The event is ready to be sent */
+ event_dispatch_and_delete(nsp, nse, 1);
+ }
+}
+
+void process_iod_events(struct npool *nsp, struct niod *nsi, int ev) {
+ int i = 0;
+ /* store addresses of the pointers to the first elements of each kind instead
+ * of storing the values, as a connect can add a read for instance */
+ gh_lnode_t **start_elems[] = {
+ &nsi->first_connect,
+ &nsi->first_read,
+ &nsi->first_write,
+#if HAVE_PCAP
+ &nsi->first_pcap_read,
+#endif
+ NULL
+ };
+ gh_list_t *evlists[] = {
+ &nsp->connect_events,
+ &nsp->read_events,
+ &nsp->write_events,
+#if HAVE_PCAP
+ &nsp->pcap_read_events,
+#endif
+ NULL
+ };
+
+ assert(nsp == nsi->nsp);
+ nsock_log_debug_all("Processing events on IOD %lu (ev=%d)", nsi->id, ev);
+
+ /* We keep the events separate because we want to handle them in the
+ * order: connect => read => write => timer for several reasons:
+ *
+ * 1) Makes sure we have gone through all the net i/o events before
+ * a timer expires (would be a shame to timeout after the data was
+ * available but before we delivered the events
+ *
+ * 2) The connect() results often lead to a read or write that can be
+ * processed in the same cycle. In the same way, read() often
+ * leads to write().
+ */
+ for (i = 0; evlists[i] != NULL; i++) {
+ gh_lnode_t *current, *next, *last;
+
+ /* for each list, get the last event and don't look past it as an event
+ * could add another event in the same list and so on... */
+ last = gh_list_last_elem(evlists[i]);
+
+ for (current = *start_elems[i];
+ current != NULL && gh_lnode_prev(current) != last;
+ current = next) {
+ struct nevent *nse;
+
+#if HAVE_PCAP
+ if (evlists[i] == &nsi->nsp->pcap_read_events)
+ nse = lnode_nevent2(current);
+ else
+#endif
+ nse = lnode_nevent(current);
+
+ /* events are grouped by IOD. Break if we're done with the events for the
+ * current IOD */
+ if (nse->iod != nsi)
+ break;
+
+ process_event(nsp, evlists[i], nse, ev);
+ next = gh_lnode_next(current);
+
+ if (nse->event_done) {
+ /* event is done, remove it from the event list and update IOD pointers
+ * to the first events of each kind */
+ update_first_events(nse);
+ gh_list_remove(evlists[i], current);
+ gh_list_append(&nsp->free_events, &nse->nodeq_io);
+
+ if (nse->timeout.tv_sec)
+ gh_heap_remove(&nsp->expirables, &nse->expire);
+ }
+ }
+ }
+}
+
+static int nevent_unref(struct npool *nsp, struct nevent *nse) {
+ switch (nse->type) {
+ case NSE_TYPE_CONNECT:
+ case NSE_TYPE_CONNECT_SSL:
+ gh_list_remove(&nsp->connect_events, &nse->nodeq_io);
+ break;
+
+ case NSE_TYPE_READ:
+ gh_list_remove(&nsp->read_events, &nse->nodeq_io);
+ break;
+
+ case NSE_TYPE_WRITE:
+ gh_list_remove(&nsp->write_events, &nse->nodeq_io);
+ break;
+
+#if HAVE_PCAP
+ case NSE_TYPE_PCAP_READ: {
+ char read = 0;
+ char pcap = 0;
+
+#if PCAP_BSD_SELECT_HACK
+ read = pcap = 1;
+#else
+ if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0)
+ read = 1;
+ else
+ pcap = 1;
+#endif /* PCAP_BSD_SELECT_HACK */
+
+ if (read)
+ gh_list_remove(&nsp->read_events, &nse->nodeq_io);
+ if (pcap)
+ gh_list_remove(&nsp->pcap_read_events, &nse->nodeq_pcap);
+
+ break;
+ }
+#endif /* HAVE_PCAP */
+
+ case NSE_TYPE_TIMER:
+ /* Nothing to do */
+ break;
+
+ default:
+ fatal("Unknown event type %d", nse->type);
+ }
+ gh_list_append(&nsp->free_events, &nse->nodeq_io);
+ return 0;
+}
+
+void process_expired_events(struct npool *nsp) {
+ for (;;) {
+ gh_hnode_t *hnode;
+ struct nevent *nse;
+
+ hnode = gh_heap_min(&nsp->expirables);
+ if (!hnode)
+ break;
+
+ nse = container_of(hnode, struct nevent, expire);
+ if (!event_timedout(nse))
+ break;
+
+ gh_heap_remove(&nsp->expirables, hnode);
+ process_event(nsp, NULL, nse, EV_NONE);
+ assert(nse->event_done);
+ update_first_events(nse);
+ nevent_unref(nsp, nse);
+ }
+}
+
+/* Calling this function will cause nsock_loop to quit on its next iteration
+ * with a return value of NSOCK_LOOP_QUIT. */
+void nsock_loop_quit(nsock_pool nsp) {
+ struct npool *ms = (struct npool *)nsp;
+ ms->quit = 1;
+}
+
+/* Grab the latest time as recorded by the nsock library, which does so at least
+ * once per event loop (in main_loop). Not only does this function (generally)
+ * avoid a system call, but in many circumstances it is better to use nsock's
+ * time rather than the system time. If nsock has never obtained the time when
+ * you call it, it will do so before returning */
+const struct timeval *nsock_gettimeofday() {
+ if (nsock_tod.tv_sec == 0)
+ gettimeofday(&nsock_tod, NULL);
+ return &nsock_tod;
+}
+
+/* Adds an event to the appropriate nsp event list, handles housekeeping such as
+ * adjusting the descriptor select/poll lists, registering the timeout value,
+ * etc. */
+void nsock_pool_add_event(struct npool *nsp, struct nevent *nse) {
+ nsock_log_debug("NSE #%lu: Adding event (timeout in %ldms)",
+ nse->id,
+ (long)TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod));
+
+ nsp->events_pending++;
+
+ if (!nse->event_done && nse->timeout.tv_sec) {
+ /* This event is expirable, add it to the queue */
+ gh_heap_push(&nsp->expirables, &nse->expire);
+ }
+
+ /* Now we do the event type specific actions */
+ switch (nse->type) {
+ case NSE_TYPE_CONNECT:
+ case NSE_TYPE_CONNECT_SSL:
+ if (!nse->event_done) {
+ assert(nse->iod->sd >= 0);
+ socket_count_read_inc(nse->iod);
+ socket_count_write_inc(nse->iod);
+ update_events(nse->iod, nsp, nse, EV_READ|EV_WRITE, EV_NONE);
+ }
+ iod_add_event(nse->iod, nse);
+ break;
+
+ case NSE_TYPE_READ:
+ if (!nse->event_done) {
+ assert(nse->iod->sd >= 0);
+ socket_count_read_inc(nse->iod);
+ update_events(nse->iod, nsp, nse, EV_READ, EV_NONE);
+#if HAVE_OPENSSL
+ if (nse->iod->ssl)
+ nse->sslinfo.ssl_desire = SSL_ERROR_WANT_READ;
+#endif
+ }
+ iod_add_event(nse->iod, nse);
+ break;
+
+ case NSE_TYPE_WRITE:
+ if (!nse->event_done) {
+ assert(nse->iod->sd >= 0);
+ socket_count_write_inc(nse->iod);
+ update_events(nse->iod, nsp, nse, EV_WRITE, EV_NONE);
+#if HAVE_OPENSSL
+ if (nse->iod->ssl)
+ nse->sslinfo.ssl_desire = SSL_ERROR_WANT_WRITE;
+#endif
+ }
+ iod_add_event(nse->iod, nse);
+ break;
+
+ case NSE_TYPE_TIMER:
+ /* nothing to do */
+ break;
+
+#if HAVE_PCAP
+ case NSE_TYPE_PCAP_READ: {
+ mspcap *mp = (mspcap *)nse->iod->pcap;
+
+ assert(mp);
+ if (mp->pcap_desc >= 0) { /* pcap descriptor present */
+ if (!nse->event_done) {
+ socket_count_readpcap_inc(nse->iod);
+ update_events(nse->iod, nsp, nse, EV_READ, EV_NONE);
+ }
+ nsock_log_debug_all("PCAP NSE #%lu: Adding event to READ_EVENTS", nse->id);
+
+ #if PCAP_BSD_SELECT_HACK
+ /* when using BSD hack we must do pcap_next() after select().
+ * Let's insert this pcap to bot queues, to selectable and nonselectable.
+ * This will result in doing pcap_next_ex() just before select() */
+ nsock_log_debug_all("PCAP NSE #%lu: Adding event to PCAP_READ_EVENTS", nse->id);
+ #endif
+ } else {
+ /* pcap isn't selectable. Add it to pcap-specific queue. */
+ nsock_log_debug_all("PCAP NSE #%lu: Adding event to PCAP_READ_EVENTS", nse->id);
+ }
+ iod_add_event(nse->iod, nse);
+ break;
+ }
+#endif
+
+ default:
+ fatal("Unknown nsock event type (%d)", nse->type);
+ }
+
+ /* It can happen that the event already completed. In which case we can
+ * already deliver it, even though we're probably not inside nsock_loop(). */
+ if (nse->event_done) {
+ event_dispatch_and_delete(nsp, nse, 1);
+ update_first_events(nse);
+ nevent_unref(nsp, nse);
+ }
+}
+
+/* An event has been completed and the handler is about to be called. This
+ * function writes out tracing data about the event if necessary */
+void nsock_trace_handler_callback(struct npool *ms, struct nevent *nse) {
+ struct niod *nsi;
+ char *str;
+ int strlength = 0;
+ char displaystr[256];
+ char errstr[256];
+
+ if (NsockLogLevel > NSOCK_LOG_INFO)
+ return;
+
+ nsi = nse->iod;
+
+ if (nse->status == NSE_STATUS_ERROR)
+ Snprintf(errstr, sizeof(errstr), "[%s (%d)] ", socket_strerror(nse->errnum),
+ nse->errnum);
+ else
+ errstr[0] = '\0';
+
+ /* Some types have special tracing treatment */
+ switch (nse->type) {
+ case NSE_TYPE_CONNECT:
+ case NSE_TYPE_CONNECT_SSL:
+ nsock_log_info("Callback: %s %s %sfor EID %li [%s]",
+ nse_type2str(nse->type), nse_status2str(nse->status),
+ errstr, nse->id, get_peeraddr_string(nsi));
+ break;
+
+ case NSE_TYPE_READ:
+ if (nse->status != NSE_STATUS_SUCCESS) {
+ nsock_log_info("Callback: %s %s %sfor EID %li [%s]",
+ nse_type2str(nse->type), nse_status2str(nse->status),
+ errstr, nse->id, get_peeraddr_string(nsi));
+ } else {
+ str = nse_readbuf(nse, &strlength);
+ if (strlength < 80) {
+ memcpy(displaystr, ": ", 2);
+ memcpy(displaystr + 2, str, strlength);
+ displaystr[2 + strlength] = '\0';
+ replacenonprintable(displaystr + 2, strlength, '.');
+ } else {
+ displaystr[0] = '\0';
+ }
+ nsock_log_info("Callback: %s %s for EID %li [%s] %s(%d bytes)%s",
+ nse_type2str(nse->type), nse_status2str(nse->status),
+ nse->id,
+ get_peeraddr_string(nsi),
+ nse_eof(nse) ? "[EOF]" : "", strlength, displaystr);
+ }
+ break;
+
+ case NSE_TYPE_WRITE:
+ nsock_log_info("Callback: %s %s %sfor EID %li [%s]",
+ nse_type2str(nse->type), nse_status2str(nse->status),
+ errstr, nse->id, get_peeraddr_string(nsi));
+ break;
+
+ case NSE_TYPE_TIMER:
+ nsock_log_info("Callback: %s %s %sfor EID %li",
+ nse_type2str(nse->type), nse_status2str(nse->status),
+ errstr, nse->id);
+ break;
+
+#if HAVE_PCAP
+ case NSE_TYPE_PCAP_READ:
+ nsock_log_info("Callback: %s %s %sfor EID %li ",
+ nse_type2str(nse->type), nse_status2str(nse->status),
+ errstr, nse->id);
+ break;
+#endif
+
+ default:
+ fatal("Invalid nsock event type (%d)", nse->type);
+ }
+}
+
diff --git a/nsock/src/nsock_engines.c b/nsock/src/nsock_engines.c
new file mode 100644
index 0000000..de9d44e
--- /dev/null
+++ b/nsock/src/nsock_engines.c
@@ -0,0 +1,187 @@
+/***************************************************************************
+ * nsock_engines.c -- This contains the functions and definitions to *
+ * manage the list of available IO engines. Each IO engine leverages a *
+ * specific IO notification function to wait for events. Nsock will try *
+ * to use the most efficient engine for your system. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "nsock_config.h"
+#endif
+
+#include "nsock_internal.h"
+
+#if HAVE_IOCP
+ extern struct io_engine engine_iocp;
+ #define ENGINE_IOCP &engine_iocp,
+#else
+ #define ENGINE_IOCP
+#endif /* HAVE_IOCP */
+
+#if HAVE_EPOLL
+ extern struct io_engine engine_epoll;
+ #define ENGINE_EPOLL &engine_epoll,
+#else
+ #define ENGINE_EPOLL
+#endif /* HAVE_EPOLL */
+
+#if HAVE_KQUEUE
+ extern struct io_engine engine_kqueue;
+ #define ENGINE_KQUEUE &engine_kqueue,
+#else
+ #define ENGINE_KQUEUE
+#endif /* HAVE_KQUEUE */
+
+#if HAVE_POLL
+ extern struct io_engine engine_poll;
+ #define ENGINE_POLL &engine_poll,
+#else
+ #define ENGINE_POLL
+#endif /* HAVE_POLL */
+
+/* select() based engine is the fallback engine, we assume it's always available */
+extern struct io_engine engine_select;
+#define ENGINE_SELECT &engine_select,
+
+/* Available IO engines. This depends on which IO management interfaces are
+ * available on your system. Engines must be sorted by order of preference */
+static struct io_engine *available_engines[] = {
+ ENGINE_EPOLL
+ ENGINE_KQUEUE
+ ENGINE_POLL
+ ENGINE_IOCP
+ ENGINE_SELECT
+ NULL
+};
+
+static char *engine_hint;
+
+int posix_iod_connect(struct npool *nsp, int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
+ return connect(sockfd, addr, addrlen);
+}
+
+int posix_iod_read(struct npool *nsp, int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) {
+ return recvfrom(sockfd, (char *)buf, len, flags, src_addr, addrlen);
+}
+
+int posix_iod_write(struct npool *nsp, int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) {
+ struct sockaddr_storage *dest = (struct sockaddr_storage *)dest_addr;
+ if (dest->ss_family == AF_UNSPEC)
+ return send(sockfd, (char *)buf, len, flags);
+ else
+ return sendto(sockfd, (char *)buf, len, flags, dest_addr, addrlen);
+}
+
+struct io_operations posix_io_operations = {
+ posix_iod_connect,
+ posix_iod_read,
+ posix_iod_write
+};
+
+struct io_engine *get_io_engine(void) {
+ struct io_engine *engine = NULL;
+ int i;
+
+ if (!engine_hint) {
+ engine = available_engines[0];
+ } else {
+ for (i = 0; available_engines[i] != NULL; i++)
+ if (strcmp(engine_hint, available_engines[i]->name) == 0) {
+ engine = available_engines[i];
+ break;
+ }
+ }
+
+ if (!engine)
+ fatal("No suitable IO engine found! (%s)\n",
+ engine_hint ? engine_hint : "no hint");
+
+ return engine;
+}
+
+int nsock_set_default_engine(char *engine) {
+ if (engine_hint)
+ free(engine_hint);
+
+ if (engine) {
+ int i;
+
+ for (i = 0; available_engines[i] != NULL; i++) {
+ if (strcmp(engine, available_engines[i]->name) == 0) {
+ engine_hint = strdup(engine);
+ return 0;
+ }
+ }
+ return -1;
+ }
+ /* having engine = NULL is fine. This is actually the
+ * way to tell nsock to use the default engine again. */
+ engine_hint = NULL;
+ return 0;
+}
+
+const char *nsock_list_engines(void) {
+ return
+#if HAVE_IOCP
+ "iocp "
+#endif
+#if HAVE_EPOLL
+ "epoll "
+#endif
+#if HAVE_KQUEUE
+ "kqueue "
+#endif
+#if HAVE_POLL
+ "poll "
+#endif
+ "select";
+}
+
diff --git a/nsock/src/nsock_event.c b/nsock/src/nsock_event.c
new file mode 100644
index 0000000..bfc489b
--- /dev/null
+++ b/nsock/src/nsock_event.c
@@ -0,0 +1,538 @@
+/***************************************************************************
+ * nsock_event.c -- Functions dealing with nsock_events (and their *
+ * struct nevent internal representation. An event is created when you do *
+ * various calls (for reading, writing, connecting, timers, etc) and is *
+ * provided back to you in the callback when the call completes or *
+ * fails. It is automatically destroyed after the callback returns *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include "nsock_internal.h"
+#include "nsock_log.h"
+#include "gh_list.h"
+
+#if HAVE_PCAP
+#include "nsock_pcap.h"
+#endif
+
+#include <string.h>
+
+extern struct timeval nsock_tod;
+
+/* Find the type of an event that spawned a callback */
+enum nse_type nse_type(nsock_event nse) {
+ struct nevent *me = (struct nevent *)nse;
+ return me->type;
+}
+
+enum nse_status nse_status(nsock_event nse) {
+ struct nevent *me = (struct nevent *)nse;
+ return me->status;
+}
+
+int nse_eof(nsock_event nse) {
+ struct nevent *me = (struct nevent *)nse;
+ return me->eof;
+}
+
+/* Obtains the nsock_iod (see below) associated with the event. Note that
+ * some events (such as timers) don't have an nsock_iod associated with them */
+nsock_iod nse_iod(nsock_event ms_event) {
+ struct nevent *nse = (struct nevent *)ms_event;
+ return (nsock_iod) nse->iod;
+}
+
+/* This next function returns the errno style error code -- which is only valid
+ * if the status is NSE_STATUS_ERROR */
+int nse_errorcode(nsock_event nse) {
+ struct nevent *me = (struct nevent *)nse;
+ return me->errnum;
+}
+
+/* Every event has an ID which will be unique throughout the program's execution
+ * unless you use (literally) billions of them */
+nsock_event_id nse_id(nsock_event nse) {
+ struct nevent *me = (struct nevent *)nse;
+ return me->id;
+}
+
+/* If you did a read request, and the result was STATUS_SUCCESS, this function
+ * provides the buffer that was read in as well as the number of chars read.
+ * The buffer should not be modified or free'd */
+char *nse_readbuf(nsock_event nse, int *nbytes) {
+ struct nevent *me = (struct nevent *)nse;
+
+ if (nbytes)
+ *nbytes = fs_length(&(me->iobuf));
+ return fs_str(&(me->iobuf));
+}
+
+static void first_ev_next(struct nevent *nse, gh_lnode_t **first, int nodeq2) {
+ if (!first || !*first)
+ return;
+
+ if (&nse->nodeq_io == *first || &nse->nodeq_pcap == *first) {
+ gh_lnode_t *next;
+
+ next = gh_lnode_next(*first);
+ if (next) {
+ struct nevent *newevent;
+
+ if (nodeq2)
+ newevent = lnode_nevent2(next);
+ else
+ newevent = lnode_nevent(next);
+
+ if (newevent->iod == nse->iod)
+ *first = next;
+ else
+ *first = NULL;
+ } else {
+ *first = NULL;
+ }
+ }
+}
+
+void update_first_events(struct nevent *nse) {
+ switch (get_event_id_type(nse->id)) {
+ case NSE_TYPE_CONNECT:
+ case NSE_TYPE_CONNECT_SSL:
+ first_ev_next(nse, &nse->iod->first_connect, 0);
+ break;
+
+ case NSE_TYPE_READ:
+ first_ev_next(nse, &nse->iod->first_read, 0);
+ break;
+
+ case NSE_TYPE_WRITE:
+ first_ev_next(nse, &nse->iod->first_write, 0);
+ break;
+
+#if HAVE_PCAP
+ case NSE_TYPE_PCAP_READ:
+ first_ev_next(nse, &nse->iod->first_read, 0);
+ first_ev_next(nse, &nse->iod->first_pcap_read, 1);
+ break;
+#endif
+
+ case NSE_TYPE_TIMER:
+ /* nothing to do */
+ break;
+
+ default:
+ fatal("Bogus event type in update_first_events");
+ break;
+ }
+}
+
+/* Cancel an event (such as a timer or read request). If notify is nonzero, the
+ * requester will be sent an event CANCELLED status back to the given handler.
+ * But in some cases there is no need to do this (like if the function deleting
+ * it is the one which created it), in which case 0 can be passed to skip the
+ * step. This function returns zero if the event is not found, nonzero
+ * otherwise. */
+int nsock_event_cancel(nsock_pool ms_pool, nsock_event_id id, int notify) {
+ struct npool *nsp = (struct npool *)ms_pool;
+ enum nse_type type;
+ unsigned int i;
+ gh_list_t *event_list = NULL, *event_list2 = NULL;
+ gh_lnode_t *current, *next;
+ struct nevent *nse = NULL;
+
+ assert(nsp);
+
+ type = get_event_id_type(id);
+ nsock_log_info("Event #%li (type %s) cancelled", id, nse_type2str(type));
+
+ /* First we figure out what list it is in */
+ switch (type) {
+ case NSE_TYPE_CONNECT:
+ case NSE_TYPE_CONNECT_SSL:
+ event_list = &nsp->connect_events;
+ break;
+
+ case NSE_TYPE_READ:
+ event_list = &nsp->read_events;
+ break;
+
+ case NSE_TYPE_WRITE:
+ event_list = &nsp->write_events;
+ break;
+
+ case NSE_TYPE_TIMER:
+ for (i = 0; i < gh_heap_count(&nsp->expirables); i++) {
+ gh_hnode_t *hnode;
+
+ hnode = gh_heap_find(&nsp->expirables, i);
+ nse = container_of(hnode, struct nevent, expire);
+ if (nse->id == id)
+ return nevent_delete(nsp, nse, NULL, NULL, notify);
+ }
+ return 0;
+
+#if HAVE_PCAP
+ case NSE_TYPE_PCAP_READ:
+ event_list = &nsp->read_events;
+ event_list2 = &nsp->pcap_read_events;
+ break;
+#endif
+
+ default:
+ fatal("Bogus event type in nsock_event_cancel"); break;
+ }
+
+ /* Now we try to find the event in the list */
+ for (current = gh_list_first_elem(event_list); current != NULL; current = next) {
+ next = gh_lnode_next(current);
+ nse = lnode_nevent(current);
+ if (nse->id == id)
+ break;
+ }
+
+ if (current == NULL && event_list2) {
+ event_list = event_list2;
+ for (current = gh_list_first_elem(event_list); current != NULL; current = next) {
+ next = gh_lnode_next(current);
+ nse = lnode_nevent2(current);
+ if (nse->id == id)
+ break;
+ }
+ }
+ if (current == NULL)
+ return 0;
+
+ return nevent_delete(nsp, nse, event_list, current, notify);
+}
+
+/* An internal function for cancelling an event when you already have a pointer
+ * to the struct nevent (use nsock_event_cancel if you just have an ID). The
+ * event_list passed in should correspond to the type of the event. For example,
+ * with NSE_TYPE_READ, you would pass in &nsp->read_events;. elem is the list
+ * element in event_list which holds the event. Pass a nonzero for notify if
+ * you want the program owning the event to be notified that it has been
+ * cancelled */
+int nevent_delete(struct npool *nsp, struct nevent *nse, gh_list_t *event_list,
+ gh_lnode_t *elem, int notify) {
+ if (nse->event_done) {
+ /* This event has already been marked for death somewhere else -- it will be
+ * gone soon (and if we try to kill it now all hell will break loose due to
+ * reentrancy. */
+ return 0;
+ }
+
+ nsock_log_info("%s on event #%li (type %s)", __func__, nse->id,
+ nse_type2str(nse->type));
+
+ /* Now that we found the event... we go through the motions of cleanly
+ * cancelling it */
+ switch (nse->type) {
+ case NSE_TYPE_CONNECT:
+ case NSE_TYPE_CONNECT_SSL:
+ handle_connect_result(nsp, nse, NSE_STATUS_CANCELLED);
+ break;
+
+ case NSE_TYPE_READ:
+ handle_read_result(nsp, nse, NSE_STATUS_CANCELLED);
+ break;
+
+ case NSE_TYPE_WRITE:
+ handle_write_result(nsp, nse, NSE_STATUS_CANCELLED);
+ break;
+
+ case NSE_TYPE_TIMER:
+ handle_timer_result(nsp, nse, NSE_STATUS_CANCELLED);
+ break;
+
+#if HAVE_PCAP
+ case NSE_TYPE_PCAP_READ:
+ handle_pcap_read_result(nsp, nse, NSE_STATUS_CANCELLED);
+ break;
+#endif
+
+ default:
+ fatal("Invalid nsock event type (%d)", nse->type);
+ }
+
+ assert(nse->event_done);
+
+ if (nse->timeout.tv_sec)
+ gh_heap_remove(&nsp->expirables, &nse->expire);
+
+ if (event_list) {
+ update_first_events(nse);
+ gh_list_remove(event_list, elem);
+ }
+
+ gh_list_append(&nsp->free_events, &nse->nodeq_io);
+
+ nsock_log_debug_all("NSE #%lu: Removing event from list", nse->id);
+
+#if HAVE_PCAP
+#if PCAP_BSD_SELECT_HACK
+ if (nse->type == NSE_TYPE_PCAP_READ) {
+ nsock_log_debug_all("PCAP NSE #%lu: CANCEL TEST pcap=%p read=%p curr=%p sd=%i",
+ nse->id, &nsp->pcap_read_events, &nsp->read_events,
+ event_list,((mspcap *)nse->iod->pcap)->pcap_desc);
+
+ /* If event occurred, and we're in BSD_HACK mode, then this event was added to
+ * two queues. read_event and pcap_read_event Of course we should
+ * destroy it only once. I assume we're now in read_event, so just unlink
+ * this event from pcap_read_event */
+ if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0 && event_list == &nsp->read_events) {
+ /* event is done, list is read_events and we're in BSD_HACK mode. So unlink
+ * event from pcap_read_events */
+ gh_list_remove(&nsp->pcap_read_events, &nse->nodeq_pcap);
+ nsock_log_debug_all("PCAP NSE #%lu: Removing event from PCAP_READ_EVENTS", nse->id);
+ }
+
+ if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0 && event_list == &nsp->pcap_read_events) {
+ /* event is done, list is read_events and we're in BSD_HACK mode.
+ * So unlink event from read_events */
+ gh_list_remove(&nsp->read_events, &nse->nodeq_io);
+
+ nsock_log_debug_all("PCAP NSE #%lu: Removing event from READ_EVENTS", nse->id);
+ }
+ }
+#endif
+#endif
+ event_dispatch_and_delete(nsp, nse, notify);
+ return 1;
+}
+
+/* Adjust various statistics, dispatches the event handler (if notify is
+ * nonzero) and then deletes the event. This function does NOT delete the event
+ * from any lists it might be on (eg nsp->read_list etc.) nse->event_done
+ * MUST be true when you call this */
+void event_dispatch_and_delete(struct npool *nsp, struct nevent *nse, int notify) {
+ assert(nsp);
+ assert(nse);
+
+ assert(nse->event_done);
+
+ nsp->events_pending--;
+ assert(nsp->events_pending >= 0);
+
+ if (nse->iod) {
+ nse->iod->events_pending--;
+ assert(nse->iod->events_pending >= 0);
+ }
+
+ if (notify) {
+ nsock_trace_handler_callback(nsp, nse);
+ nse->handler(nsp, nse, nse->userdata);
+ }
+
+ /* FIXME: We should be updating stats here ... */
+
+ /* Now we clobber the event ... */
+ event_delete(nsp, nse);
+}
+
+/* OK -- the idea is that we want the type included in the rightmost two bits
+ * and the serial number in the leftmost 30 or 62. But we also want to insure a
+ * correct wrap-around in the case of an obscene number of event. One
+ * definition of a "correct" wraparound is that it goes from the highest number
+ * back to one (not zero) because we don't want event numbers to ever be zero.
+ * */
+nsock_event_id get_new_event_id(struct npool *ms, enum nse_type type) {
+ int type_code = (int)type;
+ unsigned long serial = ms->next_event_serial++;
+ unsigned long max_serial_allowed;
+ int shiftbits;
+
+ assert(type < NSE_TYPE_MAX);
+
+ shiftbits = sizeof(nsock_event_id) * 8 - TYPE_CODE_NUM_BITS;
+ max_serial_allowed = ((unsigned long)1 << shiftbits) - 1;
+ if (serial == max_serial_allowed) {
+ /* then the next serial will be one because 0 is forbidden */
+ ms->next_event_serial = 1;
+ }
+
+ return (serial << TYPE_CODE_NUM_BITS) | type_code;
+}
+
+/* Take an event ID and return the type (NSE_TYPE_CONNECT, etc */
+enum nse_type get_event_id_type(nsock_event_id event_id) {
+ return (enum nse_type)((event_id & ((1 << TYPE_CODE_NUM_BITS) - 1)));
+}
+
+/* Create a new event structure -- must be deleted later with event_delete,
+ * unless it returns NULL (failure). NULL can be passed in for the struct niod
+ * and the userdata if not available */
+struct nevent *event_new(struct npool *nsp, enum nse_type type,
+ struct niod *iod, int timeout_msecs,
+ nsock_ev_handler handler, void *userdata) {
+ struct nevent *nse;
+ gh_lnode_t *lnode;
+
+ /* Bring us up to date for the timeout calculation. */
+ gettimeofday(&nsock_tod, NULL);
+
+ if (iod) {
+ iod->events_pending++;
+ assert(iod->state != NSIOD_STATE_DELETED);
+ }
+
+ /* First we check if one is available from the free list ... */
+ lnode = gh_list_pop(&nsp->free_events);
+ if (!lnode)
+ nse = (struct nevent *)safe_malloc(sizeof(*nse));
+ else
+ nse = lnode_nevent(lnode);
+
+ memset(nse, 0, sizeof(*nse));
+
+ nse->id = get_new_event_id(nsp, type);
+ nse->type = type;
+ nse->status = NSE_STATUS_NONE;
+ gh_hnode_invalidate(&nse->expire);
+#if HAVE_OPENSSL
+ nse->sslinfo.ssl_desire = SSL_ERROR_NONE;
+#endif
+
+ if (type == NSE_TYPE_READ || type == NSE_TYPE_WRITE)
+ filespace_init(&(nse->iobuf), 1024);
+
+#if HAVE_PCAP
+ if (type == NSE_TYPE_PCAP_READ) {
+ mspcap *mp;
+ int sz;
+
+ assert(iod != NULL);
+ mp = (mspcap *)iod->pcap;
+ assert(mp);
+
+ sz = mp->snaplen+1 + sizeof(nsock_pcap);
+ filespace_init(&(nse->iobuf), sz);
+ }
+#endif
+
+ if (timeout_msecs != -1) {
+ assert(timeout_msecs >= 0);
+ TIMEVAL_MSEC_ADD(nse->timeout, nsock_tod, timeout_msecs);
+ }
+
+ nse->iod = iod;
+ nse->handler = handler;
+ nse->userdata = userdata;
+
+ if (nse->iod == NULL)
+ nsock_log_debug("%s (IOD #NULL) (EID #%li)", __func__, nse->id);
+ else
+ nsock_log_debug("%s (IOD #%li) (EID #%li)", __func__, nse->iod->id,
+ nse->id);
+ return nse;
+}
+
+/* Free an struct nevent which was allocated with event_new, including all internal
+ * resources. Note -- we assume that nse->iod->events_pending (if it exists)
+ * has ALREADY been decremented (done during event_dispatch_and_delete) -- so
+ * remember to do this if you call event_delete() directly */
+void event_delete(struct npool *nsp, struct nevent *nse) {
+ if (nse->iod == NULL)
+ nsock_log_debug("%s (IOD #NULL) (EID #%li)", __func__, nse->id);
+ else
+ nsock_log_debug("%s (IOD #%li) (EID #%li)", __func__, nse->iod->id, nse->id);
+
+ /* First free the IOBuf inside it if necessary */
+ if (nse->type == NSE_TYPE_READ || nse->type == NSE_TYPE_WRITE) {
+ fs_free(&nse->iobuf);
+ }
+ #if HAVE_PCAP
+ if (nse->type == NSE_TYPE_PCAP_READ) {
+ fs_free(&nse->iobuf);
+ nsock_log_debug_all("PCAP removed %lu", nse->id);
+ }
+ #endif
+
+ /* Now we add the event back into the free pool */
+ nse->event_done = 1;
+}
+
+
+/* Takes an nse_type (as returned by nse_type() and returns a static string name
+ * that you can use for printing, etc. */
+const char *nse_type2str(enum nse_type type) {
+ switch (type) {
+ case NSE_TYPE_CONNECT: return "CONNECT";
+ case NSE_TYPE_CONNECT_SSL: return "SSL-CONNECT";
+ case NSE_TYPE_READ: return "READ";
+ case NSE_TYPE_WRITE: return "WRITE";
+ case NSE_TYPE_TIMER: return "TIMER";
+ case NSE_TYPE_PCAP_READ: return "READ-PCAP";
+ default:
+ return "UNKNOWN!";
+ }
+}
+
+/* Takes an nse_status (as returned by nse_status() and returns a static string
+ * name that you can use for printing, etc. */
+const char *nse_status2str(enum nse_status status) {
+ switch (status) {
+ case NSE_STATUS_NONE: return "NONE";
+ case NSE_STATUS_SUCCESS: return "SUCCESS";
+ case NSE_STATUS_ERROR: return "ERROR";
+ case NSE_STATUS_TIMEOUT: return "TIMEOUT";
+ case NSE_STATUS_CANCELLED: return "CANCELLED";
+ case NSE_STATUS_KILL: return "KILL";
+ case NSE_STATUS_EOF: return "EOF";
+ case NSE_STATUS_PROXYERROR: return "PROXY ERROR";
+ default:
+ return "UNKNOWN!";
+ }
+}
+
+int event_timedout(struct nevent *nse) {
+ if (nse->event_done)
+ return 0;
+
+ return (nse->timeout.tv_sec && !TIMEVAL_AFTER(nse->timeout, nsock_tod));
+}
diff --git a/nsock/src/nsock_internal.h b/nsock/src/nsock_internal.h
new file mode 100644
index 0000000..dc47c3f
--- /dev/null
+++ b/nsock/src/nsock_internal.h
@@ -0,0 +1,522 @@
+/***************************************************************************
+ * nsock_internal.h -- PRIVATE interface definitions for the guts of the *
+ * nsock parallel socket event library. Applications calling this library *
+ * should NOT include this. even LOOK at these :). *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifndef NSOCK_INTERNAL_H
+#define NSOCK_INTERNAL_H
+
+#include <nbase.h>
+
+#ifdef HAVE_CONFIG_H
+#include "nsock_config.h"
+#include "nbase_config.h"
+#endif
+
+#ifdef WIN32
+#include "nbase_winconfig.h"
+#include <Winsock2.h>
+#endif
+
+#include "gh_list.h"
+#include "gh_heap.h"
+#include "filespace.h"
+#include "nsock.h" /* The public interface -- I need it for some enum defs */
+#include "nsock_ssl.h"
+#include "nsock_proxy.h"
+
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
+#ifndef IPPROTO_SCTP
+#define IPPROTO_SCTP 132
+#endif
+
+
+/* ------------------- CONSTANTS ------------------- */
+#define READ_BUFFER_SZ 8192
+
+enum nsock_read_types {
+ NSOCK_READLINES,
+ NSOCK_READBYTES,
+ NSOCK_READ
+};
+
+enum iod_state {
+ NSIOD_STATE_DELETED,
+ NSIOD_STATE_INITIAL,
+
+ /* sd was provided to us in nsock_iod_new2 (see nsock_iod.c) */
+ NSIOD_STATE_UNKNOWN,
+
+ NSIOD_STATE_CONNECTED_TCP,
+ NSIOD_STATE_CONNECTED_UDP
+};
+
+/* XXX: ensure that these values can be OR'ed when adding new ones */
+#define EV_NONE 0x00
+#define EV_READ 0x01
+#define EV_WRITE 0x02
+#define EV_EXCEPT 0x04
+
+
+/* ------------------- STRUCTURES ------------------- */
+
+struct readinfo {
+ enum nsock_read_types read_type;
+ /* num lines; num bytes; whatever (depends on read_type) */
+ int num;
+};
+
+struct writeinfo {
+ struct sockaddr_storage dest;
+ size_t destlen;
+ /* Number of bytes successfully written */
+ int written_so_far;
+};
+
+/* Remember that callers of this library should NOT be accessing these
+ * fields directly */
+struct npool {
+ /* User data, NULL if unset */
+ void *userdata;
+
+ /* IO Engine vtable */
+ struct io_engine *engine;
+ /* IO Engine internal data */
+ void *engine_data;
+
+ /* Active network events */
+ gh_list_t connect_events;
+ gh_list_t read_events;
+ gh_list_t write_events;
+#if HAVE_PCAP
+ gh_list_t pcap_read_events;
+#endif
+ gh_heap_t expirables;
+
+ /* Active iods and related lists of events */
+ gh_list_t active_iods;
+
+ /* struct niod structures that have been freed for reuse */
+ gh_list_t free_iods;
+ /* When an event is deleted, we stick it here for later reuse */
+ gh_list_t free_events;
+
+ /* Number of events pending (total) on all lists */
+ int events_pending;
+
+ /* Serial # of next event (used to create next nsock_event_id */
+ unsigned long next_event_serial;
+ /* Serial # of next iod to be created */
+ unsigned long next_iod_serial;
+
+ /* If nsock_loop() returns NSOCK_LOOP_ERROR, this is where we describe the
+ * error (errnum fashion) */
+ int errnum;
+
+ /* If true, new sockets will have SO_BROADCAST set */
+ int broadcast;
+
+ /* Interface to bind to; only supported on Linux with SO_BINDTODEVICE sockopt. */
+ const char *device;
+
+ /* If true, exit the next iteration of nsock_loop with a status of
+ * NSOCK_LOOP_QUIT. */
+ int quit;
+
+#if HAVE_OPENSSL
+ /* The SSL Context (options and such) */
+ SSL_CTX *sslctx;
+#ifdef HAVE_DTLS_CLIENT_METHOD
+ SSL_CTX *dtlsctx;
+#endif
+#endif
+
+ /* Optional proxy chain (NULL is not set). Can only be set once per NSP (using
+ * nsock_proxychain_new() or nsock_pool_set_proxychain(). */
+ struct proxy_chain *px_chain;
+
+};
+
+
+/* nsock_iod is like a "file descriptor" for the nsock library. You use it to
+ * request events. */
+struct niod {
+ /* The socket descriptor related to the event */
+ int sd;
+
+ /* Number of pending events on this iod */
+ int events_pending;
+
+ /* Pending events */
+ gh_lnode_t *first_connect;
+ gh_lnode_t *first_read;
+ gh_lnode_t *first_write;
+#if HAVE_PCAP
+ gh_lnode_t *first_pcap_read;
+#endif
+
+ int readsd_count;
+ int writesd_count;
+#if HAVE_PCAP
+ int readpcapsd_count;
+#endif
+
+ int watched_events;
+
+ /* The struct npool used to create the iod (used for deletion) */
+ struct npool *nsp;
+
+ enum iod_state state;
+
+ /* The host and port we are connected to using sd (saves a call to getpeername) */
+ struct sockaddr_storage peer;
+ /* The host and port to bind to with sd */
+ struct sockaddr_storage local;
+
+ /* The length of peer/local actually used (sizeof(sockaddr_in) or
+ * sizeof(sockaddr_in6), SUN_LEN(sockaddr_un), or 0 if peer/local
+ * has not been filled in */
+ size_t locallen;
+ size_t peerlen;
+
+ /* -1 if none yet, otherwise IPPROTO_TCP, etc. */
+ int lastproto;
+
+ /* The struct npool keeps track of NIODs that have been allocated so that it
+ * can destroy them if the msp is deleted. This pointer makes it easy to
+ * remove this struct niod from the allocated list when necessary */
+ gh_lnode_t nodeq;
+
+#define IOD_REGISTERED 0x01
+#define IOD_PROCESSED 0x02 /* internally used by engine_kqueue.c */
+
+#define IOD_PROPSET(iod, flag) ((iod)->_flags |= (flag))
+#define IOD_PROPCLR(iod, flag) ((iod)->_flags &= ~(flag))
+#define IOD_PROPGET(iod, flag) (((iod)->_flags & (flag)) != 0)
+ char _flags;
+
+ /* Used for SSL Server Name Indication. */
+ char *hostname;
+
+#if HAVE_OPENSSL
+ /* An SSL connection (or NULL if none) */
+ SSL *ssl;
+ /* SSL SESSION ID (or NULL if none) */
+ SSL_SESSION *ssl_session;
+#else
+ /* Because there are many if (nsi->ssl) cases in the code */
+ char *ssl;
+#endif
+ /* Every iod has an id which is always unique for the same nspool (unless you
+ * create billions of them) */
+ unsigned long id;
+
+ /* No. of bytes read from the sd*/
+ unsigned long read_count;
+ /* No. of bytes written to the sd */
+ unsigned long write_count;
+
+ void *userdata;
+
+ /* IP options to set on socket before connect() */
+ void *ipopts;
+ int ipoptslen;
+
+ /* Pointer to mspcap struct (used only if pcap support is included) */
+ void *pcap;
+
+ struct proxy_chain_context *px_ctx;
+
+};
+
+
+/* nsock_event_t handles a single event. Its ID is generally returned when the
+ * event is created, and the event is included in callbacks */
+struct nevent {
+ /* Every event has an ID which is unique for a given nsock unless you blow
+ * through more than 500,000,000 events */
+ nsock_event_id id;
+
+ enum nse_type type;
+ enum nse_status status;
+
+ /* For write events, this is the data to be written, for read events, this is
+ * what we will read into */
+ struct filespace iobuf;
+
+ /* The timeout of the event -- absolute time
+ * except that tv_sec == 0 means no timeout */
+ struct timeval timeout;
+
+ /* Info pertaining to READ requests */
+ struct readinfo readinfo;
+ /* Info pertaining to WRITE requests */
+ struct writeinfo writeinfo;
+
+#if HAVE_OPENSSL
+ struct sslinfo sslinfo;
+#endif
+
+ /* If we return a status of NSE_STATUS_ERROR, this must be set */
+ int errnum;
+
+ /* The nsock I/O descriptor related to event (if applicable) */
+ struct niod *iod;
+
+ /* The handler to call when event is complete */
+ nsock_ev_handler handler;
+
+ /* slot in the expirable binheap */
+ gh_hnode_t expire;
+
+ /* For some reasons (see nsock_pcap.c) we register pcap events as both read
+ * and pcap_read events when in PCAP_BSD_SELECT_HACK mode. We then need two
+ * gh_lnode_t handles. To make code simpler, we _always_ use _nodeq_pcap for
+ * pcap_read events and _nodeq_io for the other ones.
+ * When not in PCAP_BSD_SELECT_HACK mode we define both handles as members
+ * of an union to optimize memory footprint. */
+ gh_lnode_t nodeq_io;
+ gh_lnode_t nodeq_pcap;
+
+ /* Optional (NULL if unset) pointer to pass to the handler */
+ void *userdata;
+
+ /* If this event is all filled out and ready for immediate delivery,
+ * event_done is nonzero. Used when event is finished at unexpected time and
+ * we want to dispatch it later to avoid duplicating stat update code and all
+ * that other crap */
+ unsigned int event_done: 1;
+ unsigned int eof: 1;
+
+#if HAVE_IOCP
+ struct extended_overlapped *eov;
+#endif
+};
+
+struct io_operations {
+ int(*iod_connect)(struct npool *nsp, int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+
+ int(*iod_read)(struct npool *nsp, int sockfd, void *buf, size_t len, int flags,
+ struct sockaddr *src_addr, socklen_t *addrlen);
+
+ int(*iod_write)(struct npool *nsp, int sockfd, const void *buf, size_t len, int flags,
+ const struct sockaddr *dest_addr, socklen_t addrlen);
+};
+
+struct io_engine {
+ /* Human readable identifier for this engine. */
+ const char *name;
+
+ /* Engine constructor */
+ int (*init)(struct npool *nsp);
+
+ /* Engine destructor */
+ void (*destroy)(struct npool *nsp);
+
+ /* Register a new IOD to the engine */
+ int(*iod_register)(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev);
+
+ /* Remove a registered IOD */
+ int(*iod_unregister)(struct npool *nsp, struct niod *iod);
+
+ /* Modify events for a registered IOD.
+ * - ev_set represent the events to add
+ * - ev_clr represent the events to delete (if set) */
+ int (*iod_modify)(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr);
+
+ /* Main engine loop */
+ int (*loop)(struct npool *nsp, int msec_timeout);
+
+ /* I/O operations */
+ struct io_operations *io_operations;
+};
+
+/* ----------- NSOCK I/O ENGINE CONVENIENCE WRAPPERS ------------ */
+static inline int nsock_engine_init(struct npool *nsp) {
+ return nsp->engine->init(nsp);
+}
+
+static inline void nsock_engine_destroy(struct npool *nsp) {
+ nsp->engine->destroy(nsp);
+ return;
+}
+
+static inline int nsock_engine_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev) {
+ return nsp->engine->iod_register(nsp, iod, nse, ev);
+}
+
+static inline int nsock_engine_iod_unregister(struct npool *nsp, struct niod *iod) {
+ return nsp->engine->iod_unregister(nsp, iod);
+}
+
+static inline int nsock_engine_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr) {
+ return nsp->engine->iod_modify(nsp, iod, nse, ev_set, ev_clr);
+}
+
+static inline int nsock_engine_loop(struct npool *nsp, int msec_timeout) {
+ return nsp->engine->loop(nsp, msec_timeout);
+}
+
+/* ------------------- PROTOTYPES ------------------- */
+
+int event_timedout(struct nevent *nse);
+
+/* Get a new nsock_event_id, given a type */
+nsock_event_id get_new_event_id(struct npool *nsp, enum nse_type type);
+
+/* Take an event ID and return the type (NSE_TYPE_CONNECT, etc */
+enum nse_type get_event_id_type(nsock_event_id event_id);
+
+/* Create a new event structure -- must be deleted later with event_delete,
+ * unless it returns NULL (failure). NULL can be passed in for the struct niod and
+ * the userdata if not available. */
+struct nevent *event_new(struct npool *nsp, enum nse_type type, struct niod *iod,
+ int timeout_msecs, nsock_ev_handler handler, void *userdata);
+
+/* An internal function for cancelling an event when you already have a pointer
+ * to the struct nevent (use nsock_event_cancel if you just have an ID). The
+ * event_list passed in should correspond to the type of the event. For
+ * example, with NSE_TYPE_READ, you would pass in &iod->read_events;. elem
+ * is the list element in event_list which holds the event. Pass a nonzero for
+ * notify if you want the program owning the event to be notified that it has
+ * been cancelled */
+int nevent_delete(struct npool *nsp, struct nevent *nse, gh_list_t *event_list, gh_lnode_t *elem, int notify);
+
+/* Adjust various statistics, dispatches the event handler (if notify is
+ * nonzero) and then deletes the event. This function does NOT delete the event
+ * from any lists it might be on (eg nsp->read_list etc.) nse->event_done
+ * MUST be true when you call this */
+void event_dispatch_and_delete(struct npool *nsp, struct nevent *nse, int notify);
+
+/* Free an struct nevent which was allocated with event_new, including all internal
+ * resources. Note -- we assume that nse->iod->events_pending (if it exists)
+ * has ALREADY been decremented (done during event_dispatch_and_delete) -- so
+ * remember to do this if you call event_delete() directly */
+void event_delete(struct npool *nsp, struct nevent *nse);
+
+/* Add an event to the appropriate nsp event list, handles housekeeping such as
+ * adjusting the descriptor select/poll lists, registering the timeout value,
+ * etc. */
+void nsock_pool_add_event(struct npool *nsp, struct nevent *nse);
+
+void nsock_connect_internal(struct npool *ms, struct nevent *nse, int type, int proto, struct sockaddr_storage *ss, size_t sslen, unsigned int port);
+
+/* Comments on using the following handle_*_result functions are available in nsock_core.c */
+
+/* handle_connect_results assumes that select or poll have already shown the
+ * descriptor to be active */
+void handle_connect_result(struct npool *ms, struct nevent *nse, enum nse_status status);
+
+void handle_read_result(struct npool *ms, struct nevent *nse, enum nse_status status);
+
+void handle_write_result(struct npool *ms, struct nevent *nse, enum nse_status status);
+
+void handle_timer_result(struct npool *ms, struct nevent *nse, enum nse_status status);
+
+#if HAVE_PCAP
+void handle_pcap_read_result(struct npool *ms, struct nevent *nse, enum nse_status status);
+#endif
+
+/* An event has been completed and the handler is about to be called. This
+ * function writes out tracing data about the event if necessary */
+void nsock_trace_handler_callback(struct npool *ms, struct nevent *nse);
+
+#if HAVE_OPENSSL
+/* Sets the ssl session of an nsock_iod, increments usage count. The session
+ * should not have been set yet (as no freeing is done) */
+void nsi_set_ssl_session(struct niod *iod, SSL_SESSION *sessid);
+#endif
+
+static inline struct nevent *next_expirable_event(struct npool *nsp) {
+ gh_hnode_t *hnode;
+
+ hnode = gh_heap_min(&nsp->expirables);
+ if (!hnode)
+ return NULL;
+
+ return container_of(hnode, struct nevent, expire);
+}
+
+static inline struct nevent *lnode_nevent(gh_lnode_t *lnode) {
+ return container_of(lnode, struct nevent, nodeq_io);
+}
+
+static inline struct nevent *lnode_nevent2(gh_lnode_t *lnode) {
+ return container_of(lnode, struct nevent, nodeq_pcap);
+}
+
+#endif /* NSOCK_INTERNAL_H */
+
diff --git a/nsock/src/nsock_iod.c b/nsock/src/nsock_iod.c
new file mode 100644
index 0000000..d74ab5e
--- /dev/null
+++ b/nsock/src/nsock_iod.c
@@ -0,0 +1,455 @@
+/***************************************************************************
+ * nsock_iod.c -- This contains the functions relating to nsock_iod (and *
+ * its nsock internal manifestation -- nsockiod. This is is similar to a *
+ * file descriptor in that you create it and then use it to initiate *
+ * connections, read/write data, etc. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include "nsock.h"
+#include "nsock_internal.h"
+#include "nsock_log.h"
+#include "gh_list.h"
+#include "netutils.h"
+
+#if HAVE_PCAP
+#include "nsock_pcap.h"
+#endif
+
+#include <string.h>
+
+
+/* nsock_iod is like a "file descriptor" for the nsock library. You use it to
+ * request events. And here is how you create an nsock_iod. nsock_iod_new returns
+ * NULL if the iod cannot be allocated. Pass NULL as userdata if you don't want
+ * to immediately associate any user data with the iod. */
+nsock_iod nsock_iod_new(nsock_pool nsockp, void *userdata) {
+ return nsock_iod_new2(nsockp, -1, userdata);
+}
+
+/* This version allows you to associate an existing sd with the msi so that you
+ * can read/write it using the nsock infrastructure. For example, you may want
+ * to watch for data from STDIN_FILENO at the same time as you read/write
+ * various sockets. STDIN_FILENO is a special case, however. Any other sd is
+ * dup()ed, so you may close or otherwise manipulate your copy. The duped copy
+ * will be destroyed when the nsi is destroyed. */
+nsock_iod nsock_iod_new2(nsock_pool nsockp, int sd, void *userdata) {
+ struct npool *nsp = (struct npool *)nsockp;
+ gh_lnode_t *lnode;
+ struct niod *nsi;
+
+ lnode = gh_list_pop(&nsp->free_iods);
+ if (!lnode) {
+ nsi = (struct niod *)safe_malloc(sizeof(*nsi));
+ memset(nsi, 0, sizeof(*nsi));
+ } else {
+ nsi = container_of(lnode, struct niod, nodeq);
+ }
+
+ if (sd == -1) {
+ nsi->sd = -1;
+ nsi->state = NSIOD_STATE_INITIAL;
+ } else if (sd == STDIN_FILENO) {
+ nsi->sd = STDIN_FILENO;
+ nsi->state = NSIOD_STATE_UNKNOWN;
+ } else {
+ nsi->sd = dup_socket(sd);
+ if (nsi->sd == -1) {
+ free(nsi);
+ return NULL;
+ }
+ unblock_socket(nsi->sd);
+ nsi->state = NSIOD_STATE_UNKNOWN;
+ }
+
+ nsi->first_connect = NULL;
+ nsi->first_read = NULL;
+ nsi->first_write = NULL;
+#if HAVE_PCAP
+ nsi->first_pcap_read = NULL;
+ nsi->readpcapsd_count = 0;
+#endif
+ nsi->readsd_count = 0;
+ nsi->write_count = 0;
+
+ nsi->userdata = userdata;
+ nsi->nsp = (struct npool *)nsockp;
+
+ nsi->_flags = 0;
+
+ nsi->read_count = 0;
+ nsi->write_count = 0;
+
+ nsi->hostname = NULL;
+
+ nsi->ipopts = NULL;
+ nsi->ipoptslen = 0;
+
+#if HAVE_OPENSSL
+ nsi->ssl_session = NULL;
+#endif
+
+ if (nsp->px_chain) {
+ nsi->px_ctx = proxy_chain_context_new(nsp);
+ } else {
+ nsi->px_ctx = NULL;
+ }
+
+ nsi->id = nsp->next_iod_serial++;
+ if (nsi->id == 0)
+ nsi->id = nsp->next_iod_serial++;
+
+ /* The nsp keeps track of active iods so it can delete them if it is deleted */
+ gh_list_append(&nsp->active_iods, &nsi->nodeq);
+
+ nsock_log_info("nsock_iod_new (IOD #%lu)", nsi->id);
+
+ return (nsock_iod)nsi;
+}
+
+/* Defined in nsock_core.c. */
+int socket_count_zero(struct niod *iod, struct npool *ms);
+
+/* If nsock_iod_new returned success, you must free the iod when you are done with
+ * it to conserve memory (and in some cases, sockets). After this call,
+ * nsockiod may no longer be used -- you need to create a new one with
+ * nsock_iod_new(). pending_response tells what to do with any events that are
+ * pending on this nsock_iod. This can be NSOCK_PENDING_NOTIFY (send a KILL
+ * notification to each event), NSOCK_PENDING_SILENT (do not send notification
+ * to the killed events), or NSOCK_PENDING_ERROR (print an error message and
+ * quit the program) */
+void nsock_iod_delete(nsock_iod nsockiod, enum nsock_del_mode pending_response) {
+#if HAVE_PCAP
+#define NUM_EVT_TYPES 4
+#else
+#define NUM_EVT_TYPES 3
+#endif
+ struct niod *nsi = (struct niod *)nsockiod;
+ gh_lnode_t *evlist_ar[NUM_EVT_TYPES];
+ gh_list_t *corresp_list[NUM_EVT_TYPES];
+ int i;
+ gh_lnode_t *current, *next;
+
+ assert(nsi);
+
+ if (nsi->state == NSIOD_STATE_DELETED) {
+ /* This nsi is already marked as deleted, will probably be removed from the
+ * list very soon. Just return to avoid breaking reentrancy. */
+ return;
+ }
+
+ nsock_log_info("nsock_iod_delete (IOD #%lu)", nsi->id);
+
+ if (nsi->events_pending > 0) {
+ /* shit -- they killed the struct niod while an event was still pending on it.
+ * Maybe I should store the pending events in the iod. On the other hand,
+ * this should be a pretty rare occurrence and so I'll save space and hassle
+ * by just locating the events here by searching through the active events
+ * list */
+ if (pending_response == NSOCK_PENDING_ERROR)
+ fatal("nsock_iod_delete called with argument NSOCK_PENDING_ERROR on a nsock_iod that has %d pending event(s) associated with it", nsi->events_pending);
+
+ assert(pending_response == NSOCK_PENDING_NOTIFY || pending_response == NSOCK_PENDING_SILENT);
+
+ evlist_ar[0] = nsi->first_connect;
+ evlist_ar[1] = nsi->first_read;
+ evlist_ar[2] = nsi->first_write;
+#if HAVE_PCAP
+ evlist_ar[3] = nsi->first_pcap_read;
+#endif
+
+ corresp_list[0] = &nsi->nsp->connect_events;
+ corresp_list[1] = &nsi->nsp->read_events;
+ corresp_list[2] = &nsi->nsp->write_events;
+#if HAVE_PCAP
+ corresp_list[3] = &nsi->nsp->pcap_read_events;
+#endif
+
+ for (i = 0; i < NUM_EVT_TYPES && nsi->events_pending > 0; i++) {
+ for (current = evlist_ar[i]; current != NULL; current = next) {
+ struct nevent *nse;
+
+ next = gh_lnode_next(current);
+ nse = lnode_nevent(current);
+
+ /* we're done with this list of events for the current IOD */
+ if (nse->iod != nsi)
+ break;
+
+ nevent_delete(nsi->nsp, nse, corresp_list[i], current, pending_response == NSOCK_PENDING_NOTIFY);
+ }
+ }
+ }
+
+ if (nsi->events_pending != 0)
+ fatal("Trying to delete NSI, but could not find %d of the purportedly pending events on that IOD.\n", nsi->events_pending);
+
+ /* Make sure we no longer select on this socket, in case the socket counts
+ * weren't already decremented to zero. */
+ if (nsi->sd >= 0)
+ socket_count_zero(nsi, nsi->nsp);
+
+ free(nsi->hostname);
+
+#if HAVE_OPENSSL
+ /* Close any SSL resources */
+ if (nsi->ssl) {
+ /* No longer free session because copy nsi stores is not reference counted */
+#if 0
+ if (nsi->ssl_session)
+ SSL_SESSION_free(nsi->ssl_session);
+ nsi->ssl_session = NULL;
+#endif
+
+ if (SSL_shutdown(nsi->ssl) == -1) {
+ nsock_log_info("nsock_iod_delete: SSL shutdown failed (%s) on NSI %li",
+ ERR_reason_error_string(SSL_get_error(nsi->ssl, -1)), nsi->id);
+ }
+
+ /* I don't really care if the SSL_shutdown() succeeded politely. I could
+ * make the SD blocking temporarily for this, but I'm hoping it will succeed
+ * 95% of the time because we can usually write to a socket. */
+ SSL_free(nsi->ssl);
+ nsi->ssl = NULL;
+ }
+#endif
+
+ if (nsi->sd >= 0 && nsi->sd != STDIN_FILENO) {
+ close(nsi->sd);
+ nsi->sd = -1;
+ }
+
+ nsi->state = NSIOD_STATE_DELETED;
+ nsi->userdata = NULL;
+
+ if (nsi->ipoptslen)
+ free(nsi->ipopts);
+
+#if HAVE_PCAP
+ if (nsi->pcap){
+ mspcap *mp = (mspcap *)nsi->pcap;
+
+ if (mp->pt){
+ pcap_close(mp->pt);
+ mp->pt = NULL;
+ }
+ if (mp->pcap_desc) {
+ /* pcap_close() will close the associated pcap descriptor */
+ mp->pcap_desc = -1;
+ }
+ if (mp->pcap_device) {
+ free(mp->pcap_device);
+ mp->pcap_device = NULL;
+ }
+ free(mp);
+ nsi->pcap = NULL;
+ }
+#endif
+
+ if (nsi->px_ctx)
+ proxy_chain_context_delete(nsi->px_ctx);
+}
+
+/* Returns the ID of an nsock_iod . This ID is always unique amongst ids for a
+ * given nspool (unless you blow through billions of them). */
+unsigned long nsock_iod_id(nsock_iod nsockiod) {
+ assert(nsockiod);
+ return ((struct niod *)nsockiod)->id;
+}
+
+/* Returns the SSL object inside an nsock_iod, or NULL if unset. */
+nsock_ssl nsock_iod_get_ssl(nsock_iod iod) {
+#if HAVE_OPENSSL
+ return ((struct niod *)iod)->ssl;
+#else
+ return NULL;
+#endif
+}
+
+/* Returns the SSL_SESSION of an nsock_iod.
+ * Increments its usage count if inc_ref is not zero. */
+nsock_ssl_session nsock_iod_get_ssl_session(nsock_iod iod, int inc_ref) {
+#if HAVE_OPENSSL
+ if (inc_ref)
+ return SSL_get1_session(((struct niod *)iod)->ssl);
+ else
+ return SSL_get0_session(((struct niod *)iod)->ssl);
+#else
+ return NULL;
+#endif
+}
+
+/* sets the ssl session of an nsock_iod, increments usage count. The session
+ * should not have been set yet (as no freeing is done) */
+#if HAVE_OPENSSL
+void nsi_set_ssl_session(struct niod *iod, SSL_SESSION *sessid) {
+ if (sessid) {
+ iod->ssl_session = sessid;
+ /* No reference counting for the copy stored briefly in nsiod */
+ }
+}
+#endif
+
+/* Sometimes it is useful to store a pointer to information inside the struct niod so
+ * you can retrieve it during a callback. */
+void nsock_iod_set_udata(nsock_iod iod, void *udata) {
+ assert(iod);
+ ((struct niod *)iod)->userdata = udata;
+}
+
+/* And the function above wouldn't make much sense if we didn't have a way to
+ * retrieve that data... */
+void *nsock_iod_get_udata(nsock_iod iod) {
+ assert(iod);
+ return ((struct niod *)iod)->userdata;
+}
+
+/* Returns 1 if an NSI is communicating via SSL, 0 otherwise. */
+int nsock_iod_check_ssl(nsock_iod iod) {
+ return (((struct niod *)iod)->ssl) ? 1 : 0;
+}
+
+/* Returns the remote peer port (or -1 if unavailable). Note the return value
+ * is a whole int so that -1 can be distinguished from 65535. Port is returned
+ * in host byte order. */
+int nsock_iod_get_peerport(nsock_iod iod) {
+ struct niod *nsi = (struct niod *)iod;
+ int fam;
+
+ if (nsi->peerlen <= 0)
+ return -1;
+
+ fam = ((struct sockaddr_in *)&nsi->peer)->sin_family;
+
+ if (fam == AF_INET)
+ return ntohs(((struct sockaddr_in *)&nsi->peer)->sin_port);
+#if HAVE_IPV6
+ else if (fam == AF_INET6)
+ return ntohs(((struct sockaddr_in6 *)&nsi->peer)->sin6_port);
+#endif
+
+ return -1;
+}
+
+/* Sets the local address to bind to before connect() */
+int nsock_iod_set_localaddr(nsock_iod iod, struct sockaddr_storage *ss,
+ size_t sslen) {
+ struct niod *nsi = (struct niod *)iod;
+
+ assert(nsi);
+
+ if (sslen > sizeof(nsi->local))
+ return -1;
+
+ memcpy(&nsi->local, ss, sslen);
+ nsi->locallen = sslen;
+ return 0;
+}
+
+/* Sets IPv4 options to apply before connect(). It makes a copy of the options,
+ * so you can free() yours if necessary. This copy is freed when the iod is
+ * destroyed. */
+int nsock_iod_set_ipoptions(nsock_iod iod, void *opts, size_t optslen) {
+ struct niod *nsi = (struct niod *)iod;
+
+ assert(nsi);
+
+ if (optslen > 44)
+ return -1;
+
+ nsi->ipopts = safe_malloc(optslen);
+ memcpy(nsi->ipopts, opts, optslen);
+ nsi->ipoptslen = optslen;
+ return 0;
+}
+
+/* I didn't want to do this. Its an ugly hack, but I suspect it will be
+ * necessary. I certainly can't reproduce in nsock EVERYTHING you might want
+ * to do with a socket. So I'm offering you this function to obtain the socket
+ * descriptor which is (usually) wrapped in a nsock_iod). You can do
+ * "reasonable" things with it, like setting socket receive buffers. But don't
+ * create havok by closing the descriptor! If the descriptor you get back is
+ * -1, the iod does not currently possess a valid descriptor */
+int nsock_iod_get_sd(nsock_iod iod) {
+ struct niod *nsi = (struct niod *)iod;
+
+ assert(nsi);
+
+#if HAVE_PCAP
+ if (nsi->pcap)
+ return ((mspcap *)nsi->pcap)->pcap_desc;
+ else
+#endif
+ return nsi->sd;
+}
+
+unsigned long nsock_iod_get_read_count(nsock_iod iod){
+ assert(iod);
+ return ((struct niod *)iod)->read_count;
+}
+
+unsigned long nsock_iod_get_write_count(nsock_iod iod){
+ assert(iod);
+ return ((struct niod *)iod)->write_count;
+}
+
+int nsock_iod_set_hostname(nsock_iod iod, const char *hostname) {
+ struct niod *nsi = (struct niod *)iod;
+
+ if (nsi->hostname != NULL)
+ free(nsi->hostname);
+
+ nsi->hostname = strdup(hostname);
+ if (nsi->hostname == NULL)
+ return -1;
+
+ return 0;
+}
+
diff --git a/nsock/src/nsock_log.c b/nsock/src/nsock_log.c
new file mode 100644
index 0000000..5ef033c
--- /dev/null
+++ b/nsock/src/nsock_log.c
@@ -0,0 +1,116 @@
+/***************************************************************************
+ * nsock_log.c -- nsock logging infrastructure. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+
+#define _GNU_SOURCE
+#include <stdio.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "nsock_internal.h"
+#include "nsock_log.h"
+
+static void nsock_stderr_logger(const struct nsock_log_rec *rec);
+
+extern struct timeval nsock_tod;
+
+nsock_loglevel_t NsockLogLevel = NSOCK_LOG_ERROR;
+nsock_logger_t NsockLogger = nsock_stderr_logger;
+
+
+void nsock_set_log_function(nsock_logger_t logger) {
+ if (logger != NULL)
+ NsockLogger = logger;
+ else
+ NsockLogger = nsock_stderr_logger;
+
+ nsock_log_debug("Registered external logging function: %p", NsockLogger);
+}
+
+nsock_loglevel_t nsock_get_loglevel(void) {
+ return NsockLogLevel;
+}
+
+void nsock_set_loglevel(nsock_loglevel_t loglevel) {
+ NsockLogLevel = loglevel;
+ nsock_log_debug("Set log level to %s", nsock_loglevel2str(loglevel));
+}
+
+void nsock_stderr_logger(const struct nsock_log_rec *rec) {
+ fprintf(stderr, "libnsock %s(): %s\n", rec->func, rec->msg);
+}
+
+void __nsock_log_internal(nsock_loglevel_t loglevel, const char *file, int line,
+ const char *func, const char *format, ...) {
+ struct nsock_log_rec rec;
+ va_list args;
+ int rc;
+
+ va_start(args, format);
+
+ rec.level = loglevel;
+ rec.time = nsock_tod;
+ rec.file = file;
+ rec.line = line;
+ rec.func = func;
+
+ rc = vasprintf(&rec.msg, format, args);
+ if (rc >= 0) {
+ NsockLogger(&rec);
+ free(rec.msg);
+ }
+ va_end(args);
+}
+
diff --git a/nsock/src/nsock_log.h b/nsock/src/nsock_log.h
new file mode 100644
index 0000000..49b0dea
--- /dev/null
+++ b/nsock/src/nsock_log.h
@@ -0,0 +1,115 @@
+/***************************************************************************
+ * nsock_log.c -- nsock logging infrastructure. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+
+#ifndef NSOCK_LOG_H
+#define NSOCK_LOG_H
+
+#include "nsock.h"
+
+extern nsock_loglevel_t NsockLogLevel;
+extern nsock_logger_t NsockLogger;
+
+
+#define NSOCK_LOG_WRAP(lvl, ...) \
+ do { \
+ if (NsockLogger && (lvl) >= NsockLogLevel) { \
+ __nsock_log_internal((lvl), __FILE__, __LINE__, __func__, __VA_ARGS__); \
+ } \
+ } while (0)
+
+
+static inline const char *nsock_loglevel2str(nsock_loglevel_t level)
+{
+ switch (level) {
+ case NSOCK_LOG_DBG_ALL:
+ return "FULL DEBUG";
+ case NSOCK_LOG_DBG:
+ return "DEBUG";
+ case NSOCK_LOG_INFO:
+ return "INFO";
+ case NSOCK_LOG_ERROR:
+ return "ERROR";
+ default:
+ return "???";
+ }
+}
+
+/* -- Internal logging macros -- */
+/**
+ * Most detailed debug messages, like allocating or moving objects.
+ */
+#define nsock_log_debug_all(...) NSOCK_LOG_WRAP(NSOCK_LOG_DBG_ALL, __VA_ARGS__)
+
+/**
+ * Detailed debug messages, describing internal operations.
+ */
+#define nsock_log_debug(...) NSOCK_LOG_WRAP(NSOCK_LOG_DBG, __VA_ARGS__)
+
+/**
+ * High level debug messages, describing top level operations and external
+ * requests.
+ */
+#define nsock_log_info(...) NSOCK_LOG_WRAP(NSOCK_LOG_INFO, __VA_ARGS__)
+
+/**
+ * Error messages.
+ */
+#define nsock_log_error(...) NSOCK_LOG_WRAP(NSOCK_LOG_ERROR, __VA_ARGS__)
+
+
+void __nsock_log_internal(nsock_loglevel_t loglevel, const char *file, int line,
+ const char *func, const char *format, ...)
+ __attribute__((format (printf, 5, 6)));
+
+#endif /* NSOCK_LOG_H */
+
diff --git a/nsock/src/nsock_pcap.c b/nsock/src/nsock_pcap.c
new file mode 100644
index 0000000..c9e43d4
--- /dev/null
+++ b/nsock/src/nsock_pcap.c
@@ -0,0 +1,516 @@
+/***************************************************************************
+ * nsock_pcap.c -- This contains pcap operations functions from *
+ * the nsock parallel socket event library *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include "nsock.h"
+#include "nsock_internal.h"
+#include "nsock_log.h"
+
+#include <limits.h>
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#if HAVE_NET_BPF_H
+#ifdef _AIX
+/* Prevent bpf.h from redefining the DLT_ values to their IFT_ values. (See
+ * similar comment in libpcap/pcap-bpf.c.) */
+#undef _AIX
+#include <net/bpf.h>
+#define _AIX
+#else
+#include <net/bpf.h>
+#endif
+#endif
+
+#include "nsock_pcap.h"
+
+extern struct timeval nsock_tod;
+
+#if HAVE_PCAP
+
+#ifndef PCAP_NETMASK_UNKNOWN
+/* libpcap before 1.1.1 (e.g. WinPcap) doesn't handle this specially, so just use 0 netmask */
+#define PCAP_NETMASK_UNKNOWN 0
+#endif
+
+#define PCAP_OPEN_MAX_RETRIES 3
+
+#define PCAP_FAILURE_EXPL_MESSAGE \
+ "There are several possible reasons for this, " \
+ "depending on your operating system:\n" \
+ "LINUX: If you are getting Socket type not supported, " \
+ "try modprobe af_packet or recompile your kernel with PACKET enabled.\n" \
+ "*BSD: If you are getting device not configured, you need to recompile " \
+ "your kernel with Berkeley Packet Filter support." \
+ "If you are getting No such file or directory, try creating the device " \
+ "(eg cd /dev; MAKEDEV <device>; or use mknod).\n" \
+ "*WINDOWS: Nmap only supports ethernet interfaces on Windows for most " \
+ "operations because Microsoft disabled raw sockets as of Windows XP SP2. " \
+ "Depending on the reason for this error, it is possible that the " \
+ "--unprivileged command-line argument will help.\n" \
+ "SOLARIS: If you are trying to scan localhost and getting "\
+ "'/dev/lo0: No such file or directory', complain to Sun. "\
+ "I don't think Solaris can support advanced localhost scans. "\
+ "You can probably use \"-PN -sT localhost\" though.\n\n"
+
+
+static int nsock_pcap_set_filter(struct npool *nsp, pcap_t *pt, const char *device,
+ const char *bpf) {
+ struct bpf_program fcode;
+ int rc;
+
+ rc = pcap_compile(pt, &fcode, (char *)bpf, 1, PCAP_NETMASK_UNKNOWN);
+ if (rc) {
+ nsock_log_error("Error compiling pcap filter: %s", pcap_geterr(pt));
+ return rc;
+ }
+
+ rc = pcap_setfilter(pt, &fcode);
+ if (rc) {
+ nsock_log_error("Failed to set the pcap filter: %s", pcap_geterr(pt));
+ return rc;
+ }
+
+ pcap_freecode(&fcode);
+ return 0;
+}
+
+static int nsock_pcap_get_l3_offset(pcap_t *pt, int *dl) {
+ int datalink;
+ unsigned int offset = 0;
+
+ /* New packet capture device, need to recompute offset */
+ if ((datalink = pcap_datalink(pt)) < 0)
+ fatal("Cannot obtain datalink information: %s", pcap_geterr(pt));
+
+ /* XXX NOTE:
+ * if a new offset ever exceeds the current max (24),
+ * adjust MAX_LINK_HEADERSZ in libnetutil/netutil.h
+ */
+ switch (datalink) {
+ case DLT_EN10MB: offset = 14; break;
+ case DLT_IEEE802: offset = 22; break;
+ #ifdef __amigaos__
+ case DLT_MIAMI: offset = 16; break;
+ #endif
+ #ifdef DLT_LOOP
+ case DLT_LOOP:
+ #endif
+ case DLT_NULL: offset = 4; break;
+
+ case DLT_SLIP:
+ #ifdef DLT_SLIP_BSDOS
+ case DLT_SLIP_BSDOS:
+ #endif
+ #if (FREEBSD || OPENBSD || NETBSD || BSDI || MACOSX)
+ offset = 16;break;
+ #else
+ offset = 24;break; /* Anyone use this??? */
+ #endif
+
+ case DLT_PPP:
+ #ifdef DLT_PPP_BSDOS
+ case DLT_PPP_BSDOS:
+ #endif
+ #ifdef DLT_PPP_SERIAL
+ case DLT_PPP_SERIAL:
+ #endif
+ #ifdef DLT_PPP_ETHER
+ case DLT_PPP_ETHER:
+ #endif
+ #if (FREEBSD || OPENBSD || NETBSD || BSDI || MACOSX)
+ offset = 4;break;
+ #else
+ #ifdef SOLARIS
+ offset = 8;break;
+ #else
+ offset = 24;break; /* Anyone use this? */
+ #endif /* ifdef solaris */
+ #endif /* if freebsd || openbsd || netbsd || bsdi */
+ #ifdef DLT_RAW
+ case DLT_RAW: offset = 0; break;
+ #endif /* DLT_RAW */
+ case DLT_FDDI: offset = 21; break;
+ #ifdef DLT_ENC
+ case DLT_ENC: offset = 12; break;
+ #endif /* DLT_ENC */
+ #ifdef DLT_LINUX_SLL
+ case DLT_LINUX_SLL: offset = 16; break;
+ #endif
+ #ifdef DLT_IPNET
+ case DLT_IPNET: offset = 24; break;
+ #endif /* DLT_IPNET */
+
+ default: /* Sorry, link type is unknown. */
+ fatal("Unknown datalink type %d.\n", datalink);
+ }
+ if (dl)
+ *dl = datalink;
+ return (offset);
+}
+
+/* Convert new nsiod to pcap descriptor. Other parameters have
+ * the same meaning as for pcap_open_live in pcap(3).
+ * device : pcap-style device name
+ * snaplen : size of packet to be copied to handler
+ * promisc : whether to open device in promiscuous mode
+ * bpf_fmt : berkeley filter
+ * return value: NULL if everything was okay, or error string
+ * if error occurred. */
+int nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod, const char *pcap_device,
+ int snaplen, int promisc, const char *bpf_fmt, ...) {
+ struct niod *nsi = (struct niod *)nsiod;
+ struct npool *ms = (struct npool *)nsp;
+ mspcap *mp = (mspcap *)nsi->pcap;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ char bpf[4096];
+ va_list ap;
+ int failed, datalink;
+ int rc;
+
+#ifdef PCAP_CAN_DO_SELECT
+#if PCAP_BSD_SELECT_HACK
+ /* MacOsX reports error if to_ms is too big (like INT_MAX) with error
+ * FAILED. Reported error: BIOCSRTIMEOUT: Invalid argument
+ * INT_MAX/6 (=357913941) seems to be working... */
+ int to_ms = 357913941;
+#else
+ int to_ms = 200;
+#endif /* PCAP_BSD_SELECT_HACK */
+
+#else
+ int to_ms = 1;
+#endif
+
+ gettimeofday(&nsock_tod, NULL);
+
+ if (mp) {
+ nsock_log_error("This nsi already has pcap device opened");
+ return -1;
+ }
+
+ mp = (mspcap *)safe_zalloc(sizeof(mspcap));
+ nsi->pcap = (void *)mp;
+
+ va_start(ap, bpf_fmt);
+ rc = Vsnprintf(bpf, sizeof(bpf), bpf_fmt, ap);
+ va_end(ap);
+
+ if (rc >= (int)sizeof(bpf)) {
+ nsock_log_error("Too-large bpf filter argument");
+ return -1;
+ }
+
+ nsock_log_info("PCAP requested on device '%s' with berkeley filter '%s' "
+ "(promisc=%i snaplen=%i to_ms=%i) (IOD #%li)",
+ pcap_device,bpf, promisc, snaplen, to_ms, nsi->id);
+
+#ifdef __amigaos__
+ // Amiga doesn't have pcap_create
+ // TODO: Does Nmap still work on Amiga?
+ mp->pt = pcap_open_live(pcap_device, snaplen, promisc, to_ms, errbuf);
+ if (!mp->pt) {
+ nsock_log_error("pcap_open_live(%s, %d, %d, %d) failed with error: %s",
+ pcap_device, snaplen, promisc, to_ms, errbuf);
+ nsock_log_error(PCAP_FAILURE_EXPL_MESSAGE);
+ nsock_log_error("Can't open pcap! Are you root?");
+ return -1;
+ }
+#else
+ mp->pt = pcap_create(pcap_device, errbuf);
+ if (!mp->pt) {
+ nsock_log_error("pcap_create(%s) failed with error: %s", pcap_device, errbuf);
+ nsock_log_error(PCAP_FAILURE_EXPL_MESSAGE);
+ nsock_log_error("Can't open pcap! Are you root?");
+ return -1;
+ }
+
+#define MY_PCAP_SET(func, p_t, val) do {\
+ failed = func(p_t, val);\
+ if (failed) {\
+ nsock_log_error(#func "(%d) FAILED: %d.", val, failed);\
+ pcap_close(p_t);\
+ return -1;\
+ }\
+} while(0);
+
+ MY_PCAP_SET(pcap_set_snaplen, mp->pt, snaplen);
+ MY_PCAP_SET(pcap_set_promisc, mp->pt, promisc);
+ MY_PCAP_SET(pcap_set_timeout, mp->pt, to_ms);
+#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
+ MY_PCAP_SET(pcap_set_immediate_mode, mp->pt, 1);
+#endif
+
+ failed = pcap_activate(mp->pt);
+ if (failed < 0) {
+ // PCAP error
+ nsock_log_error("pcap_activate(%s) FAILED: %s.", pcap_device, pcap_geterr(mp->pt));
+ pcap_close(mp->pt);
+ mp->pt = NULL;
+ return -1;
+ }
+ else if (failed > 0) {
+ // PCAP warning, report but assume it'll still work
+ nsock_log_error("pcap_activate(%s) WARNING: %s.", pcap_device, pcap_geterr(mp->pt));
+ }
+#endif /* not __amigaos__ */
+
+ rc = nsock_pcap_set_filter(ms, mp->pt, pcap_device, bpf);
+ if (rc)
+ return rc;
+
+ mp->l3_offset = nsock_pcap_get_l3_offset(mp->pt, &datalink);
+ mp->snaplen = snaplen;
+ mp->datalink = datalink;
+ mp->pcap_device = strdup(pcap_device);
+#ifdef PCAP_CAN_DO_SELECT
+ mp->pcap_desc = pcap_get_selectable_fd(mp->pt);
+#else
+ mp->pcap_desc = -1;
+#endif
+ mp->readsd_count = 0;
+
+#ifndef HAVE_PCAP_SET_IMMEDIATE_MODE
+ /* This is already handled by pcap_set_immediate_mode if available */
+#ifdef BIOCIMMEDIATE
+ /* Without setting this ioctl, some systems (BSDs, though it depends on the
+ * release) will buffer packets in non-blocking mode and only return them in a
+ * bunch when the buffer is full. Setting the ioctl makes each one be
+ * delivered immediately. This is how Linux works by default. See the comments
+ * surrounding the setting of BIOCIMMEDIATE in libpcap/pcap-bpf.c. */
+ if (mp->pcap_desc != -1) {
+ int immediate = 1;
+
+ if (ioctl(mp->pcap_desc, BIOCIMMEDIATE, &immediate) < 0)
+ fatal("Cannot set BIOCIMMEDIATE on pcap descriptor");
+ }
+#elif defined WIN32
+ /* We want any responses back ASAP */
+ pcap_setmintocopy(mp->pt, 0);
+#endif
+#endif
+
+ /* Set device non-blocking */
+ rc = pcap_setnonblock(mp->pt, 1, errbuf);
+ if (rc) {
+
+ /* I can't do select() on pcap!
+ * blocking + no_select is fatal */
+#ifndef PCAP_BSD_SELECT_HACK
+ if (mp->pcap_desc < 0)
+#endif
+ {
+ nsock_log_error("Failed to set pcap descriptor on device %s "
+ "to nonblocking mode: %s", pcap_device, errbuf);
+ return -1;
+ }
+ /* in other case, we can accept blocking pcap */
+ nsock_log_info("Failed to set pcap descriptor on device %s "
+ "to nonblocking state: %s", pcap_device, errbuf);
+ }
+
+ if (NsockLogLevel <= NSOCK_LOG_INFO) {
+ #if PCAP_BSD_SELECT_HACK
+ int bsd_select_hack = 1;
+ #else
+ int bsd_select_hack = 0;
+ #endif
+
+ #if PCAP_RECV_TIMEVAL_VALID
+ int recv_timeval_valid = 1;
+ #else
+ int recv_timeval_valid = 0;
+ #endif
+
+ nsock_log_info("PCAP created successfully on device '%s' "
+ "(pcap_desc=%i bsd_hack=%i to_valid=%i l3_offset=%i) (IOD #%li)",
+ pcap_device, mp->pcap_desc, bsd_select_hack,
+ recv_timeval_valid, mp->l3_offset, nsi->id);
+ }
+ return 0;
+}
+
+/* Requests exactly one packet to be captured. */
+nsock_event_id nsock_pcap_read_packet(nsock_pool nsp, nsock_iod nsiod,
+ nsock_ev_handler handler,
+ int timeout_msecs, void *userdata) {
+ struct niod *nsi = (struct niod *)nsiod;
+ struct npool *ms = (struct npool *)nsp;
+ struct nevent *nse;
+
+ nse = event_new(ms, NSE_TYPE_PCAP_READ, nsi, timeout_msecs, handler, userdata);
+ assert(nse);
+
+ nsock_log_info("Pcap read request from IOD #%li EID %li", nsi->id, nse->id);
+
+ nsock_pool_add_event(ms, nse);
+
+ return nse->id;
+}
+
+/* Remember that pcap descriptor is in nonblocking state. */
+int do_actual_pcap_read(struct nevent *nse) {
+ mspcap *mp = (mspcap *)nse->iod->pcap;
+ nsock_pcap npp;
+ nsock_pcap *n;
+ struct pcap_pkthdr *pkt_header;
+ const unsigned char *pkt_data = NULL;
+ int rc;
+
+ memset(&npp, 0, sizeof(nsock_pcap));
+
+ nsock_log_debug_all("PCAP %s TEST (IOD #%li) (EID #%li)",
+ __func__, nse->iod->id, nse->id);
+
+ assert(fs_length(&(nse->iobuf)) == 0);
+
+ rc = pcap_next_ex(mp->pt, &pkt_header, &pkt_data);
+ switch (rc) {
+ case 1: /* read good packet */
+#ifdef PCAP_RECV_TIMEVAL_VALID
+ npp.ts = pkt_header->ts;
+#else
+ /* On these platforms time received from pcap is invalid.
+ * It's better to set current time */
+ memcpy(&npp.ts, nsock_gettimeofday(), sizeof(struct timeval));
+#endif
+ npp.len = pkt_header->len;
+ npp.caplen = pkt_header->caplen;
+ npp.packet = pkt_data;
+
+ fs_cat(&(nse->iobuf), (char *)&npp, sizeof(npp));
+ fs_cat(&(nse->iobuf), (char *)pkt_data, npp.caplen);
+ n = (nsock_pcap *)fs_str(&(nse->iobuf));
+ n->packet = (unsigned char *)fs_str(&(nse->iobuf)) + sizeof(npp);
+
+ nsock_log_debug_all("PCAP %s READ (IOD #%li) (EID #%li) size=%i",
+ __func__, nse->iod->id, nse->id, pkt_header->caplen);
+ rc = 1;
+ break;
+
+ case 0: /* timeout */
+ rc = 0;
+ break;
+
+ case -1: /* error */
+ fatal("pcap_next_ex() fatal error while reading from pcap: %s\n",
+ pcap_geterr(mp->pt));
+ break;
+
+ case -2: /* no more packets in savefile (if reading from one) */
+ default:
+ fatal("Unexpected return code from pcap_next_ex! (%d)\n", rc);
+ }
+
+ return rc;
+}
+
+void nse_readpcap(nsock_event nsev, const unsigned char **l2_data, size_t *l2_len,
+ const unsigned char **l3_data, size_t *l3_len,
+ size_t *packet_len, struct timeval *ts) {
+ struct nevent *nse = (struct nevent *)nsev;
+ struct niod *iod = nse->iod;
+ mspcap *mp = (mspcap *)iod->pcap;
+ nsock_pcap *n;
+ size_t l2l;
+ size_t l3l;
+
+ n = (nsock_pcap *)fs_str(&(nse->iobuf));
+ if (fs_length(&(nse->iobuf)) < sizeof(nsock_pcap)) {
+ if (l2_data)
+ *l2_data = NULL;
+ if (l2_len)
+ *l2_len = 0;
+ if (l3_data)
+ *l3_data = NULL;
+ if (l3_len)
+ *l3_len = 0;
+ if (packet_len)
+ *packet_len = 0;
+ return;
+ }
+
+ l2l = MIN(mp->l3_offset, n->caplen);
+ l3l = MAX(0, n->caplen-mp->l3_offset);
+
+ if (l2_data)
+ *l2_data = n->packet;
+ if (l2_len)
+ *l2_len = l2l;
+ if (l3_data)
+ *l3_data = (l3l > 0) ? n->packet+l2l : NULL;
+ if (l3_len)
+ *l3_len = l3l;
+ if (packet_len)
+ *packet_len = n->len;
+ if (ts)
+ *ts = n->ts;
+ return;
+}
+
+int nsock_iod_linktype(nsock_iod iod) {
+ struct niod *nsi = (struct niod *)iod;
+ mspcap *mp = (mspcap *)nsi->pcap;
+
+ assert(mp);
+ return (mp->datalink);
+}
+
+int nsock_iod_is_pcap(nsock_iod iod) {
+ struct niod *nsi = (struct niod *)iod;
+ mspcap *mp = (mspcap *)nsi->pcap;
+
+ return (mp != NULL);
+}
+
+#endif /* HAVE_PCAP */
+
diff --git a/nsock/src/nsock_pcap.h b/nsock/src/nsock_pcap.h
new file mode 100644
index 0000000..ca667db
--- /dev/null
+++ b/nsock/src/nsock_pcap.h
@@ -0,0 +1,152 @@
+/***************************************************************************
+ * nsock_pcap.h -- Header for pcap operations functions from *
+ * the nsock parallel socket event library *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifndef NSOCK_PCAP_H
+#define NSOCK_PCAP_H
+
+#include "nsock_internal.h"
+#ifdef HAVE_PCAP
+
+#include "pcap.h"
+
+#include <string.h>
+#include <stdarg.h>
+
+/*
+ * There are three possible ways to read packets from pcap descriptor:
+ * - select() on descriptor:
+ * this one is of course the best, but there are systems that
+ * don't support this like WIN32. This works perfectly for Linux.
+ *
+ * - select() + some hacks:
+ * this one is hack for older bsd systems,
+ * Descriptor *must* be set in nonblocking mode.
+ *
+ * - never do select():
+ * this one is for WIN32 and other systems that return descriptor -1
+ * from pcap_get_selectable_fd().
+ * In this case descriptor *must* be set in nonblocking mode.
+ * If that fails than we can't do any sniffing from that box.
+ *
+ * In any case we try to set descriptor to non-blocking mode.
+ */
+
+/* Returns whether the system supports pcap_get_selectable_fd() properly */
+#if !defined(WIN32) && !defined(SOLARIS_BPF_PCAP_CAPTURE)
+#define PCAP_CAN_DO_SELECT 1
+#endif
+
+/* In some systems (like Windows), the pcap descriptor is not selectable.
+ * Therefore, we cannot just select() on it and expect it to wake us up and
+ * deliver a packet, but we need to poll it continuously. This define sets the
+ * frequency, in milliseconds, at which the pcap handle is polled to determine
+ * if there are any captured packets. Note that this is only used when
+ * PCAP_CAN_DO_SELECT is not defined and therefore it has no effect on systems
+ * like Linux.
+ */
+#define PCAP_POLL_INTERVAL 2
+
+/* Note that on most versions of most BSDs (including Mac OS X) select() and
+ * poll() do not work correctly on BPF devices; pcap_get_selectable_fd() will
+ * return a file descriptor on most of those versions (the exceptions being
+ * FreeBSD 4.3 and 4.4), a simple select() or poll() will not return even after
+ * a timeout specified in pcap_open_live() expires. To work around this, an
+ * application that uses select() or poll() to wait for packets to arrive must
+ * put the pcap_t in non-blocking mode, and must arrange that the select() or
+ * poll() have a timeout less than or equal to the timeout specified in
+ * pcap_open_live(), and must try to read packets after that timeout expires,
+ * regardless of whether select() or poll() indicated that the file descriptor
+ * for the pcap_t is ready to be read or not. (That workaround will not work in
+ * FreeBSD 4.3 and later; however, in FreeBSD 4.6 and later, select() and poll()
+ * work correctly on BPF devices, so the workaround isn't necessary, although it
+ * does no harm.)
+ */
+#if defined(MACOSX) || defined(FREEBSD) || defined(OPENBSD)
+/* Well, now select() is not receiving any pcap events on MACOSX, but maybe it
+ * will someday :) in both cases. It never hurts to enable this feature. It just
+ * has performance penalty. */
+#define PCAP_BSD_SELECT_HACK 1
+#endif
+
+/* Returns whether the packet receive time value obtained from libpcap
+ * (and thus by readip_pcap()) should be considered valid. When
+ * invalid (Windows and Amiga), readip_pcap returns the time you called it. */
+#if !defined(WIN32) && !defined(__amigaos__)
+#define PCAP_RECV_TIMEVAL_VALID 1
+#endif
+
+
+typedef struct{
+ pcap_t *pt;
+ int pcap_desc;
+ /* Like the corresponding member in iod, when this reaches 0 we stop
+ * watching the socket for readability. */
+ int readsd_count;
+ int datalink;
+ int l3_offset;
+ int snaplen;
+ char *pcap_device;
+} mspcap;
+
+typedef struct{
+ struct timeval ts;
+ int caplen;
+ int len;
+ const unsigned char *packet; /* caplen bytes */
+} nsock_pcap;
+
+int do_actual_pcap_read(struct nevent *nse);
+
+#endif /* HAVE_PCAP */
+#endif /* NSOCK_PCAP_H */
+
diff --git a/nsock/src/nsock_pool.c b/nsock/src/nsock_pool.c
new file mode 100644
index 0000000..485a68b
--- /dev/null
+++ b/nsock/src/nsock_pool.c
@@ -0,0 +1,308 @@
+/***************************************************************************
+ * nsock_pool.c -- This contains the functions that deal with creating, *
+ * destroying, and otherwise manipulating nsock_pools (and their internal *
+ * struct npool representation). An nsock_pool aggregates and manages events *
+ * and i/o descriptors *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include "nsock_internal.h"
+#include "nsock_log.h"
+#include "gh_list.h"
+#include "netutils.h"
+
+#include <string.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <signal.h>
+
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+extern struct timeval nsock_tod;
+
+/* To use this library, the first thing they must do is create a pool
+ * so we do the initialization during the first pool creation */
+static int nsocklib_initialized = 0;
+
+
+/* defined in nsock_engines.h */
+struct io_engine *get_io_engine(void);
+
+/* ---- INTERNAL FUNCTIONS PROTOTYPES ---- */
+static void nsock_library_initialize(void);
+/* --------------------------------------- */
+
+
+/* This next function returns the errno style error code -- which is only
+ * valid if the status NSOCK_LOOP_ERROR was returned by nsock_loop() */
+int nsock_pool_get_error(nsock_pool nsp) {
+ struct npool *mt = (struct npool *)nsp;
+ return mt->errnum;
+}
+
+/* Sometimes it is useful to store a pointer to information inside
+ * the NSP so you can retrieve it during a callback. */
+void nsock_pool_set_udata(nsock_pool nsp, void *data) {
+ struct npool *mt = (struct npool *)nsp;
+ mt->userdata = data;
+}
+
+/* And the define above wouldn't make much sense if we didn't have a way
+ * to retrieve that data ... */
+void *nsock_pool_get_udata(nsock_pool nsp) {
+ struct npool *mt = (struct npool *)nsp;
+ return mt->userdata;
+}
+
+/* Turns on or off broadcast support on new sockets. Default is off (0, false)
+ * set in nsock_pool_new(). Any non-zero (true) value sets SO_BROADCAST on all new
+ * sockets (value of optval will be used directly in the setsockopt() call */
+void nsock_pool_set_broadcast(nsock_pool nsp, int optval) {
+ struct npool *mt = (struct npool *)nsp;
+ mt->broadcast = optval;
+}
+
+/* Sets the name of the interface for new sockets to bind to. */
+void nsock_pool_set_device(nsock_pool nsp, const char *device) {
+ struct npool *mt = (struct npool *)nsp;
+ mt->device = device;
+}
+
+static int expirable_cmp(gh_hnode_t *n1, gh_hnode_t *n2) {
+ struct nevent *nse1;
+ struct nevent *nse2;
+
+ nse1 = container_of(n1, struct nevent, expire);
+ nse2 = container_of(n2, struct nevent, expire);
+
+ return (TIMEVAL_BEFORE(nse1->timeout, nse2->timeout)) ? 1 : 0;
+}
+
+/* And here is how you create an nsock_pool. This allocates, initializes, and
+ * returns an nsock_pool event aggregator. In the case of error, NULL will be
+ * returned. If you do not wish to immediately associate any userdata, pass in
+ * NULL. */
+nsock_pool nsock_pool_new(void *userdata) {
+ struct npool *nsp;
+
+ /* initialize the library in not already done */
+ if (!nsocklib_initialized) {
+ nsock_library_initialize();
+ nsocklib_initialized = 1;
+ }
+
+ nsp = (struct npool *)safe_malloc(sizeof(*nsp));
+ memset(nsp, 0, sizeof(*nsp));
+
+ gettimeofday(&nsock_tod, NULL);
+
+ nsp->userdata = userdata;
+
+ nsp->engine = get_io_engine();
+ nsock_engine_init(nsp);
+
+ /* initialize IO events lists */
+ gh_list_init(&nsp->connect_events);
+ gh_list_init(&nsp->read_events);
+ gh_list_init(&nsp->write_events);
+#if HAVE_PCAP
+ gh_list_init(&nsp->pcap_read_events);
+#endif
+
+ /* initialize timer heap */
+ gh_heap_init(&nsp->expirables, expirable_cmp);
+
+ /* initialize the list of IODs */
+ gh_list_init(&nsp->active_iods);
+
+ /* initialize caches */
+ gh_list_init(&nsp->free_iods);
+ gh_list_init(&nsp->free_events);
+
+ nsp->next_event_serial = 1;
+
+ nsp->device = NULL;
+
+#if HAVE_OPENSSL
+ nsp->sslctx = NULL;
+ nsp->dtlsctx = NULL;
+#endif
+
+ nsp->px_chain = NULL;
+
+ return (nsock_pool)nsp;
+}
+
+/* If nsock_pool_new returned success, you must free the nsp when you are done with it
+ * to conserve memory (and in some cases, sockets). After this call, nsp may no
+ * longer be used. Any pending events are sent an NSE_STATUS_KILL callback and
+ * all outstanding iods are deleted. */
+void nsock_pool_delete(nsock_pool ms_pool) {
+ struct npool *nsp = (struct npool *)ms_pool;
+ struct nevent *nse;
+ struct niod *nsi;
+ int i;
+ gh_lnode_t *current, *next;
+ gh_list_t *event_lists[] = {
+ &nsp->connect_events,
+ &nsp->read_events,
+ &nsp->write_events,
+#if HAVE_PCAP
+ &nsp->pcap_read_events,
+#endif
+ NULL
+ };
+
+ assert(nsp);
+
+ /* First I go through all the events sending NSE_STATUS_KILL */
+ for (i = 0; event_lists[i] != NULL; i++) {
+ while (gh_list_count(event_lists[i]) > 0) {
+ gh_lnode_t *lnode = gh_list_pop(event_lists[i]);
+
+ assert(lnode);
+
+#if HAVE_PCAP
+ if (event_lists[i] == &nsp->pcap_read_events)
+ nse = lnode_nevent2(lnode);
+ else
+#endif
+ nse = lnode_nevent(lnode);
+
+ assert(nse);
+
+ nse->status = NSE_STATUS_KILL;
+ nsock_trace_handler_callback(nsp, nse);
+ nse->handler(nsp, nse, nse->userdata);
+
+ if (nse->iod) {
+ nse->iod->events_pending--;
+ assert(nse->iod->events_pending >= 0);
+ }
+ event_delete(nsp, nse);
+ }
+ gh_list_free(event_lists[i]);
+ }
+
+ /* Kill timers too, they're not in event lists */
+ while (gh_heap_count(&nsp->expirables) > 0) {
+ gh_hnode_t *hnode;
+
+ hnode = gh_heap_pop(&nsp->expirables);
+ nse = container_of(hnode, struct nevent, expire);
+
+ if (nse->type == NSE_TYPE_TIMER) {
+ nse->status = NSE_STATUS_KILL;
+ nsock_trace_handler_callback(nsp, nse);
+ nse->handler(nsp, nse, nse->userdata);
+ event_delete(nsp, nse);
+ gh_list_append(&nsp->free_events, &nse->nodeq_io);
+ }
+ }
+
+ gh_heap_free(&nsp->expirables);
+
+ /* foreach struct niod */
+ for (current = gh_list_first_elem(&nsp->active_iods);
+ current != NULL;
+ current = next) {
+ next = gh_lnode_next(current);
+ nsi = container_of(current, struct niod, nodeq);
+
+ nsock_iod_delete(nsi, NSOCK_PENDING_ERROR);
+
+ gh_list_remove(&nsp->active_iods, current);
+ gh_list_prepend(&nsp->free_iods, &nsi->nodeq);
+ }
+
+ /* Now we free all the memory in the free iod list */
+ while ((current = gh_list_pop(&nsp->free_iods))) {
+ nsi = container_of(current, struct niod, nodeq);
+ free(nsi);
+ }
+
+ while ((current = gh_list_pop(&nsp->free_events))) {
+ nse = lnode_nevent(current);
+ free(nse);
+ }
+
+ gh_list_free(&nsp->active_iods);
+ gh_list_free(&nsp->free_iods);
+ gh_list_free(&nsp->free_events);
+
+ nsock_engine_destroy(nsp);
+
+#if HAVE_OPENSSL
+ nsp_ssl_cleanup(nsp);
+#endif
+
+ free(nsp);
+}
+
+void nsock_library_initialize(void) {
+#ifndef WIN32
+ rlim_t res;
+
+ /* We want to make darn sure the evil SIGPIPE is ignored */
+ signal(SIGPIPE, SIG_IGN);
+
+ /* And we're gonna need sockets -- LOTS of sockets ... */
+ res = maximize_fdlimit();
+ assert(res > 7);
+#endif
+ return;
+}
+
diff --git a/nsock/src/nsock_proxy.c b/nsock/src/nsock_proxy.c
new file mode 100644
index 0000000..29a1f3d
--- /dev/null
+++ b/nsock/src/nsock_proxy.c
@@ -0,0 +1,439 @@
+/***************************************************************************
+ * nsock_proxy.c -- This contains the functions relating to proxies. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include "nsock.h"
+#include "nsock_internal.h"
+#include "nsock_log.h"
+#include <string.h>
+
+#define IN_RANGE(x, min, max) ((x) >= (min) && (x) <= (max))
+
+static struct proxy_node *proxy_node_new(const char *proxystr, const char *end);
+
+/* --- Implemented proxy backends --- */
+extern const struct proxy_spec ProxySpecHttp;
+extern const struct proxy_spec ProxySpecSocks4;
+
+
+static const struct proxy_spec *ProxyBackends[] = {
+ &ProxySpecHttp,
+ &ProxySpecSocks4,
+ NULL
+};
+
+
+/* A proxy chain is a comma-separated list of proxy specification strings:
+ * proto://[user:pass@]host[:port] */
+int nsock_proxychain_new(const char *proxystr, nsock_proxychain *chain, nsock_pool nspool) {
+ struct npool *nsp = (struct npool *)nspool;
+ struct proxy_chain *pxc, **pchain = (struct proxy_chain **)chain;
+
+ *pchain = NULL;
+
+ pxc = (struct proxy_chain *)safe_malloc(sizeof(struct proxy_chain));
+ gh_list_init(&pxc->nodes);
+
+ if (proxystr) {
+ const char *next = proxystr;
+ const char *end = strchr(proxystr, ',');
+ struct proxy_node *proxy;
+
+ while (end != NULL) {
+ proxy = proxy_node_new(next, end);
+ if (!proxy)
+ return -1;
+ gh_list_append(&pxc->nodes, &proxy->nodeq);
+ next = end + 1;
+ end = strchr(next, ',');
+ }
+ proxy = proxy_node_new(next, strchr(next, '\0'));
+ if (!proxy)
+ return -1;
+ gh_list_append(&pxc->nodes, &proxy->nodeq);
+ }
+
+ if (nsp) {
+ if (nsock_pool_set_proxychain(nspool, pxc) < 0) {
+ nsock_proxychain_delete(pxc);
+ return -1;
+ }
+ }
+
+ *pchain = pxc;
+ return 1;
+}
+
+void nsock_proxychain_delete(nsock_proxychain chain) {
+ struct proxy_chain *pchain = (struct proxy_chain *)chain;
+ gh_lnode_t *lnode;
+
+ if (!pchain)
+ return;
+
+ while ((lnode = gh_list_pop(&pchain->nodes)) != NULL) {
+ struct proxy_node *node;
+
+ node = container_of(lnode, struct proxy_node, nodeq);
+ node->spec->ops->node_delete(node);
+ }
+
+ gh_list_free(&pchain->nodes);
+ free(pchain);
+}
+
+int nsock_pool_set_proxychain(nsock_pool nspool, nsock_proxychain chain) {
+ struct npool *nsp = (struct npool *)nspool;
+ assert(nsp != NULL);
+
+ if (nsp && nsp->px_chain) {
+ nsock_log_error("Invalid call. Existing proxychain on this nsock_pool");
+ return -1;
+ }
+
+ if (gh_list_count(&chain->nodes) < 1) {
+ nsock_log_error("Invalid call. No proxies in chain");
+ return -1;
+ }
+
+ nsp->px_chain = (struct proxy_chain *)chain;
+ return 1;
+}
+
+struct proxy_chain_context *proxy_chain_context_new(nsock_pool nspool) {
+ struct npool *nsp = (struct npool *)nspool;
+ struct proxy_chain_context *ctx;
+
+ ctx = (struct proxy_chain_context *)safe_malloc(sizeof(struct proxy_chain_context));
+ ctx->px_chain = nsp->px_chain;
+ ctx->px_state = PROXY_STATE_INITIAL;
+ ctx->px_current = container_of(gh_list_first_elem(&nsp->px_chain->nodes),
+ struct proxy_node,
+ nodeq);
+ return ctx;
+}
+
+void proxy_chain_context_delete(struct proxy_chain_context *ctx) {
+ free(ctx);
+}
+
+static void uri_free(struct uri *uri) {
+ free(uri->scheme);
+ free(uri->user);
+ free(uri->pass);
+ free(uri->host);
+ free(uri->path);
+}
+
+static int lowercase(char *s) {
+ char *p;
+
+ for (p = s; *p != '\0'; p++)
+ *p = tolower((int) (unsigned char) *p);
+
+ return p - s;
+}
+
+static int hex_digit_value(char digit) {
+ static const char DIGITS[] = "0123456789abcdef";
+ const char *p;
+
+ if ((unsigned char)digit == '\0')
+ return -1;
+
+ p = strchr(DIGITS, tolower((int)(unsigned char)digit));
+ if (p == NULL)
+ return -1;
+
+ return p - DIGITS;
+}
+
+static int percent_decode(char *s) {
+ char *p, *q;
+
+ /* Skip to the first '%'. If there are no percent escapes, this lets us
+ * return without doing any copying. */
+ q = s;
+ while (*q != '\0' && *q != '%')
+ q++;
+
+ p = q;
+ while (*q != '\0') {
+ if (*q == '%') {
+ int c, d;
+
+ q++;
+ c = hex_digit_value(*q);
+ if (c == -1)
+ return -1;
+ q++;
+ d = hex_digit_value(*q);
+ if (d == -1)
+ return -1;
+
+ *p++ = c * 16 + d;
+ q++;
+ } else {
+ *p++ = *q++;
+ }
+ }
+ *p = '\0';
+
+ return p - s;
+}
+
+static int uri_parse_authority(const char *authority, const char *end, struct uri *uri) {
+ const char *portsep;
+ const char *host_start, *host_end;
+ const char *tail;
+
+ /* We do not support "user:pass@" userinfo. The proxy has no use for it. */
+ if (strchr_p(authority, end, '@') != NULL)
+ return -1;
+
+ /* Find the beginning and end of the host. */
+ host_start = authority;
+
+ if (*host_start == '[') {
+ /* IPv6 address in brackets. */
+ host_start++;
+ if (host_start >= end ||
+ NULL == (host_end = strchr_p(host_start, end, ']'))
+ ) {
+ nsock_log_error("Invalid IPv6 address: %s", authority);
+ return -1;
+ }
+
+ portsep = host_end + 1;
+
+ } else {
+ for (portsep = end; portsep > host_start && *portsep != ':'; portsep--);
+
+ if (portsep == host_start)
+ portsep = end;
+ host_end = portsep;
+ }
+
+ /* Get the port number. */
+ if (portsep + 1 < end && *portsep == ':') {
+ long n;
+
+ errno = 0;
+ n = parse_long(portsep + 1, &tail);
+ if (errno || tail != end || !IN_RANGE(n, 1, 65535)) {
+ nsock_log_error("Invalid port number (%ld), errno = %d", n, errno);
+ return -1;
+ }
+ uri->port = n;
+ } else {
+ uri->port = -1;
+ }
+
+ /* Get the host. */
+ uri->host = mkstr(host_start, host_end);
+ if (percent_decode(uri->host) < 0) {
+ nsock_log_error("Invalid URL encoding in host: %s", uri->host);
+ free(uri->host);
+ uri->host = NULL;
+ return -1;
+ }
+
+ return 1;
+}
+
+static int parse_uri(const char *proxystr, const char *end, struct uri *uri) {
+ const char *p, *q;
+
+ /* Scheme, section 3.1. */
+ p = proxystr;
+ if (!isalpha(*p))
+ goto fail;
+
+ q = p;
+ while (isalpha(*q) || isdigit(*q) || *q == '+' || *q == '-' || *q == '.') {
+ q++;
+ if (q >= end)
+ goto fail;
+ }
+
+ if (*q != ':')
+ goto fail;
+
+ uri->scheme = mkstr(p, q);
+
+ /* "An implementation should accept uppercase letters as equivalent to
+ * lowercase in scheme names (e.g., allow "HTTP" as well as "http") for the
+ * sake of robustness..." */
+ lowercase(uri->scheme);
+
+ /* Authority, section 3.2. */
+ p = q + 1;
+ if (p >= end)
+ goto fail;
+ if (p + 1 < end && *p == '/' && *(p + 1) == '/') {
+
+ p += 2;
+ q = p;
+ while (q < end && !(*q == '/' || *q == '?' || *q == '#' || *q == '\0'))
+ q++;
+
+ if (uri_parse_authority(p, q, uri) < 0) {
+ goto fail;
+ }
+
+ p = q;
+ }
+
+ /* Path, section 3.3. We include the query and fragment in the path. The
+ * path is also not percent-decoded because we just pass it on to the origin
+ * server. */
+
+ uri->path = mkstr(p, end);
+
+ return 1;
+
+fail:
+ uri_free(uri);
+ return -1;
+}
+
+static struct proxy_node *proxy_node_new(const char *proxystr, const char *end) {
+ int i;
+
+ for (i = 0; ProxyBackends[i] != NULL; i++) {
+ const struct proxy_spec *pspec;
+ size_t prefix_len;
+
+ pspec = ProxyBackends[i];
+ prefix_len = strlen(pspec->prefix);
+ if (end - proxystr > prefix_len && strncasecmp(proxystr, pspec->prefix, prefix_len) == 0) {
+ struct proxy_node *proxy = NULL;
+ struct uri uri;
+
+ memset(&uri, 0x00, sizeof(struct uri));
+
+ if (parse_uri(proxystr, end, &uri) < 0)
+ break;
+
+ if (pspec->ops->node_new(&proxy, &uri) < 0) {
+ nsock_log_error("Cannot initialize proxy node %s", proxystr);
+ uri_free(&uri);
+ break;
+ }
+
+ uri_free(&uri);
+
+ return proxy;
+ }
+ }
+ nsock_log_error("Invalid protocol in proxy specification string: %s", proxystr);
+ return NULL;
+}
+
+void forward_event(nsock_pool nspool, nsock_event nsevent, void *udata) {
+ struct npool *nsp = (struct npool *)nspool;
+ struct nevent *nse = (struct nevent *)nsevent;
+ enum nse_type cached_type;
+ enum nse_status cached_status;
+
+ cached_type = nse->type;
+ cached_status = nse->status;
+
+ nse->type = nse->iod->px_ctx->target_ev_type;
+
+ if (nse->status != NSE_STATUS_SUCCESS)
+ nse->status = NSE_STATUS_PROXYERROR;
+
+ nsock_log_info("Forwarding event upstream: TCP connect %s (IOD #%li) EID %li",
+ nse_status2str(nse->status), nse->iod->id, nse->id);
+
+ nse->iod->px_ctx->target_handler(nsp, nse, udata);
+
+ nse->type = cached_type;
+ nse->status = cached_status;
+}
+
+void nsock_proxy_ev_dispatch(nsock_pool nspool, nsock_event nsevent, void *udata) {
+ struct nevent *nse = (struct nevent *)nsevent;
+
+ if (nse->status == NSE_STATUS_SUCCESS) {
+ struct proxy_node *current;
+
+ current = nse->iod->px_ctx->px_current;
+ assert(current);
+ current->spec->ops->handler(nspool, nsevent, udata);
+ } else {
+ forward_event(nspool, nsevent, udata);
+ }
+}
+
+int proxy_resolve(const char *host, struct sockaddr *addr, size_t *addrlen, int ai_family) {
+ struct addrinfo hints;
+ struct addrinfo *res;
+ int rc;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = ai_family;
+ /* All proxy types are TCP-only at the moment */
+ hints.ai_socktype = SOCK_STREAM;
+
+ rc = getaddrinfo(host, NULL, &hints, &res);
+ if (rc) {
+ nsock_log_info("getaddrinfo error: %s", gai_strerror(rc));
+ return -abs(rc);
+ }
+
+ *addr = *res->ai_addr;
+ *addrlen = res->ai_addrlen;
+ freeaddrinfo(res);
+ return 1;
+}
+
diff --git a/nsock/src/nsock_proxy.h b/nsock/src/nsock_proxy.h
new file mode 100644
index 0000000..57d8b12
--- /dev/null
+++ b/nsock/src/nsock_proxy.h
@@ -0,0 +1,176 @@
+/***************************************************************************
+ * nsock_proxy.h -- PRIVATE interface definitions for proxy handling. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifndef NSOCK_PROXY_H
+#define NSOCK_PROXY_H
+
+#include "gh_list.h"
+
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include <nsock.h>
+#include <errno.h>
+
+
+/* ------------------- CONSTANTS ------------------- */
+enum nsock_proxy_type {
+ PROXY_TYPE_HTTP = 0,
+ PROXY_TYPE_SOCKS4,
+ PROXY_TYPE_COUNT,
+};
+
+enum nsock_proxy_state {
+ /* Common initial state for all proxy types. */
+ PROXY_STATE_INITIAL,
+
+ /* HTTP proxy states. */
+ PROXY_STATE_HTTP_TCP_CONNECTED,
+ PROXY_STATE_HTTP_TUNNEL_ESTABLISHED,
+
+ /* SOCKS 4 proxy states. */
+ PROXY_STATE_SOCKS4_TCP_CONNECTED,
+ PROXY_STATE_SOCKS4_TUNNEL_ESTABLISHED,
+};
+
+
+/* ------------------- STRUCTURES ------------------- */
+
+struct uri {
+ char *scheme;
+ char *user;
+ char *pass;
+ char *host;
+ char *path;
+ int port;
+};
+
+/* Static information about a proxy node in the chain. This is generated by
+ * parsing the proxy specification string given by user. Those structures are
+ * then read-only and stored in the nsock_pool. */
+struct proxy_node {
+ const struct proxy_spec *spec;
+
+ struct sockaddr_storage ss;
+ size_t sslen;
+ unsigned short port;
+ char *nodestr; /* used for log messages */
+ gh_lnode_t nodeq;
+};
+
+/* Ordered list of proxy nodes, as specified in the proxy specification string. */
+struct proxy_chain {
+ gh_list_t nodes;
+};
+
+/* IOD-specific context. For each IOD we establish a tunnel through the chain of
+ * proxies. This structure stores all the related information. */
+struct proxy_chain_context {
+ const struct proxy_chain *px_chain;
+
+ /* Nodes iterator in px_chain->nodes */
+ struct proxy_node *px_current;
+
+ /* Current node connection state. */
+ enum nsock_proxy_state px_state;
+
+ /* Those fields are used to store information about the final target
+ * to reach. */
+ enum nse_type target_ev_type;
+ struct sockaddr_storage target_ss;
+ size_t target_sslen;
+ unsigned short target_port;
+ nsock_ev_handler target_handler;
+};
+
+struct proxy_op {
+ int (*node_new)(struct proxy_node **node, const struct uri *uri);
+ void (*node_delete)(struct proxy_node *node);
+ void (*handler)(nsock_pool nspool, nsock_event nsevent, void *udata);
+};
+
+struct proxy_spec {
+ const char *prefix;
+ enum nsock_proxy_type type;
+ const struct proxy_op *ops;
+};
+
+
+/* ------------------- UTIL FUNCTIONS ------------------- */
+int proxy_resolve(const char *host, struct sockaddr *addr, size_t *addrlen, int ai_family);
+
+static inline struct proxy_node *proxy_ctx_node_next(struct proxy_chain_context *ctx) {
+ gh_lnode_t *next;
+
+ assert(ctx);
+ assert(ctx->px_current);
+
+ next = gh_lnode_next(&ctx->px_current->nodeq);
+ if (!next)
+ return NULL;
+
+ return container_of(next, struct proxy_node, nodeq);
+}
+
+
+/* ------------------- PROTOTYPES ------------------- */
+
+struct proxy_chain_context *proxy_chain_context_new(nsock_pool nspool);
+void proxy_chain_context_delete(struct proxy_chain_context *ctx);
+
+void nsock_proxy_ev_dispatch(nsock_pool nspool, nsock_event nsevent, void *udata);
+void forward_event(nsock_pool nspool, nsock_event nse, void *udata);
+
+
+#endif /* NSOCK_PROXY_H */
+
diff --git a/nsock/src/nsock_read.c b/nsock/src/nsock_read.c
new file mode 100644
index 0000000..27f874f
--- /dev/null
+++ b/nsock/src/nsock_read.c
@@ -0,0 +1,130 @@
+/***************************************************************************
+ * nsock_read.c -- This contains the functions for requesting various read *
+ * events from the nsock parallel socket event library *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include "nsock_internal.h"
+#include "nsock_log.h"
+#include "netutils.h"
+
+
+/* Read up to nlines lines (terminated with \n, which of course includes \r\n),
+ * or until EOF, or until the timeout, whichever comes first. Note that
+ * NSE_STATUS_SUCCESS will be returned in the case of EOF or timeout if at least
+ * 1 char has been read. Also note that you may get more than 'nlines' back --
+ * we just stop once "at least" 'nlines' is read */
+nsock_event_id nsock_readlines(nsock_pool nsp, nsock_iod ms_iod,
+ nsock_ev_handler handler, int timeout_msecs,
+ void *userdata, int nlines) {
+ struct niod *nsi = (struct niod *)ms_iod;
+ struct npool *ms = (struct npool *)nsp;
+ struct nevent *nse;
+
+ nse = event_new(ms, NSE_TYPE_READ, nsi, timeout_msecs, handler, userdata);
+ assert(nse);
+
+ nsock_log_info("Read request for %d lines from IOD #%li [%s] EID %li",
+ nlines, nsi->id, get_peeraddr_string(nsi), nse->id);
+
+ nse->readinfo.read_type = NSOCK_READLINES;
+ nse->readinfo.num = nlines;
+
+ nsock_pool_add_event(ms, nse);
+
+ return nse->id;
+}
+
+/* Same as above, except it tries to read at least 'nbytes' instead of 'nlines'. */
+nsock_event_id nsock_readbytes(nsock_pool nsp, nsock_iod ms_iod,
+ nsock_ev_handler handler, int timeout_msecs,
+ void *userdata, int nbytes) {
+
+ struct niod *nsi = (struct niod *)ms_iod;
+ struct npool *ms = (struct npool *)nsp;
+ struct nevent *nse;
+
+ nse = event_new(ms, NSE_TYPE_READ, nsi, timeout_msecs, handler, userdata);
+ assert(nse);
+
+ nsock_log_info("Read request for %d bytes from IOD #%li [%s] EID %li",
+ nbytes, nsi->id, get_peeraddr_string(nsi), nse->id);
+
+ nse->readinfo.read_type = NSOCK_READBYTES;
+ nse->readinfo.num = nbytes;
+
+ nsock_pool_add_event(ms, nse);
+
+ return nse->id;
+}
+
+
+/* The simplest read function -- returns NSE_STATUS_SUCCESS when it
+ * reads anything, otherwise it returns timeout, eof, or error as appropriate */
+nsock_event_id nsock_read(nsock_pool nsp, nsock_iod ms_iod,
+ nsock_ev_handler handler, int timeout_msecs,
+ void *userdata) {
+ struct niod *nsi = (struct niod *)ms_iod;
+ struct npool *ms = (struct npool *)nsp;
+ struct nevent *nse;
+
+ nse = event_new(ms, NSE_TYPE_READ, nsi, timeout_msecs, handler, userdata);
+ assert(nse);
+
+ nsock_log_info("Read request from IOD #%li [%s] (timeout: %dms) EID %li",
+ nsi->id, get_peeraddr_string(nsi), timeout_msecs, nse->id);
+
+ nse->readinfo.read_type = NSOCK_READ;
+
+ nsock_pool_add_event(ms, nse);
+
+ return nse->id;
+}
+
diff --git a/nsock/src/nsock_ssl.c b/nsock/src/nsock_ssl.c
new file mode 100644
index 0000000..096ce72
--- /dev/null
+++ b/nsock/src/nsock_ssl.c
@@ -0,0 +1,278 @@
+/***************************************************************************
+ * nsock_ssl.c -- This contains functions that relate somewhat exclusively *
+ * to SSL (over TCP) support in nsock. Where SSL support is incidental, *
+ * it is often in other files where code can be more easily shared between *
+ * the SSL and NonSSL paths. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+
+#include "nsock.h"
+#include "nsock_internal.h"
+#include "nsock_log.h"
+#include "nsock_ssl.h"
+#include "netutils.h"
+
+#if HAVE_OPENSSL
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/provider.h>
+#endif
+
+/* Disallow anonymous ciphers (Diffie-Hellman key agreement), low bit-strength
+ * ciphers, export-crippled ciphers, and MD5. Prefer ciphers in decreasing order
+ * of key size. The cipher list is taken from the book Network Security with
+ * OpenSSL. To see exactly what ciphers are enabled, use the command
+ * openssl ciphers -v '...'
+ * where ... is the string below. */
+#define CIPHERS_SECURE "ALL:!aNULL:!eNULL:!LOW:!EXP:!RC4:!MD5:@STRENGTH"
+
+/* This list of ciphers is for speed and compatibility, not security. Any cipher
+ * is accepted, and the list is sorted by speed based on Brian Hatch's
+ * (bri@ifokr.org) tests on an Pentium 686 against the ciphers listed. */
+#define CIPHERS_FAST "RC4-SHA:RC4-MD5:NULL-SHA:EXP-DES-CBC-SHA:EXP-EDH-RSA-DES-CBC-SHA:EXP-RC4-MD5:NULL-MD5:EDH-RSA-DES-CBC-SHA:EXP-RC2-CBC-MD5:EDH-RSA-DES-CBC3-SHA:EXP-ADH-RC4-MD5:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:EXP-ADH-DES-CBC-SHA:ADH-AES256-SHA:ADH-DES-CBC-SHA:ADH-RC4-MD5:AES256-SHA:DES-CBC-SHA:DES-CBC3-SHA:ADH-DES-CBC3-SHA:AES128-SHA:ADH-AES128-SHA:eNULL:ALL"
+
+extern struct timeval nsock_tod;
+#define NSOCK_SSL_STATE_UNINITIALIZED -1
+#define NSOCK_SSL_STATE_INITIALIZED 1
+#define NSOCK_SSL_STATE_ATEXIT 0
+static int nsock_ssl_state = NSOCK_SSL_STATE_UNINITIALIZED;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined LIBRESSL_VERSION_NUMBER
+static void nsock_ssl_atexit(void)
+{
+ nsock_ssl_state = NSOCK_SSL_STATE_ATEXIT;
+}
+#endif
+void nsp_ssl_cleanup(struct npool *nsp)
+{
+ if (nsock_ssl_state != NSOCK_SSL_STATE_ATEXIT)
+ {
+ if (nsp->sslctx != NULL)
+ SSL_CTX_free(nsp->sslctx);
+#ifdef HAVE_DTLS_CLIENT_METHOD
+ if (nsp->dtlsctx != NULL)
+ SSL_CTX_free(nsp->dtlsctx);
+#endif
+ }
+ nsp->sslctx = NULL;
+#ifdef HAVE_DTLS_CLIENT_METHOD
+ nsp->dtlsctx = NULL;
+#endif
+}
+
+static SSL_CTX *ssl_init_helper(const SSL_METHOD *method) {
+ SSL_CTX *ctx;
+
+ if (nsock_ssl_state == NSOCK_SSL_STATE_UNINITIALIZED)
+ {
+ nsock_ssl_state = NSOCK_SSL_STATE_INITIALIZED;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined LIBRESSL_VERSION_NUMBER
+ SSL_load_error_strings();
+ SSL_library_init();
+#else
+ OPENSSL_atexit(nsock_ssl_atexit);
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (NULL == OSSL_PROVIDER_load(NULL, "legacy"))
+ {
+ nsock_log_info("OpenSSL legacy provider failed to load: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ }
+ if (NULL == OSSL_PROVIDER_load(NULL, "default"))
+ {
+ nsock_log_error("OpenSSL default provider failed to load: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ }
+#endif
+#endif
+ }
+
+ ctx = SSL_CTX_new(method);
+ if (!ctx) {
+ fatal("OpenSSL failed to create a new SSL_CTX: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ }
+
+ /* Our SSL* will always have the SSL_SESSION* inside it, so we neither need to
+ * use nor waste memory for the session cache. (Use '1' because '0' means
+ * 'infinite'.) */
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF|SSL_SESS_CACHE_NO_AUTO_CLEAR);
+ SSL_CTX_sess_set_cache_size(ctx, 1);
+ SSL_CTX_set_timeout(ctx, 3600); /* pretty unnecessary */
+
+ return ctx;
+}
+
+/* Create an SSL_CTX and do initialization that is common to all init modes. */
+static SSL_CTX *ssl_init_common() {
+ return ssl_init_helper(SSLv23_client_method());
+}
+
+/* Initializes an Nsock pool to create SSL connections. This sets an internal
+ * SSL_CTX, which is like a template that sets options for all connections that
+ * are made from it. The connections made from this context will use only secure
+ * ciphers but no server certificate verification is done. Returns the SSL_CTX
+ * so you can set your own options. */
+static nsock_ssl_ctx nsock_pool_ssl_init_helper(SSL_CTX *ctx, int flags) {
+ char rndbuf[128];
+
+ /* Get_random_bytes may or may not provide high-quality randomness. Add it to
+ * the entropy pool without increasing the entropy estimate (third argument of
+ * RAND_add is 0). We rely on OpenSSL's entropy gathering, called implicitly
+ * by RAND_status, to give us what we need, or else bail out if it fails. */
+ get_random_bytes(rndbuf, sizeof(rndbuf));
+ RAND_add(rndbuf, sizeof(rndbuf), 0);
+
+ if (!(flags & NSOCK_SSL_MAX_SPEED)) {
+ if (!RAND_status())
+ fatal("%s: Failed to seed OpenSSL PRNG"
+ " (RAND_status returned false).", __func__);
+ }
+
+ /* SSL_OP_ALL sets bug-compatibility for pretty much everything.
+ * SSL_OP_NO_SSLv2 disables the less-secure SSLv2 while allowing us to use the
+ * SSLv2-compatible SSLv23_client_method. */
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+ SSL_CTX_clear_options(ctx, SSL_OP_NO_SSLv2);
+ SSL_CTX_set_options(ctx, flags & NSOCK_SSL_MAX_SPEED ?
+ SSL_OP_ALL : SSL_OP_ALL|SSL_OP_NO_SSLv2);
+
+ if (!SSL_CTX_set_cipher_list(ctx, flags & NSOCK_SSL_MAX_SPEED ?
+ CIPHERS_FAST : CIPHERS_SECURE))
+ fatal("Unable to set OpenSSL cipher list: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+
+ return ctx;
+}
+
+nsock_ssl_ctx nsock_pool_ssl_init(nsock_pool ms_pool, int flags) {
+ struct npool *ms = (struct npool *)ms_pool;
+
+ if (ms->sslctx == NULL)
+ ms->sslctx = ssl_init_common();
+ return nsock_pool_ssl_init_helper(ms->sslctx, flags);
+}
+
+#ifdef HAVE_DTLS_CLIENT_METHOD
+
+/* Create an SSL_CTX and do initialisation, creating a DTLS client */
+static SSL_CTX *dtls_init_common() {
+ return ssl_init_helper(DTLS_client_method());
+}
+
+/* Initializes an Nsock pool to create DTLS connections. Very much similar to
+ * nsock_pool_ssl_init, just with DTLS. */
+nsock_ssl_ctx nsock_pool_dtls_init(nsock_pool ms_pool, int flags) {
+ SSL_CTX *dtls_ctx = NULL;
+ struct npool *ms = (struct npool *)ms_pool;
+
+ if (ms->dtlsctx == NULL)
+ ms->dtlsctx = dtls_init_common();
+ dtls_ctx = (SSL_CTX *) nsock_pool_ssl_init_helper(ms->dtlsctx, flags);
+
+ /* Don't add padding or the ClientHello will fragment and not connect properly. */
+ SSL_CTX_clear_options(dtls_ctx, SSL_OP_TLSEXT_PADDING);
+
+ if (!SSL_CTX_set_cipher_list(dtls_ctx, "DEFAULT"))
+ fatal("Unable to set OpenSSL cipher list: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+
+ return dtls_ctx;
+}
+
+#else /* OpenSSL Version does not support DTLS */
+
+nsock_ssl_ctx nsock_pool_dtls_init(nsock_pool ms_pool, int flags) {
+ fatal("%s called with no OpenSSL DTLS support", __func__);
+}
+
+#endif
+
+/* Check server certificate verification, after a connection is established. We
+ * check first that a certificate was even offered, then call
+ * SSL_get_verify_result to get the overall status of verification. (Just
+ * calling SSL_get_verify_result is not enough because that function returns
+ * X509_V_OK when 0 certificates are presented.) If the verification mode of the
+ * SSL object is SSL_VERIFY_NONE, or if OpenSSL is disabled, this function
+ * always returns true. */
+int nsi_ssl_post_connect_verify(const nsock_iod nsockiod) {
+ struct niod *iod = (struct niod *)nsockiod;
+
+ assert(iod->ssl != NULL);
+ if (SSL_get_verify_mode(iod->ssl) != SSL_VERIFY_NONE) {
+ X509 *cert;
+
+ cert = SSL_get_peer_certificate(iod->ssl);
+ if (cert == NULL)
+ /* No certificate presented. */
+ return 0;
+
+ X509_free(cert);
+
+ if (SSL_get_verify_result(iod->ssl) != X509_V_OK)
+ /* Something wrong with verification. */
+ return 0;
+ }
+ return 1;
+}
+
+#else /* NOT HAVE_OPENSSL */
+
+nsock_ssl_ctx nsock_pool_ssl_init(nsock_pool ms_pool, int flags) {
+ fatal("%s called with no OpenSSL support", __func__);
+}
+
+nsock_ssl_ctx nsock_pool_dtls_init(nsock_pool ms_pool, int flags) {
+ fatal("%s called with no OpenSSL support", __func__);
+}
+
+int nsi_ssl_post_connect_verify(const nsock_iod nsockiod) {
+ return 1;
+}
+
+#endif
diff --git a/nsock/src/nsock_ssl.h b/nsock/src/nsock_ssl.h
new file mode 100644
index 0000000..f23f615
--- /dev/null
+++ b/nsock/src/nsock_ssl.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+ * nsock_ssl.c -- This contains functions that relate somewhat exclusively *
+ * to SSL (over TCP) support in nsock. Where SSL support is incidental, *
+ * it is often in other files where code can be more easily shared between *
+ * the SSL and NonSSL paths. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#ifndef NSOCK_SSL_H
+#define NSOCK_SSL_H
+
+#ifdef HAVE_CONFIG_H
+#include "nsock_config.h"
+#endif
+#include "nsock_internal.h"
+
+#if HAVE_OPENSSL
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+/* Deprecated in OpenSSL 3.0 */
+#define SSL_get_peer_certificate SSL_get1_peer_certificate
+#endif
+
+struct sslinfo {
+ /* SSL_ERROR_NONE, SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_READ, or
+ * SSL_ERROR_WANT_WRITE */
+ int ssl_desire;
+};
+
+int nsi_ssl_post_connect_verify(const nsock_iod nsockiod);
+
+void nsp_ssl_cleanup(struct npool *nsp);
+#endif /* HAVE_OPENSSL */
+#endif /* NSOCK_SSL_H */
+
diff --git a/nsock/src/nsock_timers.c b/nsock/src/nsock_timers.c
new file mode 100644
index 0000000..c36fd0b
--- /dev/null
+++ b/nsock/src/nsock_timers.c
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * nsock_timers.c -- This contains the functions for requesting timers *
+ * from the nsock parallel socket event library *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include "nsock_internal.h"
+#include "nsock_log.h"
+
+extern struct timeval nsock_tod;
+
+/* Send back an NSE_TYPE_TIMER after the number of milliseconds specified. Of
+ * course it can also return due to error, cancellation, etc. */
+nsock_event_id nsock_timer_create(nsock_pool ms_pool, nsock_ev_handler handler,
+ int timeout_msecs, void *userdata) {
+ struct npool *nsp = (struct npool *)ms_pool;
+ struct nevent *nse;
+
+ nse = event_new(nsp, NSE_TYPE_TIMER, NULL, timeout_msecs, handler, userdata);
+ assert(nse);
+
+ nsock_log_info("Timer created - %dms from now. EID %li", timeout_msecs,
+ nse->id);
+
+ nsock_pool_add_event(nsp, nse);
+
+ return nse->id;
+}
+
diff --git a/nsock/src/nsock_write.c b/nsock/src/nsock_write.c
new file mode 100644
index 0000000..03b82b8
--- /dev/null
+++ b/nsock/src/nsock_write.c
@@ -0,0 +1,236 @@
+/***************************************************************************
+ * nsock_write.c -- This contains the functions relating to writing to *
+ * sockets using the nsock parallel socket event library *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include "nsock.h"
+#include "nsock_internal.h"
+#include "nsock_log.h"
+#include "netutils.h"
+
+#include <nbase.h>
+#include <stdarg.h>
+#include <errno.h>
+
+nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
+ void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port, const char *data, int datalen) {
+ struct npool *nsp = (struct npool *)ms_pool;
+ struct niod *nsi = (struct niod *)ms_iod;
+ struct nevent *nse;
+ char displaystr[256];
+ struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
+#if HAVE_IPV6
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)saddr;
+#endif
+
+ nse = event_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata);
+ assert(nse);
+
+ if (saddr->sa_family == AF_INET) {
+ sin->sin_port = htons(port);
+#if HAVE_SYS_UN_H
+ } else if (saddr->sa_family == AF_INET6) {
+#else
+ } else {
+#endif
+ assert(saddr->sa_family == AF_INET6);
+#if HAVE_IPV6
+ sin6->sin6_port = htons(port);
+#else
+ fatal("IPv6 address passed to %s call, but nsock was not compiled w/IPv6 support", __func__);
+#endif
+ }
+
+ assert(sslen <= sizeof(nse->writeinfo.dest));
+ memcpy(&nse->writeinfo.dest, saddr, sslen);
+ nse->writeinfo.destlen = sslen;
+
+ assert(sslen <= sizeof(nse->iod->peer));
+ memcpy(&nse->iod->peer, saddr, sslen);
+ nse->iod->peerlen = sslen;
+
+ if (datalen < 0)
+ datalen = (int) strlen(data);
+
+ if (NsockLogLevel == NSOCK_LOG_DBG_ALL && datalen < 80) {
+ memcpy(displaystr, ": ", 2);
+ memcpy(displaystr + 2, data, datalen);
+ displaystr[2 + datalen] = '\0';
+ replacenonprintable(displaystr + 2, datalen, '.');
+ } else {
+ displaystr[0] = '\0';
+ }
+ nsock_log_info("Sendto request for %d bytes to IOD #%li EID %li [%s]%s",
+ datalen, nsi->id, nse->id, get_peeraddr_string(nse->iod),
+ displaystr);
+
+ fs_cat(&nse->iobuf, data, datalen);
+
+ nsock_pool_add_event(nsp, nse);
+
+ return nse->id;
+}
+
+/* Write some data to the socket. If the write is not COMPLETED within
+ * timeout_msecs , NSE_STATUS_TIMEOUT will be returned. If you are supplying
+ * NUL-terminated data, you can optionally pass -1 for datalen and nsock_write
+ * will figure out the length itself */
+nsock_event_id nsock_write(nsock_pool ms_pool, nsock_iod ms_iod,
+ nsock_ev_handler handler, int timeout_msecs, void *userdata, const char *data, int datalen) {
+ struct npool *nsp = (struct npool *)ms_pool;
+ struct niod *nsi = (struct niod *)ms_iod;
+ struct nevent *nse;
+ char displaystr[256];
+
+ nse = event_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata);
+ assert(nse);
+
+ nse->writeinfo.dest.ss_family = AF_UNSPEC;
+
+ if (datalen < 0)
+ datalen = (int)strlen(data);
+
+ if (NsockLogLevel == NSOCK_LOG_DBG_ALL && datalen < 80) {
+ memcpy(displaystr, ": ", 2);
+ memcpy(displaystr + 2, data, datalen);
+ displaystr[2 + datalen] = '\0';
+ replacenonprintable(displaystr + 2, datalen, '.');
+ } else {
+ displaystr[0] = '\0';
+ }
+
+ nsock_log_info("Write request for %d bytes to IOD #%li EID %li [%s]%s",
+ datalen, nsi->id, nse->id, get_peeraddr_string(nsi),
+ displaystr);
+
+ fs_cat(&nse->iobuf, data, datalen);
+
+ nsock_pool_add_event(nsp, nse);
+
+ return nse->id;
+}
+
+/* Same as nsock_write except you can use a printf-style format and you can only use this for ASCII strings */
+nsock_event_id nsock_printf(nsock_pool ms_pool, nsock_iod ms_iod,
+ nsock_ev_handler handler, int timeout_msecs, void *userdata, char *format, ...) {
+ struct npool *nsp = (struct npool *)ms_pool;
+ struct niod *nsi = (struct niod *)ms_iod;
+ struct nevent *nse;
+ char buf[4096];
+ char *buf2 = NULL;
+ size_t buf2size;
+ int res, res2;
+ int strlength = 0;
+ char displaystr[256];
+
+ va_list ap;
+
+ nse = event_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata);
+ assert(nse);
+
+ va_start(ap,format);
+ res = Vsnprintf(buf, sizeof(buf), format, ap);
+ va_end(ap);
+
+ if (res >= 0) {
+ if (res >= sizeof(buf)) {
+ buf2size = res + 16;
+ buf2 = (char * )safe_malloc(buf2size);
+ va_start(ap,format);
+ res2 = Vsnprintf(buf2, buf2size, format, ap);
+ va_end(ap);
+ if (res2 < 0 || (size_t) res2 >= buf2size) {
+ free(buf2);
+ buf2 = NULL;
+ } else
+ strlength = res2;
+ } else {
+ buf2 = buf;
+ strlength = res;
+ }
+ }
+
+ if (!buf2) {
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_ERROR;
+ nse->errnum = EMSGSIZE;
+ } else {
+ if (strlength == 0) {
+ nse->event_done = 1;
+ nse->status = NSE_STATUS_SUCCESS;
+ } else {
+ fs_cat(&nse->iobuf, buf2, strlength);
+ }
+ }
+
+ if (NsockLogLevel == NSOCK_LOG_DBG_ALL &&
+ nse->status != NSE_STATUS_ERROR &&
+ strlength < 80) {
+ memcpy(displaystr, ": ", 2);
+ memcpy(displaystr + 2, buf2, strlength);
+ displaystr[2 + strlength] = '\0';
+ replacenonprintable(displaystr + 2, strlength, '.');
+ } else {
+ displaystr[0] = '\0';
+ }
+
+ nsock_log_info("Write request for %d bytes to IOD #%li EID %li [%s]%s",
+ strlength, nsi->id, nse->id, get_peeraddr_string(nsi),
+ displaystr);
+
+ if (buf2 != buf)
+ free(buf2);
+
+ nsock_pool_add_event(nsp, nse);
+
+ return nse->id;
+}
+
diff --git a/nsock/src/proxy_http.c b/nsock/src/proxy_http.c
new file mode 100644
index 0000000..a6831d4
--- /dev/null
+++ b/nsock/src/proxy_http.c
@@ -0,0 +1,210 @@
+/***************************************************************************
+ * proxy_http.c -- HTTP Connect proxying. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id $ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+
+#include "nsock.h"
+#include "nsock_internal.h"
+#include "nsock_log.h"
+#include <string.h>
+
+#define DEFAULT_PROXY_PORT_HTTP 8080
+
+
+extern struct timeval nsock_tod;
+extern const struct proxy_spec ProxySpecHttp;
+
+
+static int proxy_http_node_new(struct proxy_node **node, const struct uri *uri) {
+ int rc;
+ struct proxy_node *proxy;
+
+ proxy = (struct proxy_node *)safe_zalloc(sizeof(struct proxy_node));
+ proxy->spec = &ProxySpecHttp;
+
+ rc = proxy_resolve(uri->host, (struct sockaddr *)&proxy->ss, &proxy->sslen, AF_UNSPEC);
+ if (rc < 0) {
+ free(proxy);
+ *node = NULL;
+ return -1;
+ }
+
+ if (uri->port == -1)
+ proxy->port = DEFAULT_PROXY_PORT_HTTP;
+ else
+ proxy->port = (unsigned short)uri->port;
+
+ rc = asprintf(&proxy->nodestr, "http://%s:%d", uri->host, proxy->port);
+ if (rc < 0) {
+ /* asprintf() failed for some reason but this is not a disaster (yet).
+ * Set nodestr to NULL and try to keep on going. */
+ proxy->nodestr = NULL;
+ }
+
+ *node = proxy;
+
+ return 1;
+}
+
+static void proxy_http_node_delete(struct proxy_node *node) {
+ if (!node)
+ return;
+
+ free(node->nodestr);
+
+ free(node);
+}
+
+static int handle_state_initial(struct npool *nsp, struct nevent *nse, void *udata) {
+ struct proxy_chain_context *px_ctx = nse->iod->px_ctx;
+ struct sockaddr_storage *ss;
+ size_t sslen;
+ unsigned short port;
+ struct proxy_node *next;
+ int timeout;
+
+ px_ctx->px_state = PROXY_STATE_HTTP_TCP_CONNECTED;
+
+ next = proxy_ctx_node_next(px_ctx);
+ if (next) {
+ ss = &next->ss;
+ sslen = next->sslen;
+ port = next->port;
+ } else {
+ ss = &px_ctx->target_ss;
+ sslen = px_ctx->target_sslen;
+ port = px_ctx->target_port;
+ }
+
+ timeout = TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod);
+
+ nsock_printf(nsp, (nsock_iod)nse->iod, nsock_proxy_ev_dispatch,
+ timeout, udata, "CONNECT %s:%d HTTP/1.1\r\n\r\n",
+ inet_ntop_ez(ss, sslen), (int)port);
+
+ nsock_readlines(nsp, (nsock_iod)nse->iod, nsock_proxy_ev_dispatch,
+ timeout, udata, 1);
+
+ return 0;
+}
+
+static int handle_state_tcp_connected(struct npool *nsp, struct nevent *nse, void *udata) {
+ struct proxy_chain_context *px_ctx = nse->iod->px_ctx;
+ char *res;
+ int reslen;
+
+ res = nse_readbuf(nse, &reslen);
+
+ /* TODO string check!! */
+ if (!((reslen >= 15) && strstr(res, "200 OK"))) {
+ struct proxy_node *node = px_ctx->px_current;
+
+ nsock_log_debug("Connection refused from proxy %s", node->nodestr);
+ return -EINVAL;
+ }
+
+ px_ctx->px_state = PROXY_STATE_HTTP_TUNNEL_ESTABLISHED;
+
+ if (proxy_ctx_node_next(px_ctx) == NULL) {
+ forward_event(nsp, nse, udata);
+ } else {
+ px_ctx->px_current = proxy_ctx_node_next(px_ctx);
+ px_ctx->px_state = PROXY_STATE_INITIAL;
+ nsock_proxy_ev_dispatch(nsp, nse, udata);
+ }
+ return 0;
+}
+
+static void proxy_http_handler(nsock_pool nspool, nsock_event nsevent, void *udata) {
+ int rc = 0;
+ struct npool *nsp = (struct npool *)nspool;
+ struct nevent *nse = (struct nevent *)nsevent;
+
+ switch (nse->iod->px_ctx->px_state) {
+ case PROXY_STATE_INITIAL:
+ rc = handle_state_initial(nsp, nse, udata);
+ break;
+
+ case PROXY_STATE_HTTP_TCP_CONNECTED:
+ if (nse->type == NSE_TYPE_READ)
+ rc = handle_state_tcp_connected(nsp, nse, udata);
+ break;
+
+ case PROXY_STATE_HTTP_TUNNEL_ESTABLISHED:
+ forward_event(nsp, nse, udata);
+ break;
+
+ default:
+ fatal("Invalid proxy state!");
+ }
+
+ if (rc) {
+ nse->status = NSE_STATUS_PROXYERROR;
+ forward_event(nsp, nse, udata);
+ }
+}
+
+
+/* ---- PROXY DEFINITION ---- */
+static const struct proxy_op ProxyOpsHttp = {
+ proxy_http_node_new,
+ proxy_http_node_delete,
+ proxy_http_handler,
+};
+
+const struct proxy_spec ProxySpecHttp = {
+ "http://",
+ PROXY_TYPE_HTTP,
+ &ProxyOpsHttp,
+};
+
diff --git a/nsock/src/proxy_socks4.c b/nsock/src/proxy_socks4.c
new file mode 100644
index 0000000..c88ca38
--- /dev/null
+++ b/nsock/src/proxy_socks4.c
@@ -0,0 +1,241 @@
+/***************************************************************************
+ * proxy_socks4.c -- SOCKS4 proxying. *
+ * *
+ ***********************IMPORTANT NSOCK LICENSE TERMS***********************
+ *
+ * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC
+ * This library is free software; you may redistribute and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; Version 2. This guarantees your right to use, modify, and
+ * redistribute this software under certain conditions. If this license is
+ * unacceptable to you, Nmap Software LLC may be willing to sell alternative
+ * licenses (contact sales@nmap.com ).
+ *
+ * As a special exception to the GPL terms, Nmap Software LLC grants permission
+ * to link the code of this program with any version of the OpenSSL library
+ * which is distributed under a license identical to that listed in the included
+ * docs/licenses/OpenSSL.txt file, and distribute linked combinations including
+ * the two. You must obey the GNU GPL in all respects for all of the code used
+ * other than OpenSSL. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so.
+ *
+ * If you received these files with a written license agreement stating terms
+ * other than the (GPL) terms above, then that alternative license agreement
+ * takes precedence over this comment.
+ *
+ * Source is provided to this software because we believe users have a right to
+ * know exactly what a program is going to do before they run it. This also
+ * allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to send your changes to the
+ * dev@nmap.org mailing list for possible incorporation into the main
+ * distribution. By sending these changes to Fyodor or one of the Insecure.Org
+ * development mailing lists, or checking them into the Nmap source code
+ * repository, it is understood (unless you specify otherwise) that you are
+ * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive
+ * right to reuse, modify, and relicense the code. Nmap will always be available
+ * Open Source, but this is important because the inability to relicense code
+ * has caused devastating problems for other Free Software projects (such as KDE
+ * and NASM). We also occasionally relicense the code to third parties as
+ * discussed above. If you wish to specify special license conditions of your
+ * contributions, just say so when you send them.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more
+ * details (http://www.gnu.org/licenses/gpl-2.0.html).
+ *
+ ***************************************************************************/
+
+/* $Id $ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+
+#include "nsock.h"
+#include "nsock_internal.h"
+#include "nsock_log.h"
+
+#include <string.h>
+
+#define DEFAULT_PROXY_PORT_SOCKS4 1080
+
+
+extern struct timeval nsock_tod;
+extern const struct proxy_spec ProxySpecSocks4;
+
+
+struct socks4_data {
+ uint8_t version;
+ uint8_t type;
+ uint16_t port;
+ uint32_t address;
+ uint8_t null;
+} __attribute__((packed));
+
+
+static int proxy_socks4_node_new(struct proxy_node **node, const struct uri *uri) {
+ int rc;
+ struct proxy_node *proxy;
+
+ proxy = (struct proxy_node *)safe_zalloc(sizeof(struct proxy_node));
+ proxy->spec = &ProxySpecSocks4;
+
+ rc = proxy_resolve(uri->host, (struct sockaddr *)&proxy->ss, &proxy->sslen, AF_INET);
+ if (rc < 0)
+ goto err_out;
+
+ if (proxy->ss.ss_family != AF_INET) {
+ rc = -1;
+ goto err_out;
+ }
+
+ if (uri->port == -1)
+ proxy->port = DEFAULT_PROXY_PORT_SOCKS4;
+ else
+ proxy->port = (unsigned short)uri->port;
+
+ rc = asprintf(&proxy->nodestr, "socks4://%s:%d", uri->host, proxy->port);
+ if (rc < 0) {
+ /* asprintf() failed for some reason but this is not a disaster (yet).
+ * Set nodestr to NULL and try to keep on going. */
+ proxy->nodestr = NULL;
+ }
+
+ rc = 1;
+
+err_out:
+ if (rc < 0) {
+ free(proxy);
+ proxy = NULL;
+ }
+ *node = proxy;
+ return rc;
+}
+
+static void proxy_socks4_node_delete(struct proxy_node *node) {
+ if (!node)
+ return;
+
+ free(node->nodestr);
+
+ free(node);
+}
+
+static inline void socks4_data_init(struct socks4_data *socks4,
+ struct sockaddr_storage *ss, size_t sslen,
+ unsigned short port) {
+ struct sockaddr_in *sin = (struct sockaddr_in *)ss;
+
+ memset(socks4, 0x00, sizeof(struct socks4_data));
+ socks4->version = 4;
+ socks4->type = 1;
+ socks4->port = htons(port);
+ assert(ss->ss_family == AF_INET);
+ socks4->address = sin->sin_addr.s_addr;
+}
+
+static int handle_state_initial(struct npool *nsp, struct nevent *nse, void *udata) {
+ struct proxy_chain_context *px_ctx = nse->iod->px_ctx;
+ struct sockaddr_storage *ss;
+ size_t sslen;
+ unsigned short port;
+ struct proxy_node *next;
+ struct socks4_data socks4;
+ int timeout;
+
+ px_ctx->px_state = PROXY_STATE_SOCKS4_TCP_CONNECTED;
+
+ next = proxy_ctx_node_next(px_ctx);
+ if (next) {
+ ss = &next->ss;
+ sslen = next->sslen;
+ port = next->port;
+ } else {
+ ss = &px_ctx->target_ss;
+ sslen = px_ctx->target_sslen;
+ port = px_ctx->target_port;
+ }
+
+ socks4_data_init(&socks4, ss, sslen, port);
+
+ timeout = TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod);
+
+ nsock_write(nsp, (nsock_iod)nse->iod, nsock_proxy_ev_dispatch, timeout, udata,
+ (char *)&socks4, sizeof(socks4));
+
+ nsock_readbytes(nsp, (nsock_iod)nse->iod, nsock_proxy_ev_dispatch, timeout,
+ udata, 8);
+ return 0;
+}
+
+static int handle_state_tcp_connected(struct npool *nsp, struct nevent *nse, void *udata) {
+ struct proxy_chain_context *px_ctx = nse->iod->px_ctx;
+ char *res;
+ int reslen;
+
+ res = nse_readbuf(nse, &reslen);
+
+ if (!(reslen == 8 && res[1] == 90)) {
+ struct proxy_node *node = px_ctx->px_current;
+
+ nsock_log_debug("Ignoring invalid socks4 reply from proxy %s",
+ node->nodestr);
+ return -EINVAL;
+ }
+
+ px_ctx->px_state = PROXY_STATE_SOCKS4_TUNNEL_ESTABLISHED;
+
+ if (proxy_ctx_node_next(px_ctx) == NULL) {
+ forward_event(nsp, nse, udata);
+ } else {
+ px_ctx->px_current = proxy_ctx_node_next(px_ctx);
+ px_ctx->px_state = PROXY_STATE_INITIAL;
+ nsock_proxy_ev_dispatch(nsp, nse, udata);
+ }
+ return 0;
+}
+
+static void proxy_socks4_handler(nsock_pool nspool, nsock_event nsevent, void *udata) {
+ int rc = 0;
+ struct npool *nsp = (struct npool *)nspool;
+ struct nevent *nse = (struct nevent *)nsevent;
+
+ switch (nse->iod->px_ctx->px_state) {
+ case PROXY_STATE_INITIAL:
+ rc = handle_state_initial(nsp, nse, udata);
+ break;
+
+ case PROXY_STATE_SOCKS4_TCP_CONNECTED:
+ if (nse->type == NSE_TYPE_READ)
+ rc = handle_state_tcp_connected(nsp, nse, udata);
+ break;
+
+ case PROXY_STATE_SOCKS4_TUNNEL_ESTABLISHED:
+ forward_event(nsp, nse, udata);
+ break;
+
+ default:
+ fatal("Invalid proxy state!");
+ }
+
+ if (rc) {
+ nse->status = NSE_STATUS_PROXYERROR;
+ forward_event(nsp, nse, udata);
+ }
+}
+
+/* ---- PROXY DEFINITION ---- */
+static const struct proxy_op ProxyOpsSocks4 = {
+ proxy_socks4_node_new,
+ proxy_socks4_node_delete,
+ proxy_socks4_handler,
+};
+
+const struct proxy_spec ProxySpecSocks4 = {
+ "socks4://",
+ PROXY_TYPE_SOCKS4,
+ &ProxyOpsSocks4,
+};
+
diff --git a/nsock/tests/Makefile.in b/nsock/tests/Makefile.in
new file mode 100644
index 0000000..6fa8342
--- /dev/null
+++ b/nsock/tests/Makefile.in
@@ -0,0 +1,43 @@
+#
+# nsock regression test suite
+# Same license as nmap -- see https://nmap.org/book/man-legal.html
+##
+
+NBASEDIR=@NBASEDIR@
+NSOCKLIB=../src/libnsock.a
+NBASELIB=$(NBASEDIR)/libnbase.a
+
+CC = @CC@
+CPPFLAGS = @CPPFLAGS@ -I../include
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @OPENSSL_LIBS@ @LIBPCAP_LIBS@ @LIBS@
+
+SRC = tests_main.c \
+ basic.c \
+ timer.c \
+ logs.c \
+ connect.c \
+ ghlists.c \
+ ghheaps.c \
+ proxychain.c \
+ cancel.c
+
+OBJ = $(SRC:.c=.o)
+
+EXE = tests_main
+
+all: $(SRC) $(EXE)
+
+$(EXE): $(OBJ)
+ $(CC) $(LDFLAGS) $(OBJ) -o $@ $(NSOCKLIB) $(NBASELIB) $(LIBS)
+
+.c.o:
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
+
+clean:
+ $(RM) $(OBJ) $(EXE)
+
+rebuild: clean $(EXE)
+
+.PHONY: clean rebuild
diff --git a/nsock/tests/README b/nsock/tests/README
new file mode 100644
index 0000000..a95cc1c
--- /dev/null
+++ b/nsock/tests/README
@@ -0,0 +1,5 @@
+Minimal regression test suite for nsock.
+
+Usage:
+ $ make
+ $ sh ./run_tests.sh
diff --git a/nsock/tests/basic.c b/nsock/tests/basic.c
new file mode 100644
index 0000000..9d8a12c
--- /dev/null
+++ b/nsock/tests/basic.c
@@ -0,0 +1,52 @@
+/*
+ * Nsock regression test suite
+ * Same license as nmap -- see https://nmap.org/book/man-legal.html
+ */
+
+#include "test-common.h"
+
+
+struct basic_test_data {
+ nsock_pool nsp;
+};
+
+static int basic_setup(void **tdata) {
+ struct basic_test_data *btd;
+
+ btd = calloc(1, sizeof(struct basic_test_data));
+ if (btd == NULL)
+ return -ENOMEM;
+
+ btd->nsp = nsock_pool_new(NULL);
+
+ *tdata = btd;
+ return 0;
+}
+
+static int basic_teardown(void *tdata) {
+ struct basic_test_data *btd = (struct basic_test_data *)tdata;
+
+ if (tdata) {
+ nsock_pool_delete(btd->nsp);
+ free(tdata);
+ }
+ return 0;
+}
+
+static int basic_udata(void *tdata) {
+ struct basic_test_data *btd = (struct basic_test_data *)tdata;
+
+ AssertEqual(nsock_pool_get_udata(btd->nsp), NULL);
+ nsock_pool_set_udata(btd->nsp, btd);
+ AssertEqual(nsock_pool_get_udata(btd->nsp), btd);
+ return 0;
+}
+
+
+
+const struct test_case TestPoolUserData = {
+ .t_name = "nsock pool user data",
+ .t_setup = basic_setup,
+ .t_run = basic_udata,
+ .t_teardown = basic_teardown
+};
diff --git a/nsock/tests/cancel.c b/nsock/tests/cancel.c
new file mode 100644
index 0000000..49f98bf
--- /dev/null
+++ b/nsock/tests/cancel.c
@@ -0,0 +1,134 @@
+/*
+ * Nsock regression test suite
+ * Same license as nmap -- see https://nmap.org/book/man-legal.html
+ */
+
+#include "test-common.h"
+
+
+struct basic_test_data {
+ nsock_pool nsp;
+};
+
+
+static void cancel_handler(nsock_pool nsp, nsock_event nse, void *udata) {
+ int *ev_done = (int *)udata;
+
+ if (nse_status(nse) == NSE_STATUS_CANCELLED)
+ *ev_done = 1;
+}
+
+static int cancel_setup(void **tdata) {
+ struct basic_test_data *btd;
+
+ btd = calloc(1, sizeof(struct basic_test_data));
+ if (btd == NULL)
+ return -ENOMEM;
+
+ btd->nsp = nsock_pool_new(NULL);
+
+ *tdata = btd;
+ return 0;
+}
+
+static int cancel_teardown(void *tdata) {
+ struct basic_test_data *btd = (struct basic_test_data *)tdata;
+
+ if (tdata) {
+ nsock_pool_delete(btd->nsp);
+ free(tdata);
+ }
+ return 0;
+}
+
+static int cancel_tcp_run(void *tdata) {
+ struct basic_test_data *btd = (struct basic_test_data *)tdata;
+ struct sockaddr_in peer;
+ nsock_iod iod;
+ nsock_event_id id;
+ int done = 0;
+
+ iod = nsock_iod_new(btd->nsp, NULL);
+ AssertNonNull(iod);
+
+ memset(&peer, 0, sizeof(peer));
+ peer.sin_family = AF_INET;
+ inet_aton("127.0.0.1", &peer.sin_addr);
+
+ id = nsock_connect_tcp(btd->nsp, iod, cancel_handler, 4000, (void *)&done,
+ (struct sockaddr *)&peer, sizeof(peer), PORT_TCP);
+ nsock_event_cancel(btd->nsp, id, 1);
+
+ nsock_iod_delete(iod, NSOCK_PENDING_SILENT);
+
+ return (done == 1) ? 0 : -ENOEXEC;
+}
+
+static int cancel_udp_run(void *tdata) {
+ struct basic_test_data *btd = (struct basic_test_data *)tdata;
+ struct sockaddr_in peer;
+ nsock_iod iod;
+ nsock_event_id id;
+ int done = 0;
+
+ iod = nsock_iod_new(btd->nsp, NULL);
+ AssertNonNull(iod);
+
+ memset(&peer, 0, sizeof(peer));
+ peer.sin_family = AF_INET;
+ inet_aton("127.0.0.1", &peer.sin_addr);
+
+ id = nsock_connect_udp(btd->nsp, iod, cancel_handler, (void *)&done,
+ (struct sockaddr *)&peer, sizeof(peer), PORT_UDP);
+ nsock_event_cancel(btd->nsp, id, 1);
+
+ nsock_iod_delete(iod, NSOCK_PENDING_SILENT);
+
+ return (done == 1) ? 0 : -ENOEXEC;
+}
+
+static int cancel_ssl_run(void *tdata) {
+ struct basic_test_data *btd = (struct basic_test_data *)tdata;
+ struct sockaddr_in peer;
+ nsock_iod iod;
+ nsock_event_id id;
+ int done = 0;
+
+ iod = nsock_iod_new(btd->nsp, NULL);
+ AssertNonNull(iod);
+
+ memset(&peer, 0, sizeof(peer));
+ peer.sin_family = AF_INET;
+ inet_aton("127.0.0.1", &peer.sin_addr);
+
+ id = nsock_connect_ssl(btd->nsp, iod, cancel_handler, 4000, (void *)&done,
+ (struct sockaddr *)&peer, sizeof(peer), IPPROTO_TCP,
+ PORT_TCPSSL, NULL);
+ nsock_event_cancel(btd->nsp, id, 1);
+
+ nsock_iod_delete(iod, NSOCK_PENDING_SILENT);
+
+ return (done == 1) ? 0 : -ENOEXEC;
+}
+
+
+const struct test_case TestCancelTCP = {
+ .t_name = "schedule and cancel TCP connect",
+ .t_setup = cancel_setup,
+ .t_run = cancel_tcp_run,
+ .t_teardown = cancel_teardown
+};
+
+const struct test_case TestCancelUDP = {
+ .t_name = "schedule and cancel UDP pseudo-connect",
+ .t_setup = cancel_setup,
+ .t_run = cancel_udp_run,
+ .t_teardown = cancel_teardown
+};
+
+const struct test_case TestCancelSSL = {
+ .t_name = "schedule and cancel SSL connect",
+ .t_setup = cancel_setup,
+ .t_run = cancel_ssl_run,
+ .t_teardown = cancel_teardown
+};
diff --git a/nsock/tests/connect.c b/nsock/tests/connect.c
new file mode 100644
index 0000000..736b082
--- /dev/null
+++ b/nsock/tests/connect.c
@@ -0,0 +1,113 @@
+/*
+ * Nsock regression test suite
+ * Same license as nmap -- see https://nmap.org/book/man-legal.html
+ */
+
+#include "test-common.h"
+
+
+struct connect_test_data {
+ nsock_pool nsp;
+ nsock_iod nsi;
+ int connect_result;
+};
+
+
+static void connect_handler(nsock_pool nsp, nsock_event nse, void *udata) {
+ struct connect_test_data *ctd;
+
+ ctd = (struct connect_test_data *)nsock_pool_get_udata(nsp);
+
+ switch(nse_status(nse)) {
+ case NSE_STATUS_SUCCESS:
+ ctd->connect_result = 0;
+ break;
+
+ case NSE_STATUS_ERROR:
+ ctd->connect_result = -(nse_errorcode(nse));
+ break;
+
+ case NSE_STATUS_TIMEOUT:
+ ctd->connect_result = -ETIMEDOUT;
+ break;
+
+ default:
+ ctd->connect_result = -EINVAL;
+ break;
+ }
+}
+
+static int connect_setup(void **tdata) {
+ struct connect_test_data *ctd;
+
+ ctd = calloc(1, sizeof(struct connect_test_data));
+ if (ctd == NULL)
+ return -ENOMEM;
+
+ ctd->nsp = nsock_pool_new(ctd);
+ AssertNonNull(ctd->nsp);
+
+ ctd->nsi = nsock_iod_new(ctd->nsp, NULL);
+ AssertNonNull(ctd->nsi);
+
+ *tdata = ctd;
+ return 0;
+}
+
+static int connect_teardown(void *tdata) {
+ struct connect_test_data *ctd = (struct connect_test_data *)tdata;
+
+ if (tdata) {
+ nsock_iod_delete(ctd->nsi, NSOCK_PENDING_SILENT); /* nsock_pool_delete would also handle it */
+ nsock_pool_delete(ctd->nsp);
+ free(tdata);
+ }
+ return 0;
+}
+
+static int connect_tcp(void *tdata) {
+ struct connect_test_data *ctd = (struct connect_test_data *)tdata;
+ struct sockaddr_in peer;
+
+ memset(&peer, 0, sizeof(peer));
+ peer.sin_family = AF_INET;
+ inet_aton("127.0.0.1", &peer.sin_addr);
+
+ nsock_connect_tcp(ctd->nsp, ctd->nsi, connect_handler, 4000, NULL,
+ (struct sockaddr *)&peer, sizeof(peer), PORT_TCP);
+
+ nsock_loop(ctd->nsp, 4000);
+ return ctd->connect_result;
+}
+
+static int connect_tcp_failure(void *tdata) {
+ struct connect_test_data *ctd = (struct connect_test_data *)tdata;
+ struct sockaddr_in peer;
+
+ memset(&peer, 0, sizeof(peer));
+ peer.sin_family = AF_INET;
+ inet_aton("127.0.0.1", &peer.sin_addr);
+
+ /* pass in addrlen == 0 to force connect(2) to fail */
+ nsock_connect_tcp(ctd->nsp, ctd->nsi, connect_handler, 4000, NULL,
+ (struct sockaddr *)&peer, 0, PORT_TCP);
+
+ nsock_loop(ctd->nsp, 4000);
+ AssertEqual(ctd->connect_result, -EINVAL);
+ return 0;
+}
+
+
+const struct test_case TestConnectTCP = {
+ .t_name = "simple tcp connection",
+ .t_setup = connect_setup,
+ .t_run = connect_tcp,
+ .t_teardown = connect_teardown
+};
+
+const struct test_case TestConnectFailure = {
+ .t_name = "tcp connection failure case",
+ .t_setup = connect_setup,
+ .t_run = connect_tcp_failure,
+ .t_teardown = connect_teardown
+};
diff --git a/nsock/tests/ghheaps.c b/nsock/tests/ghheaps.c
new file mode 100644
index 0000000..0d4d2cb
--- /dev/null
+++ b/nsock/tests/ghheaps.c
@@ -0,0 +1,151 @@
+/*
+ * Nsock regression test suite
+ * Same license as nmap -- see https://nmap.org/book/man-legal.html
+ */
+
+#include "test-common.h"
+#include "../src/gh_heap.h"
+#include <stdint.h>
+#include <time.h>
+
+
+#define HEAP_COUNT 3
+
+struct testitem {
+ int val;
+ gh_hnode_t node;
+};
+
+static int hnode_int_cmp(gh_hnode_t *n1, gh_hnode_t *n2) {
+ struct testitem *a;
+ struct testitem *b;
+
+ a = container_of(n1, struct testitem, node);
+ b = container_of(n2, struct testitem, node);
+
+ return (a->val < b->val);
+}
+
+static gh_hnode_t *mknode(int val) {
+ struct testitem *item;
+
+ item = calloc(1, sizeof(struct testitem));
+ assert(item != NULL);
+ item->val = val;
+ gh_hnode_invalidate(&item->node);
+ return &item->node;
+}
+
+static int node2int(gh_hnode_t *hnode) {
+ struct testitem *item;
+
+ item = container_of(hnode, struct testitem, node);
+ return item->val;
+}
+
+static int ghheap_ordering(void *tdata) {
+ gh_heap_t heap;
+ int i, n, k;
+
+ gh_heap_init(&heap, hnode_int_cmp);
+
+ for (i = 25000; i < 50000; i++)
+ gh_heap_push(&heap, mknode(i));
+
+ for (i = 24999; i >= 0; i--)
+ gh_heap_push(&heap, mknode(i));
+
+ for (i = 25000; i < 50000; i++)
+ gh_heap_push(&heap, mknode(i));
+
+ n = -1;
+ do {
+ gh_hnode_t *current;
+
+ current = gh_heap_pop(&heap);
+ assert(!gh_hnode_is_valid(current));
+ k = node2int(current);
+
+ if (k < n)
+ return -EINVAL;
+
+ n = k;
+ free(container_of(current, struct testitem, node));
+ } while (gh_heap_count(&heap) > 0);
+
+ gh_heap_free(&heap);
+ return 0;
+}
+
+static int ghheap_stress(void *tdata) {
+ gh_heap_t heaps[HEAP_COUNT];
+ int i, num;
+
+ for (i = 0; i < HEAP_COUNT; i++)
+ gh_heap_init(&heaps[i], hnode_int_cmp);
+
+ for (num = 25000; num < 50000; num++) {
+ for (i = 0; i < HEAP_COUNT; i++) {
+ gh_heap_push(&heaps[i], mknode(num));
+ }
+ }
+
+ for (num = 24999; num >= 0; num--) {
+ for (i = 0; i < HEAP_COUNT; i++) {
+ gh_heap_push(&heaps[i], mknode(num));
+ }
+ }
+
+ for (num = 0; num < 50000; num++) {
+ for (i = 0; i < HEAP_COUNT; i++) {
+ int r_min, r_pop;
+ gh_hnode_t *hnode;
+
+ r_min = node2int(gh_heap_min(&heaps[i]));
+ hnode = gh_heap_pop(&heaps[i]);
+ r_pop = node2int(hnode);
+
+ if (r_min != r_pop) {
+ fprintf(stderr, "Bogus min/pop return values (%d != %d)\n", r_min, r_pop);
+ return -EINVAL;
+ }
+
+ if (r_min != num) {
+ fprintf(stderr, "Bogus return value %d when expected %d\n", r_min, num);
+ return -EINVAL;
+ }
+
+ free(container_of(hnode, struct testitem, node));
+ }
+ }
+
+ for (i = 0; i < HEAP_COUNT; i++) {
+ void *ret;
+
+ ret = gh_heap_pop(&heaps[i]);
+ if (ret != NULL) {
+ fprintf(stderr, "Ret is bogus for heap %d\n", i);
+ return -EINVAL;
+ }
+ }
+
+ for (i = 0; i < HEAP_COUNT; i++)
+ gh_heap_free(&heaps[i]);
+
+ return 0;
+}
+
+
+const struct test_case TestGHHeaps = {
+ .t_name = "test nsock internal ghheaps",
+ .t_setup = NULL,
+ .t_run = ghheap_stress,
+ .t_teardown = NULL
+};
+
+const struct test_case TestHeapOrdering = {
+ .t_name = "test heaps conditions",
+ .t_setup = NULL,
+ .t_run = ghheap_ordering,
+ .t_teardown = NULL
+};
diff --git a/nsock/tests/ghlists.c b/nsock/tests/ghlists.c
new file mode 100644
index 0000000..f445022
--- /dev/null
+++ b/nsock/tests/ghlists.c
@@ -0,0 +1,189 @@
+/*
+ * Nsock regression test suite
+ * Same license as nmap -- see https://nmap.org/book/man-legal.html
+ */
+
+#include "test-common.h"
+/* Additional checks enabled */
+#define GH_LIST_PARANOID 1
+#include "../src/gh_list.h"
+/* For container_of */
+#include "../src/gh_heap.h"
+#include <stdint.h>
+#include <time.h>
+
+
+#define LIST_COUNT 16
+#define ELT_COUNT 2000
+
+
+struct testlist {
+ unsigned int val;
+ gh_lnode_t lnode;
+};
+
+static unsigned int nodeval(gh_lnode_t *lnode) {
+ struct testlist *tl;
+
+ tl = container_of(lnode, struct testlist, lnode);
+ return tl->val;
+}
+
+static gh_lnode_t *mknode(unsigned int val) {
+ struct testlist *tl;
+
+ tl = calloc(1, sizeof(struct testlist));
+ tl->val = val;
+ return &tl->lnode;
+}
+
+static void delnode(gh_lnode_t *lnode) {
+ if (lnode)
+ free(container_of(lnode, struct testlist, lnode));
+}
+
+static int ghlist_stress(void *tdata) {
+ gh_list_t lists[LIST_COUNT];
+ gh_lnode_t *current, *next;
+ int num = 0;
+ int ret;
+ int i;
+
+ for (i = 0; i < LIST_COUNT; i++)
+ gh_list_init(&lists[i]);
+
+ for (num = ELT_COUNT/2; num < ELT_COUNT; num++) {
+ for (i = 0; i < LIST_COUNT; i++) {
+ gh_list_append(&lists[i], mknode(num));
+ }
+ }
+
+ for (num = (ELT_COUNT/2 - 1); num >= 0; num--) {
+ for (i = 0; i < LIST_COUNT; i++) {
+ gh_list_prepend(&lists[i], mknode(num));
+ }
+ }
+
+ for (num = 0; num < ELT_COUNT; num++) {
+ for (i = 0; i < LIST_COUNT; i++) {
+ current = gh_list_pop(&lists[i]);
+ ret = nodeval(current);
+ if (ret != num) {
+ fprintf(stderr, "prepend_test: Bogus return value %d when expected %d\n",
+ ret, num);
+ return -EINVAL;
+ }
+ delnode(current);
+ }
+ }
+ for (i = 0; i < LIST_COUNT; i++) {
+ current = gh_list_pop(&lists[i]);
+ if (current) {
+ fprintf(stderr, "Ret is bogus for list %d", i);
+ return -EINVAL;
+ }
+ }
+
+ for (num = (ELT_COUNT/2 - 1); num >= 0; num--) {
+ for (i = 0; i < LIST_COUNT; i++) {
+ gh_list_prepend(&lists[i], mknode(num));
+ }
+ }
+
+ for (num = ELT_COUNT/2; num < ELT_COUNT; num++) {
+ for (i = 0; i < LIST_COUNT; i++) {
+ gh_list_append(&lists[i], mknode(num));
+ }
+ }
+
+ for (num = 0; num < ELT_COUNT; num++) {
+ for (i=0; i < LIST_COUNT; i++) {
+ current = gh_list_pop(&lists[i]);
+ ret = nodeval(current);
+ if (ret != num) {
+ fprintf(stderr, "prepend_test: Bogus return value %d when expected %d\n",
+ ret, num);
+ return -EINVAL;
+ }
+ delnode(current);
+ }
+ }
+
+ for (num = ELT_COUNT/2; num < ELT_COUNT; num++) {
+ for (i = 0; i < LIST_COUNT; i++)
+ gh_list_append(&lists[i], mknode(num));
+ }
+
+ for (num = ELT_COUNT/2 - 1; num >= 0; num--) {
+ for (i = 0; i < LIST_COUNT; i++)
+ gh_list_prepend(&lists[i], mknode(num));
+ }
+
+ for (num = 0; num < ELT_COUNT; num++) {
+ for (i = 0; i < LIST_COUNT; i++) {
+ current = gh_list_pop(&lists[i]);
+ ret = nodeval(current);
+ if (ret != num) {
+ fprintf(stderr, "prepend_test: Bogus return value %d when expected %d\n",
+ ret, num);
+ return -EINVAL;
+ }
+ delnode(current);
+ }
+ }
+
+ for (num = ELT_COUNT/2 - 1; num >= 0; num--) {
+ for (i = 0; i < LIST_COUNT; i++)
+ gh_list_prepend(&lists[i], mknode(num));
+ }
+
+ for (num = ELT_COUNT/2; num < ELT_COUNT; num++) {
+ for (i=0; i < LIST_COUNT; i++)
+ gh_list_append(&lists[i], mknode(num));
+ }
+
+ for (i = 0; i < LIST_COUNT; i++) {
+ num = 0;
+
+ for (current = gh_list_first_elem(&lists[i]); current; current = next) {
+ int k;
+
+ next = gh_lnode_next(current);
+ k = nodeval(current);
+ if (k != num) {
+ fprintf(stderr, "Got %d when I expected %d\n", k, num);
+ return -EINVAL;
+ }
+ gh_list_remove(&lists[i], current);
+ delnode(current);
+ num++;
+ }
+ if (num != ELT_COUNT) {
+ fprintf(stderr, "Number is %d, even though %d was expected", num, ELT_COUNT);
+ return -EINVAL;
+ }
+
+ if (gh_list_count(&lists[i]) != 0) {
+ fprintf(stderr, "List should be empty, but instead it has %d members!\n",
+ gh_list_count(&lists[i]));
+ return -EINVAL;
+ }
+ }
+
+ for (i = 0; i < LIST_COUNT; i++) {
+ while ((current = gh_list_pop(&lists[i])) != NULL)
+ delnode(current);
+
+ gh_list_free(&lists[i]);
+ }
+
+ return 0;
+}
+
+const struct test_case TestGHLists = {
+ .t_name = "test nsock internal ghlists",
+ .t_setup = NULL,
+ .t_run = ghlist_stress,
+ .t_teardown = NULL
+};
+
diff --git a/nsock/tests/logs.c b/nsock/tests/logs.c
new file mode 100644
index 0000000..d316d34
--- /dev/null
+++ b/nsock/tests/logs.c
@@ -0,0 +1,176 @@
+/*
+ * Nsock regression test suite
+ * Same license as nmap -- see https://nmap.org/book/man-legal.html
+ */
+
+#include "test-common.h"
+
+
+struct log_test_data {
+ nsock_pool nsp;
+ nsock_loglevel_t current_level;
+ unsigned int got_dbgfull: 1;
+ unsigned int got_dbg: 1;
+ unsigned int got_info: 1;
+ unsigned int got_error: 1;
+ unsigned int total;
+ int errcode;
+};
+
+static struct log_test_data *GlobalLTD;
+
+static void log_handler(const struct nsock_log_rec *rec) {
+ GlobalLTD->total++;
+ switch(rec->level) {
+ case NSOCK_LOG_DBG_ALL:
+ GlobalLTD->got_dbgfull = 1;
+ break;
+
+ case NSOCK_LOG_DBG:
+ GlobalLTD->got_dbg = 1;
+ break;
+
+ case NSOCK_LOG_INFO:
+ GlobalLTD->got_info = 1;
+ break;
+
+ case NSOCK_LOG_ERROR:
+ GlobalLTD->got_error = 1;
+ break;
+
+ default:
+ fprintf(stderr, "UNEXPECTED LOG LEVEL (%d)!\n", (int)rec->level);
+ GlobalLTD->errcode = -EINVAL;
+ }
+}
+
+static void nop_handler(nsock_pool nsp, nsock_event nse, void *udata) {
+}
+
+static int check_loglevel(struct log_test_data *ltd, nsock_loglevel_t level) {
+ int rc = 0;
+ nsock_event_id id;
+
+ nsock_set_loglevel(level);
+
+ ltd->current_level = level;
+
+ ltd->got_dbgfull = 0;
+ ltd->got_dbg = 0;
+ ltd->got_info = 0;
+ ltd->got_error = 0;
+
+ ltd->total = 0;
+ ltd->errcode = 0;
+
+ id = nsock_timer_create(ltd->nsp, nop_handler, 200, NULL);
+ nsock_event_cancel(ltd->nsp, id, 0);
+
+ if (ltd->errcode)
+ return ltd->errcode;
+
+ if (ltd->total < 1)
+ return -EINVAL;
+
+ return rc;
+}
+
+static int check_errlevel(struct log_test_data *ltd, nsock_loglevel_t level) {
+ nsock_event_id id;
+
+ nsock_set_loglevel(level);
+
+ ltd->current_level = level;
+
+ ltd->got_dbgfull = 0;
+ ltd->got_dbg = 0;
+ ltd->got_info = 0;
+ ltd->got_error = 0;
+
+ ltd->total = 0;
+ ltd->errcode = 0;
+
+ id = nsock_timer_create(ltd->nsp, nop_handler, 200, NULL);
+ nsock_event_cancel(ltd->nsp, id, 0);
+
+ if (ltd->errcode)
+ return ltd->errcode;
+
+ if (ltd->total > 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int log_setup(void **tdata) {
+ struct log_test_data *ltd;
+
+ ltd = calloc(1, sizeof(struct log_test_data));
+ if (ltd == NULL)
+ return -ENOMEM;
+
+ ltd->nsp = nsock_pool_new(ltd);
+ AssertNonNull(ltd->nsp);
+
+ *tdata = GlobalLTD = ltd;
+ return 0;
+}
+
+static int log_teardown(void *tdata) {
+ struct log_test_data *ltd = (struct log_test_data *)tdata;
+
+ if (tdata) {
+ nsock_pool_delete(ltd->nsp);
+ free(tdata);
+ }
+ nsock_set_log_function(NULL);
+ GlobalLTD = NULL;
+ return 0;
+}
+
+static int log_check_std_levels(void *tdata) {
+ struct log_test_data *ltd = (struct log_test_data *)tdata;
+ nsock_loglevel_t lvl;
+ int rc = 0;
+
+ nsock_set_log_function(log_handler);
+
+ for (lvl = NSOCK_LOG_DBG_ALL; lvl < NSOCK_LOG_ERROR; lvl++) {
+ rc = check_loglevel(ltd, lvl);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static int log_check_err_levels(void *tdata) {
+ struct log_test_data *ltd = (struct log_test_data *)tdata;
+ nsock_loglevel_t lvl;
+ int rc = 0;
+
+ nsock_set_log_function(log_handler);
+
+ for (lvl = NSOCK_LOG_ERROR; lvl <= NSOCK_LOG_NONE; lvl++) {
+ rc = check_errlevel(ltd, NSOCK_LOG_ERROR);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+
+const struct test_case TestLogLevels = {
+ .t_name = "set standard log levels",
+ .t_setup = log_setup,
+ .t_run = log_check_std_levels,
+ .t_teardown = log_teardown
+};
+
+const struct test_case TestErrLevels = {
+ .t_name = "check error log levels",
+ .t_setup = log_setup,
+ .t_run = log_check_err_levels,
+ .t_teardown = log_teardown
+};
diff --git a/nsock/tests/proxychain.c b/nsock/tests/proxychain.c
new file mode 100644
index 0000000..2360a68
--- /dev/null
+++ b/nsock/tests/proxychain.c
@@ -0,0 +1,159 @@
+/*
+ * Nsock regression test suite
+ * Same license as nmap -- see https://nmap.org/book/man-legal.html
+ */
+
+#include "test-common.h"
+#include "../src/nsock_log.h"
+
+struct proxy_test_data {
+ int tn;
+ nsock_pool nsp;
+};
+static struct proxy_test_data *GlobalTD;
+
+#define END_OF_TESTS -1
+#define GOOD 0
+#define BAD 1
+struct proxy_test {
+ int ttype;
+ const char *input;
+};
+
+static const struct proxy_test Tests[] = {
+ /* single proxy */
+ /* http */
+ {GOOD, "http://example.com"},
+ {GOOD, "http://127.0.0.1/"},
+ {GOOD, "http://1/some/crazy.path"},
+ {GOOD, "http://127.1/some/path?q=@!weird&other=;"},
+ {GOOD, "http://[::1]/"},
+ {GOOD, "http://1:80/"},
+ {GOOD, "http://1:8080"},
+ {GOOD, "http://127.0.0.1:1234/"},
+ {GOOD, "http://[::1]:8080/"},
+ {GOOD, "http://[::1]:80"},
+ /* https not supported! */
+ {BAD, "https://example.com/"},
+ /* No username/password in URI */
+ {BAD, "https://scott:tiger@example.com/"},
+ /* Port out of range */
+ {BAD, "http://example.com:65536/"},
+ /* Bad IPv6 syntax */
+ {BAD, "http://::1/"},
+ /* Missing host name */
+ {BAD, "http://:8080/"},
+ /* socks4 */
+ {GOOD, "socks4://example.com"},
+ {GOOD, "socks4://1"},
+ /* socks4 does not support IPv6 */
+ {BAD, "socks4://[::1]"},
+ /* Does SOCKS4 really support a path like this? */
+ {GOOD, "socks4://example.com/path?"},
+ /* multiple proxies */
+ {GOOD, "http://example.com:8080/,socks4://127.0.0.1/"},
+ {GOOD, "http://[::1]/,socks4://example.com:5000/"},
+ /* Should fail: socks4 cannot connect to IPv6 proxy */
+ {GOOD, "socks4://127.0.0.1/,socks4://example.com/,http://[::1]:9090"},
+ /* Dumb stuff */
+ {BAD, ""},
+ {BAD, ","},
+ {BAD, ",,"},
+ {BAD, "http://example.com/,"},
+ {BAD, "http://example.com/,,"},
+ {BAD, ",http://example.com/"},
+ {BAD, ",,http://example.com/"},
+ {BAD, "socks4://127.0.0.1/,http://example.com/,"},
+ {BAD, ",socks4://127.0.0.1/,http://example.com/"},
+ {BAD, "socks4://127.0.0.1/,,http://example.com/"},
+ {BAD, "http://example.com:-1/"},
+ {BAD, "http://example.com:0x80/"},
+ {BAD, "http://example.com:0/"},
+ {BAD, "http://example.com:2147483648"},
+ {BAD, "http://example.com:21474836480"},
+ {BAD, "http://:80"},
+ {BAD, "http://example.com:80.com"},
+ {BAD, "com"},
+ {BAD, "example.com"},
+ {BAD, "/example.com/"},
+ {BAD, "//example.com/"},
+ {BAD, "http/example.com/"},
+ {BAD, "http//example.com/"},
+ {BAD, "http:///example.com"},
+ {BAD, "sptth://example.com/"},
+ {BAD, " "},
+ {BAD, ", "},
+ {BAD, " ,"},
+ {BAD, ", ,"},
+ {BAD, " , , "},
+ {BAD, "http://example.com/,asdf"},
+ {END_OF_TESTS, NULL}
+};
+
+static int parser_test(void *testdata) {
+ int result = 0;
+ struct proxy_test_data *ptd = (struct proxy_test_data *)testdata;
+ const struct proxy_test *pt = &Tests[ptd->tn];
+ while (pt->ttype != END_OF_TESTS) {
+ nsock_proxychain pxc = NULL;
+ if (pt->ttype == BAD)
+ nsock_log_info("Expected failure:");
+ int ret = nsock_proxychain_new(pt->input, &pxc, NULL);
+ nsock_log_debug("Test %d result: %d", ptd->tn, ret);
+ if (ret > 0) {
+ if (pt->ttype == BAD) {
+ fprintf(stderr, "Proxy Test #%d: Failed to reject bad input: %s\n", ptd->tn, pt->input);
+ result = -1;
+ }
+ nsock_proxychain_delete(pxc);
+ }
+ else if (ret <= 0 && pt->ttype == GOOD) {
+ fprintf(stderr, "Proxy Test #%d: Failed to parse good input: %s\n", ptd->tn, pt->input);
+ result = -2;
+ }
+ ptd->tn++;
+ pt = &Tests[ptd->tn];
+ }
+ return result;
+}
+
+static void log_handler(const struct nsock_log_rec *rec) {
+ /* Only print log messages if we expect the test to succeed. */
+ if (Tests[GlobalTD->tn].ttype == GOOD) {
+ fprintf(stderr, "Proxy Test #%d: %s(): %s\n", GlobalTD->tn, rec->func, rec->msg);
+ }
+}
+
+static int proxy_setup(void **tdata) {
+ struct proxy_test_data *ptd = calloc(1, sizeof(struct proxy_test_data));
+ if (ptd == NULL)
+ return -ENOMEM;
+
+ ptd->nsp = nsock_pool_new(ptd);
+ AssertNonNull(ptd->nsp);
+
+ nsock_set_log_function(log_handler);
+
+ *tdata = GlobalTD = ptd;
+ return 0;
+}
+
+static int proxy_teardown(void *tdata) {
+ struct proxy_test_data *ptd = (struct proxy_test_data *)tdata;
+
+ if (tdata) {
+ nsock_pool_delete(ptd->nsp);
+ free(tdata);
+ }
+ nsock_set_log_function(NULL);
+ GlobalTD = NULL;
+ return 0;
+}
+
+
+const struct test_case TestProxyParse = {
+ .t_name = "test nsock proxychain parsing",
+ .t_setup = proxy_setup,
+ .t_run = parser_test,
+ .t_teardown = proxy_teardown
+};
diff --git a/nsock/tests/run_tests.sh b/nsock/tests/run_tests.sh
new file mode 100755
index 0000000..c0392f8
--- /dev/null
+++ b/nsock/tests/run_tests.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+
+# nsock regression test suite
+# Same license as nmap -- see https://nmap.org/book/man-legal.html
+
+# hackish, I should consider using a configuration file.
+PORT_UDP=$(grep "PORT_UDP " test-common.h | awk '{print $3}')
+PORT_TCP=$(grep "PORT_TCP " test-common.h | awk '{print $3}')
+PORT_TCPSSL=$(grep "PORT_TCPSSL " test-common.h | awk '{print $3}')
+
+EXEC_MAIN=./tests_main
+
+NCAT=${NCAT:-ncat}
+if [ ! -x "$NCAT" -a -z "$(which $NCAT)" ]; then
+ echo "Can't find your ncat: $NCAT"
+ echo "Trying ../../ncat/ncat"
+ NCAT="../../ncat/ncat"
+ if [ ! -x "$NCAT" ]; then
+ echo "You haven't built Ncat."
+ echo "Skipping nsock tests."
+ exit 0
+ fi
+fi
+
+
+if [ -n "$1" ]
+then
+ case "$1" in
+ "gdb")
+ TRACER="gdb --args"
+ ;;
+
+ "trace")
+ TRACER="strace"
+ ;;
+
+ "leak")
+ TRACER="valgrind --leak-check=yes"
+ ;;
+
+ "-h")
+ echo "Usage: `basename $0` [gdb|trace|leak]"
+ exit 0
+ ;;
+
+ *)
+ echo "Unknown mode $1"
+ exit 1
+ ;;
+ esac
+fi
+
+
+setup_echo_udp() {
+ $NCAT -l --udp --sh-exec cat 127.0.0.1 $PORT_UDP &
+ pid_udp=$!
+ echo "started UDP listener on port $PORT_UDP (pid $pid_udp)"
+}
+
+setup_echo_tcp() {
+ $NCAT -l --keep-open --sh-exec cat 127.0.0.1 $PORT_TCP &
+ pid_tcp=$!
+ echo "started TCP listener on port $PORT_TCP (pid $pid_tcp)"
+}
+
+setup_echo_tcpssl() {
+ $NCAT -l --ssl --keep-open --sh-exec cat 127.0.0.1 $PORT_TCPSSL &
+ pid_tcpssl=$!
+ echo "started TCP SSL listener on port $PORT_TCPSSL (pid $pid_tcpssl)"
+}
+
+cleanup_all() {
+ kill -s KILL $@ 2>&1 >> /dev/null
+}
+
+main() {
+ setup_echo_udp $PORT_UDP
+ setup_echo_tcp $PORT_TCP
+ $EXEC_MAIN --ssl && setup_echo_tcpssl $PORT_TCPSSL
+
+ $TRACER $EXEC_MAIN
+
+ cleanup_all $pid_udp $pid_tcp $pid_tcpssl
+}
+
+main
diff --git a/nsock/tests/test-common.h b/nsock/tests/test-common.h
new file mode 100644
index 0000000..d746460
--- /dev/null
+++ b/nsock/tests/test-common.h
@@ -0,0 +1,89 @@
+/*
+ * Nsock regression test suite
+ * Same license as nmap -- see https://nmap.org/book/man-legal.html
+ */
+
+
+#ifndef __TEST_COMMON_H
+#define __TEST_COMMON_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <nsock.h>
+
+
+#define PORT_UDP 55234
+#define PORT_TCP 55235
+#define PORT_TCPSSL 55236
+
+
+#define __ASSERT_BASE(stmt) do { \
+ if (!(stmt)) { \
+ fprintf(stderr, "(%s:%d) Assertion failed: " #stmt "\n", \
+ __FILE__, __LINE__); \
+ return -EINVAL; \
+ } \
+ } while (0)
+
+
+#define AssertNonNull(a) __ASSERT_BASE((a) != NULL);
+#define AssertEqual(a, b) __ASSERT_BASE((a) == (b));
+#define AssertStrEqual(a, b) __ASSERT_BASE(strcmp((a), (b)) == 0);
+
+
+struct test_case {
+ const char *t_name;
+ int (*t_setup)(void **tdata);
+ int (*t_run)(void *tdata);
+ int (*t_teardown)(void *tdata);
+};
+
+
+static inline const char *get_test_name(const struct test_case *test) {
+ return test->t_name;
+}
+
+static inline int test_setup(const struct test_case *test, void **tdata) {
+ int rc;
+
+ assert(test);
+
+ if (test->t_setup)
+ rc = test->t_setup(tdata);
+ else
+ rc = 0;
+
+ return rc;
+}
+
+static inline int test_run(const struct test_case *test, void *tdata) {
+ int rc;
+
+ assert(test);
+
+ if (test->t_run)
+ rc = test->t_run(tdata);
+ else
+ rc = 0;
+
+ return rc;
+}
+
+static inline int test_teardown(const struct test_case *test, void *tdata) {
+ int rc;
+
+ assert(test);
+
+ if (test->t_teardown)
+ rc = test->t_teardown(tdata);
+ else
+ rc = 0;
+
+ return rc;
+}
+
+#endif /* ^__TEST_COMMON_H */
diff --git a/nsock/tests/tests_main.c b/nsock/tests/tests_main.c
new file mode 100644
index 0000000..4ab6d07
--- /dev/null
+++ b/nsock/tests/tests_main.c
@@ -0,0 +1,133 @@
+/*
+ * Nsock regression test suite
+ * Same license as nmap -- see https://nmap.org/book/man-legal.html
+ */
+
+
+#include "test-common.h"
+#include "string.h"
+
+
+#ifndef WIN32
+ #define RESET "\033[0m"
+ #define BOLDRED "\033[1m\033[31m"
+ #define BOLDGREEN "\033[1m\033[32m"
+ #define TEST_FAILED "[" BOLDRED "FAILED" RESET "]"
+ #define TEST_OK "[" BOLDGREEN "OK" RESET "]"
+#else
+ /* WIN32 terminal has no ANSI driver */
+ #define TEST_FAILED "[FAILED]"
+ #define TEST_OK "[OK]"
+#endif
+
+
+
+/* socket_strerror() comes from nbase
+ * Declared here to work around a silly inclusion issue until I can fix it. */
+char *socket_strerror(int errnum);
+
+extern const struct test_case TestPoolUserData;
+extern const struct test_case TestTimer;
+extern const struct test_case TestLogLevels;
+extern const struct test_case TestErrLevels;
+extern const struct test_case TestConnectTCP;
+extern const struct test_case TestConnectFailure;
+extern const struct test_case TestGHLists;
+extern const struct test_case TestGHHeaps;
+extern const struct test_case TestHeapOrdering;
+extern const struct test_case TestProxyParse;
+extern const struct test_case TestCancelTCP;
+extern const struct test_case TestCancelUDP;
+#ifdef HAVE_OPENSSL
+extern const struct test_case TestCancelSSL;
+#endif
+
+
+static const struct test_case *TestCases[] = {
+ /* ---- basic.c */
+ &TestPoolUserData,
+ /* ---- timer.c */
+ &TestTimer,
+ /* ---- logs.c */
+ &TestLogLevels,
+ &TestErrLevels,
+ /* ---- connect.c */
+ &TestConnectTCP,
+ &TestConnectFailure,
+ /* ---- ghlists.c */
+ &TestGHLists,
+ /* ---- ghheaps.c */
+ &TestGHHeaps,
+ &TestHeapOrdering,
+ /* ---- proxychain.c */
+ &TestProxyParse,
+ /* ---- cancel.c */
+ &TestCancelTCP,
+ &TestCancelUDP,
+#ifdef HAVE_OPENSSL
+ &TestCancelSSL,
+#endif
+ NULL
+};
+
+
+static int test_case_run(const struct test_case *test) {
+ int rc;
+ void *tdata = NULL;
+
+ rc = test_setup(test, &tdata);
+ if (rc)
+ return rc;
+
+ rc = test_run(test, tdata);
+ if (rc)
+ return rc;
+
+ return test_teardown(test, tdata);
+}
+
+#ifdef WIN32
+static int win_init(void) {
+ WSADATA data;
+ int rc;
+
+ rc = WSAStartup(MAKEWORD(2, 2), &data);
+ if (rc)
+ fatal("Failed to start winsock: %s\n", socket_strerror(rc));
+
+ return 0;
+}
+#endif
+
+int main(int ac, char **av) {
+ int rc, i;
+
+ /* simple "do we have ssl" check for run_tests.sh */
+ if (ac == 2 && !strncmp(av[1], "--ssl", 5)) {
+#ifdef HAVE_SSL
+ return 0;
+#else
+ return 1;
+#endif
+ }
+
+#ifdef WIN32
+ win_init();
+#endif
+
+ for (i = 0; TestCases[i] != NULL; i++) {
+ const struct test_case *current = TestCases[i];
+ const char *name = get_test_name(current);
+
+ printf("%-48s", name);
+ fflush(stdout);
+ rc = test_case_run(current);
+ if (rc) {
+ printf(TEST_FAILED " (%s)\n", socket_strerror(-rc));
+ break;
+ }
+ printf(TEST_OK "\n");
+ }
+ return rc;
+}
+
diff --git a/nsock/tests/timer.c b/nsock/tests/timer.c
new file mode 100644
index 0000000..27250ce
--- /dev/null
+++ b/nsock/tests/timer.c
@@ -0,0 +1,129 @@
+/*
+ * Nsock regression test suite
+ * Same license as nmap -- see https://nmap.org/book/man-legal.html
+ */
+
+#include "test-common.h"
+#include <time.h>
+
+#define TIMERS_BUFFLEN 1024
+
+
+struct timer_test_data {
+ nsock_pool nsp;
+ nsock_event_id timer_list[TIMERS_BUFFLEN];
+ size_t timer_count;
+ int stop; /* set to non-zero to stop the test */
+};
+
+
+static void timer_handler(nsock_pool nsp, nsock_event nse, void *tdata);
+
+
+static void add_timer(struct timer_test_data *ttd, int timeout) {
+ nsock_event_id id;
+
+ id = nsock_timer_create(ttd->nsp, timer_handler, timeout, ttd);
+ ttd->timer_list[ttd->timer_count++] = id;
+}
+
+static void timer_handler(nsock_pool nsp, nsock_event nse, void *tdata) {
+ struct timer_test_data *ttd = (struct timer_test_data *)tdata;
+ int rnd, rnd2;
+
+ if (nse_status(nse) != NSE_STATUS_SUCCESS) {
+ ttd->stop = -nsock_pool_get_error(nsp);
+ return;
+ }
+
+ if (ttd->timer_count > TIMERS_BUFFLEN - 3)
+ return;
+
+ rnd = rand() % ttd->timer_count;
+ rnd2 = rand() % 3;
+
+ switch (rnd2) {
+ case 0:
+ /* Do nothing */
+ /* Actually I think I'll create two timers :) */
+ add_timer(ttd, rand() % 3000);
+ add_timer(ttd, rand() % 3000);
+ break;
+
+ case 1:
+ /* Try to kill another id (which may or may not be active */
+ nsock_event_cancel(nsp, ttd->timer_list[rnd], rand() % 2);
+ break;
+
+ case 2:
+ /* Create a new timer */
+ add_timer(ttd, rand() % 3000);
+ break;
+
+ default:
+ assert(0);
+ }
+}
+
+static int timer_setup(void **tdata) {
+ struct timer_test_data *ttd;
+
+ srand(time(NULL));
+
+ ttd = calloc(1, sizeof(struct timer_test_data));
+ if (ttd == NULL)
+ return -ENOMEM;
+
+ ttd->nsp = nsock_pool_new(NULL);
+ AssertNonNull(ttd->nsp);
+
+ *tdata = ttd;
+ return 0;
+}
+
+static int timer_teardown(void *tdata) {
+ struct timer_test_data *ttd = (struct timer_test_data *)tdata;
+
+ if (tdata) {
+ nsock_pool_delete(ttd->nsp);
+ free(tdata);
+ }
+ return 0;
+}
+
+static int timer_totalmess(void *tdata) {
+ struct timer_test_data *ttd = (struct timer_test_data *)tdata;
+ enum nsock_loopstatus loopret;
+ int num_loops = 0;
+
+ add_timer(ttd, 1800);
+ add_timer(ttd, 800);
+ add_timer(ttd, 1300);
+ add_timer(ttd, 0);
+ add_timer(ttd, 100);
+
+ /* Now lets get this party started right! */
+ while (num_loops++ < 5 && !ttd->stop) {
+ loopret = nsock_loop(ttd->nsp, 1500);
+ switch (loopret) {
+ case NSOCK_LOOP_TIMEOUT:
+ /* nothing to do */
+ break;
+
+ case NSOCK_LOOP_NOEVENTS:
+ return 0;
+
+ default:
+ return -(nsock_pool_get_error(ttd->nsp));
+ }
+ }
+ return ttd->stop;
+}
+
+const struct test_case TestTimer = {
+ .t_name = "test timer operations",
+ .t_setup = timer_setup,
+ .t_run = timer_totalmess,
+ .t_teardown = timer_teardown
+};
+