1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-12 10:49:02 +00:00

Merged nsock-engines from nmap-exp. This rewrite of the nsock library adds

support for system-specific scalable IO notification facilities without breaking
portability. This initial version comes with an epoll(7)-based engine for Linux
and a select(2)-based fallback engine for all other operating systems.

This required an important refactoring of the library but the external API was
preserved.

The rewrite also tries to bring the coding standards of nmap to nsock.

See http://labs.unix-junkies.org/nsock_engines.html for the details.
This commit is contained in:
henri
2012-01-05 01:08:16 +00:00
parent 15f74d395f
commit 856cd00a17
31 changed files with 4496 additions and 2774 deletions

View File

@@ -1,5 +1,11 @@
# Nmap Changelog ($Id$); -*-text-*- # Nmap Changelog ($Id$); -*-text-*-
o Merged nsock-engines from nmap-exp. This rewrite of the nsock library adds
support for system-specific scalable IO notification facilities without
breaking portability. This initial version comes with an epoll(7)-based engine
for Linux and a select(2)-based fallback engine for all other operating
systems. [Henri]
o Added probe and matchline for Couchbase Membase NoSQL database [Patrik] o Added probe and matchline for Couchbase Membase NoSQL database [Patrik]
o Added the new --script-args-file option which allows you to specify o Added the new --script-args-file option which allows you to specify

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* nsock.h -- public interface definitions for the nsock parallel socket * * nsock.h -- public interface definitions for the nsock parallel socket *
* event library * * event library *
@@ -56,11 +55,6 @@
/* $Id$ */ /* $Id$ */
/* Would you like to include pcap support in nsock?
* Pcap support code is currently unstable, so we give
* you a choice. In future this #define will be removed.*/
//#define HAVE_PCAP 1
#ifndef NSOCK_H #ifndef NSOCK_H
#define NSOCK_H #define NSOCK_H
@@ -89,38 +83,34 @@ extern "C" {
/* The read calls will generally return after reading at least this /* The read calls will generally return after reading at least this
* much data so that the caller can process it and so that the * much data so that the caller can process it and so that the
* connection spewing data doesn't monopolize resources. The caller * connection spewing data doesn't monopolize resources. The caller
* can always initiate another read request to ask for more. * can always initiate another read request to ask for more. */
*/
#define NSOCK_READ_CHUNK_SIZE 0x8FFFF #define NSOCK_READ_CHUNK_SIZE 0x8FFFF
/********************* TYPEDEFS ********************/
/* ------------------- TYPEDEFS ------------------- */
/* nsock_pool, nsock_iod, and nsock_event are opaque objects that should /* nsock_pool, nsock_iod, and nsock_event are opaque objects that should
only be accessed using the appropriate accessor functions (described * only be accessed using the appropriate accessor functions (described below). */
below).
*/
/* An nsock_pool aggregates and manages events and i/o descriptors */ /* An nsock_pool aggregates and manages events and i/o descriptors */
typedef void *nsock_pool; typedef void *nsock_pool;
/* nsock_iod is an I/O descriptor -- you create it and then use it to /* 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 * make calls to do connect()s, read()s, write()s, etc. A single IOD can handle
can handle multiple event calls, but only one at a time. Also the * multiple event calls, but only one at a time. Also the event calls must be in
event calls must be in a "reasonable" order. For example, you * a "reasonable" order. For example, you might start with nsock_connect_tcp()
might start with nsock_connect_tcp() followed by a bunch of * followed by a bunch of nsock_read* and nsock_write* calls. Then you either
nsock_read* and nsock_write* calls. Then you either destroy the * destroy the iod for good with nsi_delete() and allocate a new one via nsi_new
iod for good with nsi_delete() and allocate a new one via nsi_new * for your next connection. */
for your next connection. */
typedef void *nsock_iod; typedef void *nsock_iod;
/* An event is created when you do various calls (for reading, writing, /* An event is created when you do various calls (for reading, writing,
connecting, timers, etc) and is provided back to you in the callback * connecting, timers, etc) and is provided back to you in the callback when the
when the call completes/fails. It is automatically destroyed after * call completes/fails. It is automatically destroyed after the callback */
the callback
*/
typedef void *nsock_event; typedef void *nsock_event;
/* Provided by calls which (internally) create an nsock_event. This allows /* Provided by calls which (internally) create an nsock_event. This allows you
you to cancel the event */ * to cancel the event */
typedef unsigned long nsock_event_id; typedef unsigned long nsock_event_id;
/* This is used to save SSL sessionids between SSL connections */ /* This is used to save SSL sessionids between SSL connections */
@@ -128,28 +118,34 @@ typedef void *nsock_ssl_session;
typedef void *nsock_ssl_ctx; typedef void *nsock_ssl_ctx;
typedef void *nsock_ssl; typedef void *nsock_ssl;
/******************** PROTOTYPES *******************/
/* ------------------- PROTOTYPES ------------------- */
/* Here is the all important looping function that tells the event /* Here is the all important looping function that tells the event
engine to start up and begin processing events. It will continue * engine to start up and begin processing events. It will continue until all
until all events have been delivered (including new ones started * events have been delivered (including new ones started from event handlers),
from event handlers), or the msec_timeout is reached, or a major * or the msec_timeout is reached, or a major error has occured. Use -1 if you
error has occured. Use -1 if you don't want to set a maximum time * don't want to set a maximum time for it to run. A timeout of 0 will return
for it to run. A timeout of 0 will return after 1 non-blocking * after 1 non-blocking loop. The nsock loop can be restarted again after it
loop. The nsock loop can be restarted again after it returns. For * returns. For example you could do a series of 15 second runs, allowing you
example you could do a series of 15 second runs, allowing you to do * to do other stuff between them. Or you could just schedule a timer to call
other stuff between them. Or you could just schedule a timer to * you back every 15 seconds. */
call you back every 15 seconds.*/ enum nsock_loopstatus {
enum nsock_loopstatus { NSOCK_LOOP_NOEVENTS = 2, NSOCK_LOOP_TIMEOUT, NSOCK_LOOP_ERROR, NSOCK_LOOP_QUIT }; NSOCK_LOOP_NOEVENTS = 2,
NSOCK_LOOP_TIMEOUT,
NSOCK_LOOP_ERROR,
NSOCK_LOOP_QUIT
};
enum nsock_loopstatus nsock_loop(nsock_pool nsp, int msec_timeout); enum nsock_loopstatus nsock_loop(nsock_pool nsp, int msec_timeout);
/* Calling this function will cause nsock_loop to quit on its next iteration /* Calling this function will cause nsock_loop to quit on its next iteration
with a return value of NSOCK_LOOP_QUIT. */ * with a return value of NSOCK_LOOP_QUIT. */
void nsock_loop_quit(nsock_pool nsp); void nsock_loop_quit(nsock_pool nsp);
/* This next function returns the errno style error code -- which is only /* This next function returns the errno style error code -- which is only valid
valid if the status is NSOCK_LOOP_ERROR was returned by nsock_loop() */ * if the status is NSOCK_LOOP_ERROR was returned by nsock_loop() */
int nsp_geterrorcode(nsock_pool nsp); int nsp_geterrorcode(nsock_pool nsp);
/* Every nsp has an ID that is unique across the program execution */ /* Every nsp has an ID that is unique across the program execution */
@@ -157,425 +153,380 @@ unsigned long nsp_getid(nsock_pool nsp);
nsock_ssl nsi_getssl(nsock_iod nsockiod); nsock_ssl nsi_getssl(nsock_iod nsockiod);
/* Note that nsi_get1_ssl_session will increment the usage count /* Note that nsi_get1_ssl_session will increment the usage count of the
* of the SSL_SESSION, since nsock does a free when the nsi is * SSL_SESSION, since nsock does a free when the nsi is destroyed. It's up to
* destroyed. It's up to any calling function/etc to do a * any calling function/etc to do a SSL_SESSION_free() on it.
* SSL_SESSION_free() on it. nsi_get0_ssl_session doesn't * nsi_get0_ssl_session doesn't increment, and is for informational purposes
* increment, and is for informational purposes only. * only. */
*/
nsock_ssl_session nsi_get1_ssl_session(nsock_iod nsockiod); nsock_ssl_session nsi_get1_ssl_session(nsock_iod nsockiod);
nsock_ssl_session nsi_get0_ssl_session(nsock_iod nsockiod); nsock_ssl_session nsi_get0_ssl_session(nsock_iod nsockiod);
/* Sometimes it is useful to store a pointer to information inside /* Sometimes it is useful to store a pointer to information inside the NSP so
the NSP so you can retrieve it during a callback. */ * you can retrieve it during a callback. */
void nsp_setud(nsock_pool nsp, void *data); void nsp_setud(nsock_pool nsp, void *data);
/* And the function above wouldn't make much sense if we didn't have a way /* And the function above wouldn't make much sense if we didn't have a way to
to retrieve that data ... */ * retrieve that data ... */
void *nsp_getud(nsock_pool nsp); void *nsp_getud(nsock_pool nsp);
/* Sets a trace/debug level and stream. A level of 0 (the default) /* Sets a trace/debug level and stream. A level of 0 (the default) turns
turns tracing off, while higher numbers are more verbose. If the * tracing off, while higher numbers are more verbose. If the stream given is
stream given is NULL, it defaults to stdout. This is generally only * NULL, it defaults to stdout. This is generally only used for debugging
used for debugging purposes. A level of 1 or 2 is usually sufficient, * purposes. A level of 1 or 2 is usually sufficient, but 10 will ensure you get
but 10 will ensure you get everything. The basetime can be NULL to * everything. The basetime can be NULL to print trace lines with the current
print trace lines with the current time, otherwise the difference * time, otherwise the difference between the current time and basetime will be
between the current time and basetime will be used (the time program * used (the time program execution starts would be a good candidate) */
execution starts would be a good candidate) */
void nsp_settrace(nsock_pool nsp, FILE *file, int level, const struct timeval *basetime); void nsp_settrace(nsock_pool nsp, FILE *file, int level, const struct timeval *basetime);
/* Turns on or off broadcast support on new sockets. Default is off /* Turns on or off broadcast support on new sockets. Default is off (0, false)
(0, false) set in nsp_new(). Any non-zero (true) value sets * set in nsp_new(). Any non-zero (true) value sets SO_BROADCAST on all new
SO_BROADCAST on all new sockets (value of optval will be used directly * sockets (value of optval will be used directly in the setsockopt() call */
in the setsockopt() call */
void nsp_setbroadcast(nsock_pool nsp, int optval); void nsp_setbroadcast(nsock_pool nsp, int optval);
/* Initializes an Nsock pool to create SSL connections. This sets an internal /* 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 * 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. */ * are made from it. Returns the SSL_CTX so you can set your own options. */
nsock_ssl_ctx nsp_ssl_init(nsock_pool ms_pool); nsock_ssl_ctx nsp_ssl_init(nsock_pool ms_pool);
/* Initializes an Nsock pool to create SSL connections that emphasize speed over /* Initializes an Nsock pool to create SSL connections that emphasize speed over
security. Insecure ciphers are used when they are faster and no certificate * 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. */ * verification is done. Returns the SSL_CTX so you can set your own options. */
nsock_ssl_ctx nsp_ssl_init_max_speed(nsock_pool ms_pool); nsock_ssl_ctx nsp_ssl_init_max_speed(nsock_pool ms_pool);
/* And here is how you create an nsock_pool. This allocates, initializes, /* And here is how you create an nsock_pool. This allocates, initializes, and
and returns an nsock_pool event aggregator. In the case of error, * returns an nsock_pool event aggregator. In the case of error, NULL will be
NULL will be returned. If you do not wish to immediately associate * returned. If you do not wish to immediately associate any userdata, pass in
any userdata, pass in NULL. */ * NULL. */
nsock_pool nsp_new(void *userdata); nsock_pool nsp_new(void *userdata);
/* If nsp_new returned success, you must free the nsp when you are /* If nsp_new returned success, you must free the nsp when you are done with it
done with it to conserve memory (and in some cases, sockets). * to conserve memory (and in some cases, sockets). After this call, nsp may no
After this call, nsp may no longer be used. Any pending events are * longer be used. Any pending events are sent an NSE_STATUS_KILL callback and
sent an NSE_STATUS_KILL callback and all outstanding iods are * all outstanding iods are deleted. */
deleted. */
void nsp_delete(nsock_pool nsp); void nsp_delete(nsock_pool nsp);
/* nsock_event handles a single event. Its ID is generally returned when /* nsock_event handles a single event. Its ID is generally returned when the
the event is created, and the event itself is included in callbacks */ * 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) */ * ---------------------------------------------------------------------------
* 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 #define TYPE_CODE_NUM_BITS 3
enum nse_type { enum nse_type {
NSE_TYPE_CONNECT=0, NSE_TYPE_CONNECT = 0,
NSE_TYPE_CONNECT_SSL=1, NSE_TYPE_CONNECT_SSL = 1,
NSE_TYPE_READ=2, NSE_TYPE_READ = 2,
NSE_TYPE_WRITE=3, NSE_TYPE_WRITE = 3,
NSE_TYPE_TIMER=4, NSE_TYPE_TIMER = 4,
NSE_TYPE_PCAP_READ=5, NSE_TYPE_PCAP_READ = 5,
NSE_TYPE_MAX=6, NSE_TYPE_MAX = 6,
}; /* At some point I was considering a NSE_TYPE_START and NSE_TYPE_CUSTOM */ }; /* At some point I was considering a NSE_TYPE_START and NSE_TYPE_CUSTOM */
/* Find the type of an event that spawned a callback */ /* Find the type of an event that spawned a callback */
enum nse_type nse_type(nsock_event nse); enum nse_type nse_type(nsock_event nse);
/* Takes an nse_type (as returned by nse_type() and returns a static /* Takes an nse_type (as returned by nse_type() and returns a static string name
string name that you can use for printing, etc. */ * that you can use for printing, etc. */
const char *nse_type2str(enum nse_type type); const char *nse_type2str(enum nse_type type);
/* Did the event succeed? What is the status? */ /* Did the event succeed? What is the status? */
enum nse_status { NSE_STATUS_NONE = 0, /* User should never see this */ enum nse_status {
NSE_STATUS_NONE = 0, /* User should never see this */
NSE_STATUS_SUCCESS, /* Everything went A-OK! */ NSE_STATUS_SUCCESS, /* Everything went A-OK! */
NSE_STATUS_ERROR, /* Uh-oh! Problem, check the NSE_STATUS_ERROR, /* Uh-oh! Problem, check the nse_errorcode() */
nse_errorcode() */ NSE_STATUS_TIMEOUT, /* The async call surpassed the timeout you specified */
NSE_STATUS_TIMEOUT, /* The async call surpassed the NSE_STATUS_CANCELLED, /* Someone cancelled the event. (by calling nsock_event_cancel. */
timeout you specified */ NSE_STATUS_KILL, /* The event has been killed, this generally means the
NSE_STATUS_CANCELLED, /* Someone cancelled the nspool is being deleted -- you should free up any
event. (by calling resources you have allocated and exit. Don't you
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! */ dare make any more async nsock calls! */
NSE_STATUS_EOF /* We got EOF and NO DATA -- if we got data NSE_STATUS_EOF /* We got EOF and NO DATA -- if we got data first,
first, SUCCESS is reported (see nse_eof() SUCCESS is reported (see nse_eof() */
*/ };
};
enum nse_status nse_status(nsock_event nse); enum nse_status nse_status(nsock_event nse);
/* Takes an nse_status (as returned by nse_status() and returns a static /* Takes an nse_status (as returned by nse_status() and returns a static string
string name that you can use for printing, etc. */ * name that you can use for printing, etc. */
const char *nse_status2str(enum nse_status status); const char *nse_status2str(enum nse_status status);
/* This next function tells whether we received an EOF when we /* This next function tells whether we received an EOF when we were reading. It
were reading. It is generally a better way to check for EOF * is generally a better way to check for EOF than looking at the status because
than looking at the status because sometimes we read some data * sometimes we read some data before getting the EOF, in which SUCCESS is
before getting the EOF, in which SUCCESS is returned (although * returned (although another read attempt would return a status of EOF).
another read attempt would return a status of EOF). nse_eof * nse_eof returns nonzero if we have reached EOF, zero if we have NOT reach
returns nonzero if we have reached EOF, zero if we have NOT * EOF. */
reach EOF. */
int nse_eof(nsock_event nse); int nse_eof(nsock_event nse);
/* This next function returns the errno style error code -- which is only /* This next function returns the errno style error code -- which is only valid
valid if the status is NSE_STATUS_ERROR (this is a normal errno style * if the status is NSE_STATUS_ERROR (this is a normal errno style errorcode). */
errorcode */
int nse_errorcode(nsock_event nse); 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 */ /* 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); nsock_event_id nse_id(nsock_event nse);
/* If you did a read request, and the result was STATUS_SUCCESS, this /* If you did a read request, and the result was STATUS_SUCCESS, this function
function provides the buffer that was read in as well as the number * provides the buffer that was read in as well as the number of chars read.
of chars read. The buffer should not be modified or free'd . It is not * The buffer should not be modified or free'd . It is not guaranteed to be
guaranteed to be NUL-terminated and it may even contain nuls */ * NUL-terminated and it may even contain nuls */
char *nse_readbuf(nsock_event nse, int *nbytes); char *nse_readbuf(nsock_event nse, int *nbytes);
/* Obtains the nsock_iod (see below) associated with the event. Note that /* Obtains the nsock_iod (see below) associated with the event. Note that some
some events (such as timers) don't have an nsock_iod associated with them * events (such as timers) don't have an nsock_iod associated with them */
*/
nsock_iod nse_iod(nsock_event nse); nsock_iod nse_iod(nsock_event nse);
/* nsock_iod is like a "file descriptor" for the nsock library. You use it to
/* nsock_iod is like a "file descriptor" for the nsock library. You * request events. And here is how you create an nsock_iod. nsi_new returns
use it to request events. And here is how you create an nsock_iod. * NULL if the iod cannot be allocated. Pass NULL as userdata if you don't want
nsi_new returns NULL if the iod cannot be allocated. Pass NULL as * to immediately associate any user data with the iod. */
userdata if you don't want to immediately associate any user data
with the iod. */
nsock_iod nsi_new(nsock_pool nsockp, void *userdata); nsock_iod nsi_new(nsock_pool nsockp, void *userdata);
/* This version allows you to associate an existing sd with the msi /* This version allows you to associate an existing sd with the msi so that you
so that you can read/write it using the nsock infrastructure. For example, * can read/write it using the nsock infrastructure. For example, you may want
you may want to watch for data from STDIN_FILENO at the same time as you * to watch for data from STDIN_FILENO at the same time as you read/write
read/write various sockets. STDIN_FILENO is a special case, however. Any * various sockets. STDIN_FILENO is a special case, however. Any other sd is
other sd is dup()ed, so you may close or otherwise manipulate your copy. * dup()ed, so you may close or otherwise manipulate your copy. The duped copy
The duped copy will be destroyed when the nsi is destroyed * will be destroyed when the nsi is destroyed */
*/
nsock_iod nsi_new2(nsock_pool nsockp, int sd, void *userdata); nsock_iod nsi_new2(nsock_pool nsockp, int sd, void *userdata);
/* If msiod_new returned success, you must free the iod when you are /* If msiod_new returned success, you must free the iod when you are done with
done with it to conserve memory (and in some cases, sockets). * it to conserve memory (and in some cases, sockets). After this call,
After this call, nsockiod may no longer be used -- you need to * nsockiod may no longer be used -- you need to create a new one with
create a new one with nsi_new(). pending_response tells what to do * nsi_new(). pending_response tells what to do with any events that are
with any events that are pending on this nsock_iod. This can be * pending on this nsock_iod. This can be NSOCK_PENDING_NOTIFY (send a KILL
NSOCK_PENDING_NOTIFY (send a KILL notification to each event), * notification to each event), NSOCK_PENDING_SILENT (do not send notification
NSOCK_PENDING_SILENT (do not send notification to the killed * to the killed events), or NSOCK_PENDING_ERROR (print an error message and
events), or NSOCK_PENDING_ERROR (print an error message and quiit * quiit the program) */
the program) */
#define NSOCK_PENDING_NOTIFY 1 #define NSOCK_PENDING_NOTIFY 1
#define NSOCK_PENDING_SILENT 2 #define NSOCK_PENDING_SILENT 2
#define NSOCK_PENDING_ERROR 4 #define NSOCK_PENDING_ERROR 4
void nsi_delete(nsock_iod nsockiod, int pending_response); void nsi_delete(nsock_iod nsockiod, int pending_response);
/* Sometimes it is useful to store a pointer to information inside /* Sometimes it is useful to store a pointer to information inside
the nsiod so you can retrieve it during a callback. */ * the nsiod so you can retrieve it during a callback. */
void nsi_setud(nsock_iod nsiod, void *data); void nsi_setud(nsock_iod nsiod, void *data);
/* And the function above wouldn't make much sense if we didn't have a way /* And the function above wouldn't make much sense if we didn't have a way to
to retrieve that data ... */ * retrieve that data ... */
void *nsi_getud(nsock_iod nsiod); void *nsi_getud(nsock_iod nsiod);
/* I didn't want to do this. Its an ugly hack, but I suspect it will /* I didn't want to do this. Its an ugly hack, but I suspect it will be
be neccessary. I certainly can't reproduce in nsock EVERYTHING you * neccessary. I certainly can't reproduce in nsock EVERYTHING you might want
might want to do with a socket. So I'm offering you this function * to do with a socket. So I'm offering you this function to obtain the socket
to obtain the socket descriptor which is (usually) wrapped in a * descriptor which is (usually) wrapped in a nsock_iod). You can do
nsock_iod). You can do "reasonable" things with it, like setting * "reasonable" things with it, like setting socket receive buffers. But don't
socket receive buffers. But don't create havok by closing the * create havok by closing the descriptor! If the descriptor you get back is
descriptor! If the descriptor you get back is -1, the iod does not * -1, the iod does not currently possess a valid descriptor */
currently possess a valid descriptor */
int nsi_getsd(nsock_iod nsiod); int nsi_getsd(nsock_iod nsiod);
/* Returns the ID of an nsock_iod . This ID is always unique amongst /* Returns the ID of an nsock_iod . This ID is always unique amongst ids for a
ids for a given nspool (unless you blow through billions of them). */ * given nspool (unless you blow through billions of them). */
unsigned long nsi_id(nsock_iod nsockiod); unsigned long nsi_id(nsock_iod nsockiod);
/*Returns Packets received in bytes */ /* Returns Packets received in bytes */
unsigned long nsi_get_read_count(nsock_iod nsockiod); unsigned long nsi_get_read_count(nsock_iod nsockiod);
/*Returns Packets sent in bytes */ /* Returns Packets sent in bytes */
unsigned long nsi_get_write_count(nsock_iod nsockiod); unsigned long nsi_get_write_count(nsock_iod nsockiod);
/* Returns 1 if an NSI is communicating via SSL, 0 otherwise */ /* Returns 1 if an NSI is communicating via SSL, 0 otherwise */
int nsi_checkssl(nsock_iod nsockiod); int nsi_checkssl(nsock_iod nsockiod);
/* Returns the remote peer port (or -1 if unavailable). Note the /* Returns the remote peer port (or -1 if unavailable). Note the return value
return value is a whole int so that -1 can be distinguished from * is a whole int so that -1 can be distinguished from 65535. Port is returned
65535. Port is returned in host byte order. */ * in host byte order. */
int nsi_peerport(nsock_iod nsiod); int nsi_peerport(nsock_iod nsiod);
/* Sets the local address to bind to before connect() */ /* Sets the local address to bind to before connect() */
int nsi_set_localaddr(nsock_iod nsi, struct sockaddr_storage *ss, size_t sslen); int nsi_set_localaddr(nsock_iod nsi, struct sockaddr_storage *ss, size_t sslen);
/* Sets IPv4 options to apply before connect(). It makes a copy of the /* Sets IPv4 options to apply before connect(). It makes a copy of the options,
* options, so you can free() yours if necessary. This copy is freed * so you can free() yours if necessary. This copy is freed when the iod is
* when the iod is destroyed * destroyed */
*/
int nsi_set_ipoptions(nsock_iod nsi, void *ipopts, size_t ipoptslen); int nsi_set_ipoptions(nsock_iod nsi, void *ipopts, size_t ipoptslen);
/* Returns that host/port/protocol information for the last /* Returns that host/port/protocol information for the last communication (or
communication (or comm. attempt) this nsi has been involved with. * comm. attempt) this nsi has been involved with. By "involved" with I mean
By "involved" with I mean interactions like establishing (or trying * interactions like establishing (or trying to) a connection or sending a UDP
to) a connection or sending a UDP datagram through an unconnected * datagram through an unconnected nsock_iod. AF is the address family (AF_INET
nsock_iod. AF is the address family (AF_INET or AF_INET6), Protocol * or AF_INET6), Protocol is IPPROTO_TCP or IPPROTO_UDP. Pass NULL for
is IPPROTO_TCP or IPPROTO_UDP. Pass NULL for information you do * information you do not need. If ANY of the information you requested is not
not need. If ANY of the information you requested is not * available, 0 will be returned and the unavailable sockets are zeroed. If
available, 0 will be returned and the unavailable sockets are * protocol or af is requested but not available, it will be set to -1 (and 0
zeroed. If protocol or af is requested but not available, it will * returned). The pointers you pass in must be NULL or point to allocated
be set to -1 (and 0 returned). The pointers you pass in must be * address space. The sockaddr members should actually be sockaddr_storage,
NULL or point to allocated address space. The sockaddr members * sockaddr_in6, or sockaddr_in with the socklen of them set appropriately (eg
should actually be sockaddr_storage, sockaddr_in6, or sockaddr_in * sizeof(sockaddr_storage) if that is what you are passing). */
with the socklen of them set appropriately (eg int nsi_getlastcommunicationinfo(nsock_iod ms_iod, int *protocol, int *af, struct sockaddr *local, struct sockaddr *remote, size_t socklen);
sizeof(sockaddr_storage) if that is what you are passing). */
int nsi_getlastcommunicationinfo(nsock_iod ms_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 /* Set the hostname of the remote host, for when that matters. This is currently
currently only used for Server Name Indication in SSL connections. */ * only used for Server Name Indication in SSL connections. */
int nsi_set_hostname(nsock_iod nsi, const char *hostname); int nsi_set_hostname(nsock_iod nsi, const char *hostname);
/* EVENT CREATION FUNCTIONS -- These functions request asynchronous /* EVENT CREATION FUNCTIONS
notification of completion of an event. The handler will never be * ---
synchronously called back during the event creation call (that * These functions request asynchronous
causes too many hard to debug errors and plus we don't want people * notification of completion of an event. The handler will never be
to have to deal with callbacks until they actually call nsock_loop */ * 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: /* These functions generally take a common 5 initial parameters:
*
nsock_pool mst -- the is the nsock_pool describing the events you have * nsock_pool mst:
scheduled, etc * 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 * nsock_iod nsiod:
request. Note that timer events don't have this argument since * The I/O Descriptor that should be used in the request. Note that timer
they don't use an iod. You can obtain it in the callback from * events don't have this argument since they don't use an iod. You can
the nsock_event. * obtain it in the callback from the nsock_event.
*
nsock_ev_handler handler -- This is the function you want the * nsock_ev_handler handler:
system to call when your event is triggered (or times out, or * This is the function you want the system to call when your event is
hits an error, etc.). The function should be of this form: * triggered (or times out, or hits an error, etc.). The function should be
void funcname(nsock_pool nsp, nsock_event nse, void *userdata) * of this form: void funcname(nsock_pool nsp, nsock_event nse, void *userdata)
*
int timeout_msecs -- The timeout for the request in milliseconds. * int timeout_msecs:
If the request hasn't completed (or in a few cases started) * The timeout for the request in milliseconds. If the request hasn't
within the timeout specified, the handler will be called with * completed (or in a few cases started) within the timeout specified, the
a TIMEOUT status and the request will be aborted. * 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 * void *userdata:
that pointer here. If you don't want one, just pass NULL. * 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
These functions return an nsock_event_id which can be used to cancel * pass NULL.
the event if neccessary. *
*/ * These functions return an nsock_event_id which can be used to cancel the
* event if neccessary.
*/
typedef void (*nsock_ev_handler)(nsock_pool, nsock_event, void *); typedef void (*nsock_ev_handler)(nsock_pool, nsock_event, void *);
/* Initialize an unconnected UDP socket. */ /* Initialize an unconnected UDP socket. */
int nsock_setup_udp(nsock_pool nsp, nsock_iod ms_iod, int af); int nsock_setup_udp(nsock_pool nsp, nsock_iod ms_iod, int af);
/* Request a TCP connection to another system (by IP address). The /* Request a TCP connection to another system (by IP address). The in_addr is
in_addr is normal network byte order, but the port number should be * normal network byte order, but the port number should be given in HOST BYTE
given in HOST BYTE ORDER. ss should be a sockaddr_storage, * ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as
sockaddr_in6, or sockaddr_in as appropriate (just like what you * appropriate (just like what you would pass to connect). sslen should be the
would pass to connect). sslen should be the sizeof the structure * sizeof the structure you are passing in. */
you are passing in. */ nsock_event_id nsock_connect_tcp(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs,
nsock_event_id nsock_connect_tcp(nsock_pool nsp, nsock_iod nsiod, void *userdata, struct sockaddr *ss, size_t sslen, unsigned short port);
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 /* Request an SCTP association to another system (by IP address). The in_addr is
in_addr is normal network byte order, but the port number should be * normal network byte order, but the port number should be given in HOST BYTE
given in HOST BYTE ORDER. ss should be a sockaddr_storage, * ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as
sockaddr_in6, or sockaddr_in as appropriate (just like what you * appropriate (just like what you would pass to connect). sslen should be the
would pass to connect). sslen should be the sizeof the structure * sizeof the structure you are passing in. */
you are passing in. */ nsock_event_id nsock_connect_sctp(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs,
nsock_event_id nsock_connect_sctp(nsock_pool nsp, nsock_iod nsiod, void *userdata, struct sockaddr *ss, size_t sslen, unsigned short port);
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 /* Request a UDP "connection" to another system (by IP address). The in_addr is
in_addr is normal network byte order, but the port number should be * normal network byte order, but the port number should be given in HOST BYTE
given in HOST BYTE ORDER. Since this is UDP, no packets are * ORDER. Since this is UDP, no packets are actually sent. The destination IP
actually sent. The destination IP and port are just associated * and port are just associated with the nsiod (an actual OS connect() call is
with the nsiod (an actual OS connect() call is made). You can then * made). You can then use the normal nsock write calls on the socket. There
use the normal nsock write calls on the socket. There is no * is no timeout since this call always calls your callback at the next
timeout since this call always calls your callback at the next * opportunity. The advantages to having a connected UDP socket (as opposed to
opportunity. The advantages to having a connected UDP socket (as * just specifying an address with sendto() are that we can now use a consistent
opposed to just specifying an address with sendto() are that we can * set of write/read calls for TCP/UDP, received packets from the non-partner
now use a consistent set of write/read calls for TCP/UDP, received * are automatically dropped by the OS, and the OS can provide asynchronous
packets from the non-partner are automatically dropped by the OS, * errors (see Unix Network Programming pp224). ss should be a
and the OS can provide asynchronous errors (see Unix Network * sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate (just like what
Programming pp224). ss should be a sockaddr_storage, * you would pass to connect). sslen should be the sizeof the structure you are
sockaddr_in6, or sockaddr_in as appropriate (just like what you * passing in. */
would pass to connect). sslen should be the sizeof the structure nsock_event_id nsock_connect_udp(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, void *userdata,
you are passing in. */ struct sockaddr *ss, size_t sslen, unsigned short port);
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 /* Request an SSL over TCP/SCTP connection to another system (by IP address).
address). The in_addr is normal network byte order, but the port * The in_addr is normal network byte order, but the port number should be given
number should be given in HOST BYTE ORDER. This function will call * in HOST BYTE ORDER. This function will call back only after it has made the
back only after it has made the connection AND done the initial * connection AND done the initial SSL negotiation. From that point on, you use
SSL negotiation. From that point on, you use the normal read/write * the normal read/write calls and decryption will happen transparently. ss
calls and decryption will happen transparently. ss should be a * should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate
sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate (just * (just like what you would pass to connect). sslen should be the sizeof the
like what you would pass to connect). sslen should be the sizeof * structure you are passing in. */
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,
nsock_event_id nsock_connect_ssl(nsock_pool nsp, nsock_iod nsiod, void *userdata, struct sockaddr *ss, size_t sslen, int proto, unsigned short port, nsock_ssl_session ssl_session);
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. /* Request ssl connection over already established TCP/SCTP connection. nsiod
nsiod must be socket that is already connected to target * must be socket that is already connected to target using nsock_connect_tcp or
using nsock_connect_tcp or nsock_connect_sctp. * nsock_connect_sctp. All parameters have the same meaning as in
All parameters have the same meaning as in 'nsock_connect_ssl' */ * 'nsock_connect_ssl' */
nsock_event_id nsock_reconnect_ssl(nsock_pool nsp, nsock_iod nsiod, nsock_event_id nsock_reconnect_ssl(nsock_pool nsp, nsock_iod nsiod,
nsock_ev_handler handler, int timeout_msecs, nsock_ev_handler handler, int timeout_msecs, void *userdata, nsock_ssl_session ssl_session);
void *userdata, nsock_ssl_session ssl_session);
/* Read up to nlines lines (terminated with \n, which of course /* Read up to nlines lines (terminated with \n, which of course inclues \r\n),
inclues \r\n), or until EOF, or until the timeout, whichever comes * or until EOF, or until the timeout, whichever comes first. Note that
first. Note that NSE_STATUS_SUCCESS will be returned in the case * NSE_STATUS_SUCCESS will be returned in the case of EOF or tiemout if at least
of EOF or tiemout if at least 1 char has been read. Also note that * 1 char has been read. Also note that you may get more than 'nlines' back --
you may get more than 'nlines' back -- we just stop once "at least" * we just stop once "at least" 'nlines' is read */
'nlines' is read */
nsock_event_id nsock_readlines(nsock_pool nsp, nsock_iod nsiod, nsock_event_id nsock_readlines(nsock_pool nsp, nsock_iod nsiod,
nsock_ev_handler handler, int timeout_msecs, nsock_ev_handler handler, int timeout_msecs, void *userdata, int nlines);
void *userdata, int nlines);
/* Same as above, except it tries to read at least 'nbytes' instead of /* Same as above, except it tries to read at least 'nbytes' instead of 'nlines'. */
'nlines'. */
nsock_event_id nsock_readbytes(nsock_pool nsp, nsock_iod nsiod, nsock_event_id nsock_readbytes(nsock_pool nsp, nsock_iod nsiod,
nsock_ev_handler handler, int timeout_msecs, nsock_ev_handler handler, int timeout_msecs, void *userdata, int nbytes);
void *userdata, int nbytes);
/* The simplest read function -- returns NSE_STATUS_SUCCESS when it /* The simplest read function -- returns NSE_STATUS_SUCCESS when it reads
reads anything, otherwise it returns timeout, eof, or error as * anything, otherwise it returns timeout, eof, or error as appropriate */
appropriate */ nsock_event_id nsock_read(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs, void *userdata);
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 */ /* 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_event_id nsock_write(nsock_pool nsp, nsock_iod nsiod,
nsock_ev_handler handler, int timeout_msecs, nsock_ev_handler handler, int timeout_msecs, void *userdata, const char *data, int datalen);
void *userdata, const char *data, int datalen);
nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod, nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
nsock_ev_handler handler, int timeout_msecs, void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port, const char *data, int datalen);
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 */ /* 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_event_id nsock_printf(nsock_pool nsp, nsock_iod nsiod,
nsock_ev_handler handler, int timeout_msecs, nsock_ev_handler handler, int timeout_msecs, void *userdata, char *format, ... );
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. */ /* Send back an NSE_TYPE_TIMER after the number of milliseconds specified. Of
nsock_event_id nsock_timer_create(nsock_pool nsp, nsock_ev_handler handler, * course it can also return due to error, cancellation, etc. */
int timeout_msecs, void *userdata); 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 /* Cancel an event (such as a timer or read request). If notify is nonzero, the
nonzero, the requester will be sent an event CANCELLED status back to * requester will be sent an event CANCELLED status back to the given handler.
the given handler. But in some cases there is no need to do this * But in some cases there is no need to do this (like if the function deleting
(like if the function deleting it is the one which created it), in * it is the one which created it), in which case 0 can be passed to skip the
which case 0 can be passed to skip the step. This function returns * step. This function returns zero if the event is not found, nonzero
zero if the event is not found, nonzero otherwise */ * otherwise */
int nsock_event_cancel(nsock_pool ms_pool, nsock_event_id id, int notify ); 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 /* Grab the latest time as recorded by the nsock library, which does so at least
so at least once per event loop (in main_loop). Not only does this * once per event loop (in main_loop). Not only does this function (generally)
function (generally) avoid a system call, but in many circumstances * avoid a system call, but in many circumstances it is better to use nsock's
it is better to use nsock's time rather than the system time. If * time rather than the system time. If nsock has never obtained the time when
nsock has never obtained the time when you call it, it will do so * you call it, it will do so before returning */
before returning */
const struct timeval *nsock_gettimeofday(); const struct timeval *nsock_gettimeofday();
#ifdef HAVE_PCAP #ifdef HAVE_PCAP
/* /* Open pcap device and connect it to nsp. Other parameters have the
* Open pcap device and connect it to nsp. Other parameters have the
* same meaning as for pcap_open_live in pcap(3). * same meaning as for pcap_open_live in pcap(3).
* device : pcap-style device name *
* snaplen : size of packet to be copied to handler * device: pcap-style device name
* promisc : whether to open device in promiscous mode * snaplen: size of packet to be copied to handler
* bpf_fmt : berkeley filter * promisc: whether to open device in promiscous mode
* bpf_fmt: berkeley filter
*
* return value: NULL if everything was okay, or error string if error occurred * return value: NULL if everything was okay, or error string if error occurred
* [sorry Fyodor for breaking the API, but it's just simpler] * [sorry Fyodor for breaking the API, but it's just simpler]
* */ * */
char *nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod, char *nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod, const char *pcap_device, int snaplen, int promisc, const char *bpf_fmt, ...);
const char *pcap_device, int snaplen, int promisc,
const char *bpf_fmt, ...);
/* /* Requests exacly one packet to be captured.from pcap.See nsock_read() for parameters description. */
* Requests exacly one packet to be captured.from pcap. nsock_event_id nsock_pcap_read_packet(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs, void *userdata);
* 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 succesfull receiving of packet
* Gets packet data. This should be called after succesfull receiving of packet
* to get packet. If you're not interested in some values, just pass NULL * to get packet. If you're not interested in some values, just pass NULL
* instead of valid pointer. * instead of valid pointer.
* l3_data is just after l2_data in buffer. Feel free to treat l2_data as one * l3_data is just after l2_data in buffer. Feel free to treat l2_data as one
@@ -585,9 +536,7 @@ nsock_event_id nsock_pcap_read_packet(nsock_pool nsp, nsock_iod nsiod,
* As a result you'll get longer times than you should, but it's safer to * As a result you'll get longer times than you should, but it's safer to
* think that host is a bit further. * think that host is a bit further.
* */ * */
void nse_readpcap(nsock_event nsee, void nse_readpcap(nsock_event nsee, const unsigned char **l2_data, size_t *l2_len, const unsigned char **l3_data, size_t *l3_len,
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); size_t *packet_len, struct timeval *ts);
/* Well. Just pcap-style datalink. Like DLT_EN10MB or DLT_SLIP. Check in pcap(3) manpage. */ /* Well. Just pcap-style datalink. Like DLT_EN10MB or DLT_SLIP. Check in pcap(3) manpage. */
@@ -604,11 +553,3 @@ int nsi_is_pcap(nsock_iod nsiod);
#endif /* NSOCK_H */ #endif /* NSOCK_H */

View File

@@ -74,3 +74,6 @@
#undef HAVE_SYS_IOCTL_H #undef HAVE_SYS_IOCTL_H
#undef HAVE_SSL_SET_TLSEXT_HOST_NAME #undef HAVE_SSL_SET_TLSEXT_HOST_NAME
#undef HAVE_EPOLL

View File

@@ -182,12 +182,15 @@
</Lib> </Lib>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\engine_epoll.c" />
<ClCompile Include="src\engine_select.c" />
<ClCompile Include="src\error.c" /> <ClCompile Include="src\error.c" />
<ClCompile Include="src\filespace.c" /> <ClCompile Include="src\filespace.c" />
<ClCompile Include="src\gh_list.c" /> <ClCompile Include="src\gh_list.c" />
<ClCompile Include="src\netutils.c" /> <ClCompile Include="src\netutils.c" />
<ClCompile Include="src\nsock_connect.c" /> <ClCompile Include="src\nsock_connect.c" />
<ClCompile Include="src\nsock_core.c" /> <ClCompile Include="src\nsock_core.c" />
<ClCompile Include="src\nsock_engines.c" />
<ClCompile Include="src\nsock_event.c" /> <ClCompile Include="src\nsock_event.c" />
<ClCompile Include="src\nsock_iod.c" /> <ClCompile Include="src\nsock_iod.c" />
<ClCompile Include="src\nsock_pcap.c" /> <ClCompile Include="src\nsock_pcap.c" />

View File

@@ -27,9 +27,9 @@ NBASEDIR=@NBASEDIR@
TARGET = libnsock.a TARGET = libnsock.a
SRCS = error.c filespace.c gh_list.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 @COMPAT_SRCS@ SRCS = error.c filespace.c gh_list.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 @COMPAT_SRCS@
OBJS = error.o filespace.o gh_list.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 @COMPAT_OBJS@ OBJS = error.o filespace.o gh_list.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 @COMPAT_OBJS@
DEPS = error.h filespace.h gh_list.h nsock_internal.h netutils.h nsock_pcap.h ../include/nsock.h $(NBASEDIR)/libnbase.a DEPS = error.h filespace.h gh_list.h nsock_internal.h netutils.h nsock_pcap.h ../include/nsock.h $(NBASEDIR)/libnbase.a

648
nsock/src/configure vendored
View File

@@ -1426,6 +1426,52 @@ fi
} # ac_fn_c_try_compile } # ac_fn_c_try_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 ||
$as_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 # ac_fn_c_check_func LINENO FUNC VAR
# ---------------------------------- # ----------------------------------
# Tests whether FUNC exists, setting the cache variable VAR accordingly # Tests whether FUNC exists, setting the cache variable VAR accordingly
@@ -3049,6 +3095,561 @@ if test "x$ac_cv_prog_cc_c89" != xno; then :
fi 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
for ac_func in epoll_create epoll_ctl epoll_wait
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_EPOLL 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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>
#include <sys/types.h>
#include <sys/stat.h>
/* 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_ext=c
ac_cpp='$CPP $CPPFLAGS' ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -3166,53 +3767,6 @@ if ${ac_cv_lib_nsl_gethostent+:} false; then :
else else
ac_check_lib_save_LIBS=$LIBS ac_check_lib_save_LIBS=$LIBS
LIBS="-lnsl $LIBS" LIBS="-lnsl $LIBS"
# 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 ||
$as_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
cat confdefs.h - <<_ACEOF >conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */ /* end confdefs.h. */

View File

@@ -107,6 +107,8 @@ if test "$pcap_enabled" != "no"; then
AC_DEFINE(HAVE_PCAP) AC_DEFINE(HAVE_PCAP)
fi fi
AC_CHECK_FUNCS(epoll_create epoll_ctl epoll_wait, [AC_DEFINE(HAVE_EPOLL)], )
dnl Checks for programs. dnl Checks for programs.
AC_PROG_CC AC_PROG_CC
if test -n "$GCC"; then if test -n "$GCC"; then

396
nsock/src/engine_epoll.c Normal file
View File

@@ -0,0 +1,396 @@
/***************************************************************************
* engine_epoll.c -- epoll(7) based IO engine. *
* *
***********************IMPORTANT NSOCK LICENSE TERMS***********************
* *
* The nsock parallel socket event library is (C) 1999-2011 Insecure.Com *
* 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, Insecure.Com LLC *
* may be willing to sell alternative licenses (contact *
* sales@insecure.com ). *
* *
* As a special exception to the GPL terms, Insecure.Com 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 (none *
* have been found so far). *
* *
* 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 nmap-dev@insecure.org for possible incorporation into the main *
* distribution. By sending these changes to Fyodor or one of the *
* Insecure.Org development mailing lists, it is assumed that you are *
* offering the Nmap Project (Insecure.Com 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"
#if HAVE_PCAP
#include "nsock_pcap.h"
#endif
#define INITIAL_EV_COUNT 128
#define EPOLL_R_FLAGS (EPOLLIN | EPOLLPRI)
#define EPOLL_W_FLAGS EPOLLOUT
#define EPOLL_X_FLAGS (EPOLLERR | EPOLLRDHUP | EPOLLHUP)
/* --- ENGINE INTERFACE PROTOTYPES --- */
static int epoll_init(mspool *nsp);
static void epoll_destroy(mspool *nsp);
static int epoll_iod_register(mspool *nsp, msiod *iod, int ev);
static int epoll_iod_unregister(mspool *nsp, msiod *iod);
static int epoll_iod_modify(mspool *nsp, msiod *iod, int ev_set, int ev_clr);
static int epoll_loop(mspool *nsp, int msec_timeout);
/* ---- ENGINE DEFINITION ---- */
struct io_engine engine_epoll = {
"epoll",
epoll_init,
epoll_destroy,
epoll_iod_register,
epoll_iod_unregister,
epoll_iod_modify,
epoll_loop
};
/* --- INTERNAL PROTOTYPES --- */
static void iterate_through_event_lists(mspool *nsp, int evcount);
/* defined in nsock_core.c */
void process_iod_events(mspool *nsp, msiod *nsi, int ev);
void process_event(mspool *nsp, gh_list *evlist, msevent *nse, int ev);
#if HAVE_PCAP
int pcap_read_on_nonselect(mspool *nsp);
#endif
/* defined in nsock_event.c */
void update_first_events(msevent *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(mspool *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(mspool *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(mspool *nsp, msiod *iod, 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;
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;
if (ev & EV_EXCEPT)
epev.events |= EPOLL_X_FLAGS;
sd = nsi_getsd(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(mspool *nsp, msiod *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 = nsi_getsd(iod);
epoll_ctl(einfo->epfd, EPOLL_CTL_DEL, sd, NULL);
IOD_PROPCLR(iod, IOD_REGISTERED);
}
return 1;
}
int epoll_iod_modify(mspool *nsp, msiod *iod, 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);
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;
if (iod->watched_events & EV_EXCEPT)
epev.events |= EPOLL_X_FLAGS;
sd = nsi_getsd(iod);
epoll_ctl(einfo->epfd, EPOLL_CTL_MOD, sd, &epev);
return 1;
}
int epoll_loop(mspool *nsp, int msec_timeout) {
int results_left;
int event_msecs; /* msecs before an event goes off */
int combined_msecs;
int sock_err = 0;
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 ... */
if (GH_LIST_COUNT(&nsp->active_iods) > einfo->evlen) {
einfo->evlen = GH_LIST_COUNT(&nsp->active_iods) * 2;
einfo->events = (struct epoll_event *)safe_realloc(einfo->events, einfo->evlen * sizeof(struct epoll_event));
}
do {
if (nsp->tracelevel > 6)
nsock_trace(nsp, "wait_for_events");
if (nsp->next_ev.tv_sec == 0)
event_msecs = -1; /* None of the events specified a timeout */
else
event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nsp->next_ev, 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
/* do non-blocking read on pcap devices that doesn't support select()
* If there is anything read, don't do usleep() or select(), just leave this loop */
if (pcap_read_on_nonselect(nsp)) {
/* okay, something was read. */
} else
#endif
{
if (einfo->evlen)
results_left = epoll_wait(einfo->epfd, einfo->events, einfo->evlen, combined_msecs);
else
results_left = 0;
if (results_left == -1)
sock_err = socket_errno();
}
gettimeofday(&nsock_tod, NULL); /* Due to usleep or epoll delay */
} while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occured */
if (results_left == -1 && sock_err != EINTR) {
nsock_trace(nsp, "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 ---- */
/* 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(mspool *nsp, int evcount) {
int n, initial_iod_count;
struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data;
gh_list_elem *current, *next, *last, *timer_last, *last_active = NULL;
msevent *nse;
msiod *nsi;
/* Clear it -- We will find the next event as we go through the list */
nsp->next_ev.tv_sec = 0;
last = GH_LIST_LAST_ELEM(&nsp->active_iods);
timer_last = GH_LIST_LAST_ELEM(&nsp->timer_events);
initial_iod_count = GH_LIST_COUNT(&nsp->active_iods);
for (n = 0; n < evcount; n++) {
int evmask = EV_NONE;
nsi = (msiod *)einfo->events[n].data.ptr;
assert(nsi);
if (nsi->entry_in_nsp_active_iods == last)
last = GH_LIST_ELEM_PREV(nsi->entry_in_nsp_active_iods);
/* generate the corresponding event mask with nsock event flags */
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_READ | EV_WRITE | EV_EXCEPT);
/* process all the pending events for this IOD */
process_iod_events(nsp, nsi, evmask);
if (nsi->state != NSIOD_STATE_DELETED) {
gh_list_move_front(&nsp->active_iods, nsi->entry_in_nsp_active_iods);
if (last_active == NULL)
last_active = nsi->entry_in_nsp_active_iods;
} else {
gh_list_remove_elem(&nsp->active_iods, nsi->entry_in_nsp_active_iods);
gh_list_prepend(&nsp->free_iods, nsi);
}
}
if (evcount < initial_iod_count) {
/* some IODs had no active events and need to be processed */
if (!last_active)
/* either no IOD had events or all IODs were deleted after event processing */
current = GH_LIST_FIRST_ELEM(&nsp->active_iods);
else
/* IODs that had active events were pushed to the beginning of the list, start after them */
current = GH_LIST_ELEM_NEXT(last_active);
} else {
/* all the IODs had events and were therefore processed */
current = NULL;
}
/* cull timeouts amongst the non active IODs */
while (current != NULL && GH_LIST_ELEM_PREV(current) != last) {
msiod *nsi = (msiod *)GH_LIST_ELEM_DATA(current);
if (nsi->state != NSIOD_STATE_DELETED && nsi->events_pending)
process_iod_events(nsp, nsi, EV_NONE);
next = GH_LIST_ELEM_NEXT(current);
if (nsi->state == NSIOD_STATE_DELETED) {
gh_list_remove_elem(&nsp->active_iods, current);
gh_list_prepend(&nsp->free_iods, nsi);
}
current = next;
}
/* iterate through timers */
for (current = GH_LIST_FIRST_ELEM(&nsp->timer_events);
current != NULL && GH_LIST_ELEM_PREV(current) != timer_last; current = next) {
nse = (msevent *)GH_LIST_ELEM_DATA(current);
process_event(nsp, &nsp->timer_events, nse, EV_NONE);
next = GH_LIST_ELEM_NEXT(current);
if (nse->event_done)
gh_list_remove_elem(&nsp->timer_events, current);
}
}
#endif /* HAVE_EPOLL */

409
nsock/src/engine_select.c Normal file
View File

@@ -0,0 +1,409 @@
/***************************************************************************
* engine_select.c -- select(2) based IO engine. *
* *
***********************IMPORTANT NSOCK LICENSE TERMS***********************
* *
* The nsock parallel socket event library is (C) 1999-2011 Insecure.Com *
* 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, Insecure.Com LLC *
* may be willing to sell alternative licenses (contact *
* sales@insecure.com ). *
* *
* As a special exception to the GPL terms, Insecure.Com 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 (none *
* have been found so far). *
* *
* 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 nmap-dev@insecure.org for possible incorporation into the main *
* distribution. By sending these changes to Fyodor or one of the *
* Insecure.Org development mailing lists, it is assumed that you are *
* offering the Nmap Project (Insecure.Com 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"
#if HAVE_PCAP
#include "nsock_pcap.h"
#endif
#ifdef WIN32
#define CHECKED_FD_SET FD_SET
#else
#define CHECKED_FD_SET(fd, set) \
do { \
if ((fd) < FD_SETSIZE) { \
FD_SET((fd), (set)); \
} else { \
fatal("%s:%ld: Attempt to FD_SET fd %d, which is not less than" \
" FD_SETSIZE (%d). Try using a lower parallelism.", \
__FILE__, __LINE__, (fd), FD_SETSIZE); \
} \
} while (0)
#endif
#ifdef WIN32
#define CHECKED_FD_CLR FD_CLR
#else
#define CHECKED_FD_CLR(fd, set) \
do { \
if ((fd) < FD_SETSIZE) { \
FD_CLR((fd), (set)); \
} else { \
fatal("%s:%ld: Attempt to FD_CLR fd %d, which is not less than" \
" FD_SETSIZE (%d). Try using a lower parallelism.", \
__FILE__, __LINE__, (fd), FD_SETSIZE); \
} \
} while (0)
#endif
/* --- ENGINE INTERFACE PROTOTYPES --- */
static int select_init(mspool *nsp);
static void select_destroy(mspool *nsp);
static int select_iod_register(mspool *nsp, msiod *iod, int ev);
static int select_iod_unregister(mspool *nsp, msiod *iod);
static int select_iod_modify(mspool *nsp, msiod *iod, int ev_set, int ev_clr);
static int select_loop(mspool *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
};
/* --- INTERNAL PROTOTYPES --- */
static void iterate_through_event_lists(mspool *nsp);
/* defined in nsock_core.c */
void process_event(mspool *nsp, gh_list *evlist, msevent *nse, int ev);
void process_iod_events(mspool *nsp, msiod *nsi, int ev);
#if HAVE_PCAP
int pcap_read_on_nonselect(mspool *nsp);
#endif
/* defined in nsock_event.c */
void update_first_events(msevent *nse);
extern struct timeval nsock_tod;
/*
* Engine specific data structure
*/
struct select_engine_info {
/* Descriptors from which have pending READ events */
fd_set fds_master_r;
/* Descriptors which we are tryint 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(mspool *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(mspool *nsp) {
assert(nsp->engine_data != NULL);
free(nsp->engine_data);
}
int select_iod_register(mspool *nsp, msiod *iod, int ev) {
assert(!IOD_PROPGET(iod, IOD_REGISTERED));
iod->watched_events = ev;
select_iod_modify(nsp, iod, ev, EV_NONE);
IOD_PROPSET(iod, IOD_REGISTERED);
return 1;
}
int select_iod_unregister(mspool *nsp, msiod *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_results_r);
CHECKED_FD_CLR(iod->sd, &sinfo->fds_results_w);
}
if (sinfo->max_sd == iod->sd)
sinfo->max_sd--;
IOD_PROPCLR(iod, IOD_REGISTERED);
}
return 1;
}
int select_iod_modify(mspool *nsp, msiod *iod, 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;
sd = nsi_getsd(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(mspool *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 {
if (nsp->tracelevel > 6)
nsock_trace(nsp, "wait_for_events");
if (nsp->next_ev.tv_sec == 0)
event_msecs = -1; /* None of the events specified a timeout */
else
event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nsp->next_ev, 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
/* do non-blocking read on pcap devices that doesn't support select()
* If there is anything read, don't do usleep() or select(), just leave this loop */
if (pcap_read_on_nonselect(nsp)) {
/* okay, something was read. */
} else
#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 usleep or select delay */
} while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occured */
if (results_left == -1 && sock_err != EINTR) {
nsock_trace(nsp, "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 ---- */
/* 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(mspool *nsp) {
gh_list_elem *current, *next, *last, *timer_last;
struct select_engine_info *sinfo = (struct select_engine_info *)nsp->engine_data;
/* Clear it -- We will find the next event as we go through the list */
nsp->next_ev.tv_sec = 0;
last = GH_LIST_LAST_ELEM(&nsp->active_iods);
timer_last = GH_LIST_LAST_ELEM(&nsp->timer_events);
for (current = GH_LIST_FIRST_ELEM(&nsp->active_iods);
current != NULL && GH_LIST_ELEM_PREV(current) != last; current = next) {
msiod *nsi = (msiod *)GH_LIST_ELEM_DATA(current);
if (nsi->state != NSIOD_STATE_DELETED && nsi->events_pending) {
int sd, evmask = EV_NONE;
#if HAVE_PCAP
if (nsi->pcap)
sd = ((mspcap *)nsi->pcap)->pcap_desc;
else
#endif
sd = nsi->sd;
if (FD_ISSET(sd, &sinfo->fds_results_r))
evmask |= EV_READ;
if (FD_ISSET(sd, &sinfo->fds_results_w))
evmask |= EV_WRITE;
if (FD_ISSET(sd, &sinfo->fds_results_x))
evmask |= EV_EXCEPT;
process_iod_events(nsp, nsi, evmask);
}
next = GH_LIST_ELEM_NEXT(current);
if (nsi->state == NSIOD_STATE_DELETED) {
gh_list_remove_elem(&nsp->active_iods, current);
gh_list_prepend(&nsp->free_iods, nsi);
}
}
/* iterate through timers */
for (current = GH_LIST_FIRST_ELEM(&nsp->timer_events);
current != NULL && GH_LIST_ELEM_PREV(current) != timer_last; current = next) {
msevent *nse = (msevent *)GH_LIST_ELEM_DATA(current);
process_event(nsp, &nsp->timer_events, nse, EV_NONE);
next = GH_LIST_ELEM_NEXT(current);
if (nse->event_done)
gh_list_remove_elem(&nsp->timer_events, current);
}
}

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* error.c -- a few simple routines for dealing with errors (quitting, * * error.c -- a few simple routines for dealing with errors (quitting, *
* printing error messages, etc. * * printing error messages, etc. *
@@ -59,28 +58,40 @@
#include "error.h" #include "error.h"
void fatal(char *fmt, ...) { void fatal(char *fmt, ...) {
va_list ap;va_start(ap, fmt); va_list ap;
fflush(stdout);vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");va_end(ap); va_start(ap, fmt);
exit(1);} fflush(stdout);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
exit(1);
}
void pfatal(char *fmt, ...) { void pfatal(char *fmt, ...) {
va_list ap;va_start(ap, fmt); va_list ap;
fflush(stdout);
vfprintf(stderr, fmt, ap); va_start(ap, fmt);
fprintf(stderr, ": "); fflush(stdout);
perror(""); vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n"); fprintf(stderr, ": ");
va_end(ap); perror("");
exit(1); fprintf(stderr, "\n");
va_end(ap);
exit(1);
} }
void gh_perror(char *err, ...) { void gh_perror(char *err, ...) {
va_list ap;va_start(ap, err); va_list ap;
fflush(stdout);
vfprintf(stderr, err, ap); va_start(ap, err);
va_end(ap); fflush(stdout);
perror(" "); vfprintf(stderr, err, ap);
fflush(stderr); va_end(ap);
return;
perror(" ");
fflush(stderr);
} }

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* error.h -- a few simple routines for dealing with errors (quitting, * * error.h -- a few simple routines for dealing with errors (quitting, *
* printing error messages, etc. * * printing error messages, etc. *
@@ -76,10 +75,12 @@
#endif #endif
void fatal(char *fmt, ...) __attribute__((noreturn)); void fatal(char *fmt, ...) __attribute__((noreturn));
void myerror(char *fmt, ...); void myerror(char *fmt, ...);
void pfatal(char *fmt, ...) __attribute__((noreturn)); void pfatal(char *fmt, ...) __attribute__((noreturn));
void gh_perror(char *err, ...); void gh_perror(char *err, ...);
#endif /* ERROR_H */ #endif /* ERROR_H */

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* filespace.c -- a simple mechanism for storing dynamic amounts of data * * filespace.c -- a simple mechanism for storing dynamic amounts of data *
* in a simple to use, and quick to append-to structure. * * in a simple to use, and quick to append-to structure. *
@@ -61,51 +60,44 @@
#include <string.h> #include <string.h>
#define FS_INITSIZE_DEFAULT 1024
/* Assumes space for fs has already been allocated */ /* Assumes space for fs has already been allocated */
int filespace_init(struct filespace *fs, int initial_size) { int filespace_init(struct filespace *fs, int initial_size) {
memset(fs, 0, sizeof(struct filespace)); memset(fs, 0, sizeof(struct filespace));
if (initial_size == 0) if (initial_size == 0)
initial_size = 1024; initial_size = FS_INITSIZE_DEFAULT;
fs->current_alloc = initial_size; fs->current_alloc = initial_size;
fs->str = (char *) safe_malloc(fs->current_alloc); fs->str = (char *)safe_malloc(fs->current_alloc);
fs->str[0] = '\0'; fs->str[0] = '\0';
fs->pos = fs->str; fs->pos = fs->str;
return 0; return 0;
} }
/* Used when you want to start over with a filespace you have been
using (it sets the length to zero and the pointers to the beginning
of memory , etc */
int fs_clear(struct filespace *fs) {
fs->current_size = 0;
fs->pos = fs->str;
fs->str[0] = '\0'; /* Not necessary, possible help with debugging */
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;
}
/* Prepend an n-char string to a filespace */ /* Prepend an n-char string to a filespace */
int fs_prepend(char *str, int len, struct filespace *fs) { int fs_prepend(char *str, int len, struct filespace *fs){
char *tmpstr; char *tmpstr;
if (len < 0) return -1; if (len < 0)
if (len == 0) return 0; return -1;
if (len == 0)
return 0;
if (fs->current_alloc - fs->current_size < len + 2) { if (fs->current_alloc - fs->current_size < len + 2) {
fs->current_alloc = (int) (fs->current_alloc * 1.4 + 1 ); fs->current_alloc = (int)(fs->current_alloc * 1.4 + 1);
fs->current_alloc += 100 + len; fs->current_alloc += 100 + len;
tmpstr = (char *) safe_malloc(fs->current_alloc);
tmpstr = (char *)safe_malloc(fs->current_alloc);
memcpy(tmpstr, fs->str, fs->current_size); memcpy(tmpstr, fs->str, fs->current_size);
fs->pos = (fs->pos - fs->str) + tmpstr; fs->pos = (fs->pos - fs->str) + tmpstr;
if (fs->str) free(fs->str); if (fs->str)
free(fs->str);
fs->str = tmpstr; fs->str = tmpstr;
} }
if (fs->current_size > 0) if (fs->current_size > 0)
@@ -117,14 +109,21 @@ if (len == 0) return 0;
return 0; return 0;
} }
/* Used when you want to start over with a filespace you have been using (it
* sets the length to zero and the pointers to the beginning of memory , etc */
int fs_clear(struct filespace *fs) {
fs->current_size = 0;
fs->pos = fs->str;
fs->str[0] = '\0'; /* Not necessary, possible help with debugging */
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;
}

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* filespace.h -- a simple mechanism for storing dynamic amounts of data * * filespace.h -- a simple mechanism for storing dynamic amounts of data *
* in a simple to use, and quick to append-to structure. * * in a simple to use, and quick to append-to structure. *
@@ -83,19 +82,25 @@
struct filespace { struct filespace {
int current_size; int current_size;
int current_alloc; int current_alloc;
char *pos; /* Current position in the filespace */
/* Current position in the filespace */
char *pos;
char *str; char *str;
}; };
/* If you want to express a length, use fscat() */ /* If you want to express a length, use fscat() */
static inline int fs_rputs(const char *str, struct filespace *fs) { static inline int fs_rputs(const char *str, struct filespace *fs) {
char *new_str; char *new_str;
int len = (int) strlen(str); int len;
len = (int)strlen(str);
if (len + fs->current_size + 1 > fs->current_alloc) { if (len + fs->current_size + 1 > fs->current_alloc) {
fs->current_alloc = MAX(fs->current_size * 2, fs->current_size + len + 1000); fs->current_alloc = MAX(fs->current_size * 2, fs->current_size + len + 1000);
new_str = (char *) safe_malloc(fs->current_alloc);
new_str = (char *)safe_malloc(fs->current_alloc);
memcpy(new_str, fs->str, fs->current_size); memcpy(new_str, fs->str, fs->current_size);
fs->pos = (fs->pos - fs->str) + new_str; fs->pos = (fs->pos - fs->str) + new_str;
if (fs->str) if (fs->str)
free(fs->str); free(fs->str);
@@ -104,12 +109,12 @@ static inline int fs_rputs(const char *str, struct filespace *fs) {
memcpy(fs->str + fs->current_size, str, len); memcpy(fs->str + fs->current_size, str, len);
fs->current_size += len; fs->current_size += len;
fs->str[fs->current_size] = '\0'; fs->str[fs->current_size] = '\0';
return 0; return 0;
} }
static inline int fs_rvputs(struct filespace *fs,...) static inline int fs_rvputs(struct filespace *fs,...) {
{
va_list args; va_list args;
const char *x; const char *x;
@@ -118,30 +123,36 @@ static inline int fs_rvputs(struct filespace *fs,...)
x = va_arg(args, const char *); x = va_arg(args, const char *);
if (x == NULL) if (x == NULL)
break; break;
if (fs_rputs(x,fs) == -1) { if (fs_rputs(x,fs) == -1) {
va_end(args); va_end(args);
return -1; return -1;
} }
} }
va_end(args); va_end(args);
return 1; return 1;
} }
/* Concatenate a string to the end of a filespace */ /* Concatenate a string to the end of a filespace */
static inline int fscat(struct filespace *fs, const char *str, int len) { static inline int fscat(struct filespace *fs, const char *str, int len) {
char *tmpstr; char *tmpstr;
if (len < 0) return -1; if (len < 0)
if (len == 0) return 0; return -1;
if (len == 0)
return 0;
/* printf("fscat: current_alloc=%d; current_size=%d; len=%d\n", fs->current_alloc, fs->current_size, len); */ /*
printf("fscat: current_alloc=%d; current_size=%d; len=%d\n", fs->current_alloc, fs->current_size, len);
*/
if (fs->current_alloc - fs->current_size < len + 2) { if (fs->current_alloc - fs->current_size < len + 2) {
fs->current_alloc = (int) (fs->current_alloc * 1.4 + 1 ); fs->current_alloc = (int) (fs->current_alloc * 1.4 + 1 );
fs->current_alloc += 100 + len; fs->current_alloc += 100 + len;
tmpstr = (char *) safe_malloc(fs->current_alloc);
tmpstr = (char *)safe_malloc(fs->current_alloc);
memcpy(tmpstr, fs->str, fs->current_size); memcpy(tmpstr, fs->str, fs->current_size);
fs->pos = (fs->pos - fs->str) + tmpstr; fs->pos = (fs->pos - fs->str) + tmpstr;
if (fs->str) free(fs->str); if (fs->str) free(fs->str);
fs->str = tmpstr; fs->str = tmpstr;
@@ -154,25 +165,30 @@ if (len == 0) return 0;
} }
static inline int fs_rputc(int ch, struct filespace *fs) { static inline int fs_rputc(int ch, struct filespace *fs) {
char s[2]; char s[2];
if (fs->current_size + 2 <= fs->current_alloc) { if (fs->current_size + 2 <= fs->current_alloc) {
fs->str[fs->current_size] = ch; fs->str[fs->current_size] = ch;
fs->current_size++; fs->current_size++;
fs->str[fs->current_size] = '\0'; fs->str[fs->current_size] = '\0';
} /* otherwise we use the ueber-technique of letting fscat handle it ... } else {
umm actually I don't know why we don't do this in all cases ... */ /* otherwise we use the ueber-technique of letting fscat handle it ... umm
else { * actually I don't know why we don't do this in all cases ... */
s[0] = ch; s[0] = ch;
s[1] = '\0'; s[1] = '\0';
fscat(fs, s, 1); fscat(fs, s, 1);
} }
return 0; return 0;
} }
int fs_free(struct filespace *fs);
int filespace_init(struct filespace *fs, int initial_size); int filespace_init(struct filespace *fs, int initial_size);
int fs_clear(struct filespace *fs);
int fs_prepend(char *str, int len, struct filespace *fs); int fs_prepend(char *str, int len, struct filespace *fs);
int fs_clear(struct filespace *fs);
int fs_free(struct filespace *fs);
#endif /* FILESPACE_H */ #endif /* FILESPACE_H */

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* gh_list.c -- a simple doubly-linked list implementation with a very * * gh_list.c -- a simple doubly-linked list implementation with a very *
* heavy focus on efficiency. * * heavy focus on efficiency. *
@@ -69,6 +68,21 @@
#include <strings.h> #include <strings.h>
#endif #endif
#define SAFETY_CHECK_LIST(l) do { \
assert(l); \
assert((l)->magic == GH_LIST_MAGIC); \
assert((l)->count == 0 || ((l)->first && (l)->last)); \
assert((l)->count != 0 || ((l)->first == NULL && (l)->last == NULL)); \
} while (0)
#define SAFETY_CHECK_ELEM(e) do { \
assert(e); \
assert((e)->magic == GH_LIST_MAGIC); \
} while (0)
#ifdef GH_LIST_MAIN #ifdef GH_LIST_MAIN
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
gh_list lists[16]; gh_list lists[16];
@@ -82,13 +96,13 @@ int main(int argc, char *argv[]) {
for(num=25000; num < 50000; num++) { for(num=25000; num < 50000; num++) {
for(i=0; i < 16; i++) { for(i=0; i < 16; i++) {
gh_list_append(&lists[i], (void *) num); gh_list_append(&lists[i], (void *)num);
} }
} }
for(num=24999; num >= 0; num--) { for(num=24999; num >= 0; num--) {
for(i=0; i < 16; i++) { for(i=0; i < 16; i++) {
gh_list_prepend(&lists[i], (void *) num); gh_list_prepend(&lists[i], (void *)num);
} }
} }
@@ -109,13 +123,13 @@ int main(int argc, char *argv[]) {
for(num=24999; num >= 0; num--) { for(num=24999; num >= 0; num--) {
for(i=0; i < 16; i++) { for(i=0; i < 16; i++) {
gh_list_prepend(&lists[i], (void *) num); gh_list_prepend(&lists[i], (void *)num);
} }
} }
for(num=25000; num < 50000; num++) { for(num=25000; num < 50000; num++) {
for(i=0; i < 16; i++) { for(i=0; i < 16; i++) {
gh_list_append(&lists[i], (void *) num); gh_list_append(&lists[i], (void *)num);
} }
} }
@@ -130,13 +144,13 @@ int main(int argc, char *argv[]) {
printf("Done with second set\n"); printf("Done with second set\n");
for(num=25000; num < 50000; num++) { for(num=25000; num < 50000; num++) {
for(i=0; i < 16; i++) { for(i=0; i < 16; i++) {
gh_list_append(&lists[i], (void *) num); gh_list_append(&lists[i], (void *)num);
} }
} }
for(num=24999; num >= 0; num--) { for(num=24999; num >= 0; num--) {
for(i=0; i < 16; i++) { for(i=0; i < 16; i++) {
gh_list_prepend(&lists[i], (void *) num); gh_list_prepend(&lists[i], (void *)num);
} }
} }
@@ -152,13 +166,13 @@ int main(int argc, char *argv[]) {
for(num=24999; num >= 0; num--) { for(num=24999; num >= 0; num--) {
for(i=0; i < 16; i++) { for(i=0; i < 16; i++) {
gh_list_prepend(&lists[i], (void *) num); gh_list_prepend(&lists[i], (void *)num);
} }
} }
for(num=25000; num < 50000; num++) { for(num=25000; num < 50000; num++) {
for(i=0; i < 16; i++) { for(i=0; i < 16; i++) {
gh_list_append(&lists[i], (void *) num); gh_list_append(&lists[i], (void *)num);
} }
} }
@@ -193,10 +207,10 @@ static inline struct gh_list_elem *get_free_buffer(struct gh_list *list) {
if (!list->free) { if (!list->free) {
list->last_alloc *= 2; list->last_alloc *= 2;
list->free = (struct gh_list_elem *) safe_malloc(list->last_alloc * sizeof(struct gh_list_elem)); list->free = (struct gh_list_elem *)safe_malloc(list->last_alloc * sizeof(struct gh_list_elem));
memset(list->free, 0, list->last_alloc * sizeof(struct gh_list_elem)); memset(list->free, 0, list->last_alloc * sizeof(struct gh_list_elem));
list->free->allocated = 1; list->free->allocated = 1;
for(i=0; i < list->last_alloc - 1; i++) { for (i=0; i < list->last_alloc - 1; i++) {
(list->free + i)->next = list->free + i + 1; (list->free + i)->next = list->free + i + 1;
} }
} }
@@ -209,50 +223,58 @@ static inline struct gh_list_elem *get_free_buffer(struct gh_list *list) {
} }
int gh_list_init(gh_list *newlist) { int gh_list_init(gh_list *newlist) {
int i; int i;
if (!newlist) return -1;
newlist->count = 0; if (!newlist)
newlist->first = newlist->last = NULL; return -1;
newlist->last_alloc = 32;
newlist->free = (struct gh_list_elem *) safe_malloc(newlist->last_alloc * sizeof(struct gh_list_elem)); newlist->count = 0;
memset(newlist->free, 0, newlist->last_alloc * sizeof(struct gh_list_elem)); newlist->first = newlist->last = NULL;
newlist->free->allocated = 1; newlist->last_alloc = 16;
for(i=0; i < newlist->last_alloc - 1; i++) { newlist->free = (struct gh_list_elem *)safe_malloc(newlist->last_alloc * sizeof(struct gh_list_elem));
memset(newlist->free, 0, newlist->last_alloc * sizeof(struct gh_list_elem));
newlist->free->allocated = 1;
for (i = 0; i < newlist->last_alloc - 1; i++) {
(newlist->free + i)->next = newlist->free + i + 1; (newlist->free + i)->next = newlist->free + i + 1;
} }
/* Not needed (newlist->free + newlist->last_alloc - 1)->next = NULL */ /* Not needed (newlist->free + newlist->last_alloc - 1)->next = NULL */
#ifndef NDEBUG #ifndef NDEBUG
newlist->magic = GH_LIST_MAGIC; newlist->magic = GH_LIST_MAGIC;
#endif #endif
return 0; return 0;
} }
gh_list_elem *gh_list_append(gh_list *list, void *data) { gh_list_elem *gh_list_append(gh_list *list, void *data) {
gh_list_elem *newelem; gh_list_elem *newelem;
gh_list_elem *oldlast; gh_list_elem *oldlast;
assert(list); SAFETY_CHECK_LIST(list);
assert(list->magic == GH_LIST_MAGIC);
assert(list->count == 0 || (list->first && list->last));
assert(list->count != 0 || (list->first == NULL && list->last == NULL));
newelem = get_free_buffer(list); newelem = get_free_buffer(list);
oldlast = list->last; oldlast = list->last;
if (oldlast) { if (oldlast) {
oldlast->next = newelem; oldlast->next = newelem;
newelem->prev = oldlast; newelem->prev = oldlast;
} else newelem->prev = NULL; } else {
newelem->prev = NULL;
}
newelem->next = NULL; newelem->next = NULL;
newelem->data = data; newelem->data = data;
#ifndef NDEBUG #ifndef NDEBUG
newelem->magic = GH_LIST_MAGIC; newelem->magic = GH_LIST_MAGIC;
#endif #endif
list->count++; list->count++;
list->last = newelem; list->last = newelem;
if (list->count == 1) if (list->count == 1)
list->first = newelem; list->first = newelem;
return newelem; return newelem;
} }
@@ -260,44 +282,79 @@ gh_list_elem *gh_list_prepend(gh_list *list, void *data) {
gh_list_elem *newelem; gh_list_elem *newelem;
gh_list_elem *oldfirst; gh_list_elem *oldfirst;
assert(list); SAFETY_CHECK_LIST(list);
assert(list->magic == GH_LIST_MAGIC);
assert(list->count == 0 || (list->first && list->last));
assert(list->count != 0 || (list->first == NULL && list->last == NULL));
newelem = get_free_buffer(list); newelem = get_free_buffer(list);
oldfirst = list->first; oldfirst = list->first;
if (oldfirst) { if (oldfirst) {
oldfirst->prev = newelem; oldfirst->prev = newelem;
newelem->next = oldfirst; newelem->next = oldfirst;
} else newelem->next = NULL; } else {
newelem->next = NULL;
}
newelem->prev = NULL; newelem->prev = NULL;
newelem->data = data; newelem->data = data;
#ifndef NDEBUG #ifndef NDEBUG
newelem->magic = GH_LIST_MAGIC; newelem->magic = GH_LIST_MAGIC;
#endif #endif
list->count++; list->count++;
list->first = newelem; list->first = newelem;
if (list->count == 1) if (list->count == 1)
list->last = newelem; list->last = newelem;
return newelem;
}
gh_list_elem *gh_list_insert_before(gh_list *list, gh_list_elem *before, void *data) {
gh_list_elem *newelem;
SAFETY_CHECK_LIST(list);
SAFETY_CHECK_ELEM(before);
/* create or reuse a new cell */
newelem = get_free_buffer(list);
newelem->data = data;
newelem->prev = before->prev;
newelem->next = before;
#ifndef NDEBUG
newelem->magic = GH_LIST_MAGIC;
#endif
if (before->prev)
before->prev->next = newelem;
else
list->first = newelem;
before->prev = newelem;
list->count++;
return newelem; return newelem;
} }
void *gh_list_pop(gh_list *list) { void *gh_list_pop(gh_list *list) {
struct gh_list_elem *oldelem; struct gh_list_elem *oldelem;
assert(list);
assert(list->magic == GH_LIST_MAGIC); SAFETY_CHECK_LIST(list);
assert(list->count == 0 || (list->first && list->last));
assert(list->count != 0 || (list->first == NULL && list->last == NULL));
oldelem = list->first; oldelem = list->first;
if (!oldelem) return NULL; if (!oldelem)
return NULL;
list->first = list->first->next; list->first = list->first->next;
if (list->first) if (list->first)
list->first->prev = NULL; list->first->prev = NULL;
list->count--; list->count--;
if (list->count < 2) if (list->count < 2)
list->last = list->first; list->last = list->first;
oldelem->next = list->free; oldelem->next = list->free;
list->free = oldelem; list->free = oldelem;
@@ -308,44 +365,39 @@ int gh_list_free(gh_list *list) {
struct gh_list_elem *current; struct gh_list_elem *current;
char *free_list[32]; char *free_list[32];
int free_index = 0; int free_index = 0;
int i=0; int i = 0;
assert(list); SAFETY_CHECK_LIST(list);
assert(list->magic == GH_LIST_MAGIC);
assert(list->count == 0 || (list->first && list->last));
assert(list->count != 0 || (list->first == NULL && list->last == NULL));
#ifndef NDEBUG #ifndef NDEBUG
list->magic++; list->magic++;
#endif #endif
for(current = list->first; current; current = current->next) {
# ifndef NDEBUG for (current = list->first; current; current = current->next) {
#ifndef NDEBUG
current->magic++; current->magic++;
# endif #endif
if (current->allocated) { if (current->allocated) {
assert(free_index < 32); assert(free_index < 32);
free_list[free_index++] = (char *) current; free_list[free_index++] = (char *)current;
} }
} }
for(current = list->free; current; current = current->next) for (current = list->free; current; current = current->next)
if (current->allocated) { if (current->allocated) {
assert(free_index < 32); assert(free_index < 32);
free_list[free_index++] = (char *) current; free_list[free_index++] = (char *)current;
} }
for(i=0; i < free_index; i++) for (i = 0; i < free_index; i++)
free(free_list[i]); free(free_list[i]);
return 0; return 0;
} }
int gh_list_remove_elem(gh_list *list, gh_list_elem *elem) { int gh_list_remove_elem(gh_list *list, gh_list_elem *elem) {
assert(elem); SAFETY_CHECK_ELEM(elem);
assert(elem->magic == GH_LIST_MAGIC); SAFETY_CHECK_LIST(list);
assert(list);
assert(list->magic == GH_LIST_MAGIC);
assert(list->count == 0 || (list->first && list->last));
assert(list->count != 0 || (list->first == NULL && list->last == NULL));
if (elem->prev) { if (elem->prev) {
elem->prev->next = elem->next; elem->prev->next = elem->next;
@@ -372,26 +424,41 @@ int gh_list_remove_elem(gh_list *list, gh_list_elem *elem) {
return 0; return 0;
} }
int gh_list_move_front(gh_list *list, gh_list_elem *elem) {
SAFETY_CHECK_LIST(list);
SAFETY_CHECK_ELEM(elem);
if (list->first == elem)
return 0;
/* remove element from its current position */
elem->prev->next = elem->next;
if (elem->next) {
elem->next->prev = elem->prev;
} else {
assert(list->last == elem);
list->last = elem->prev;
}
/* add element to the beginning list */
list->first->prev = elem;
elem->next = list->first;
elem->prev = NULL;
list->first = elem;
return 0;
}
int gh_list_remove(gh_list *list, void *data) { int gh_list_remove(gh_list *list, void *data) {
struct gh_list_elem *current; struct gh_list_elem *current;
assert(list); SAFETY_CHECK_LIST(list);
assert(list->magic == GH_LIST_MAGIC);
assert(list->count == 0 || (list->first && list->last));
assert(list->count != 0 || (list->first == NULL && list->last == NULL));
for(current = list->first; current; current = current->next) { for (current = list->first; current; current = current->next) {
if (current->data == data) if (current->data == data)
return gh_list_remove_elem(list, current); return gh_list_remove_elem(list, current);
} }
return -1; return -1;
} }

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* gh_list.h -- a simple doubly-linked list implementation with a very * * gh_list.h -- a simple doubly-linked list implementation with a very *
* heavy focus on efficiency. * * heavy focus on efficiency. *
@@ -75,37 +74,51 @@
/* Take a LIST ELEMENT (not just the data) and return the next one */ /* Take a LIST ELEMENT (not just the data) and return the next one */
#define GH_LIST_ELEM_NEXT(x) ((x)->next) #define GH_LIST_ELEM_NEXT(x) ((x)->next)
/* Same as above but return the previous element */ /* Same as above but return the previous element */
#define GH_LIST_ELEM_PREV(x) ((x)->prev) #define GH_LIST_ELEM_PREV(x) ((x)->prev)
/* Take a LIST (not a list element) and return the first element */ /* Take a LIST (not a list element) and return the first element */
#define GH_LIST_FIRST_ELEM(x) ((x)->first) #define GH_LIST_FIRST_ELEM(x) ((x)->first)
/* Same as above but return the last element */ /* Same as above but return the last element */
#define GH_LIST_LAST_ELEM(x) ((x)->last) #define GH_LIST_LAST_ELEM(x) ((x)->last)
/* Obtain the actual data stored in an element */ /* Obtain the actual data stored in an element */
#define GH_LIST_ELEM_DATA(x) ((x)->data) #define GH_LIST_ELEM_DATA(x) ((x)->data)
/* Obtain the number of elements in a list */ /* Obtain the number of elements in a list */
#define GH_LIST_COUNT(x) ((x)->count) #define GH_LIST_COUNT(x) ((x)->count)
typedef struct gh_list_elem { typedef struct gh_list_elem {
void *data; void *data;
struct gh_list_elem *next; struct gh_list_elem *next;
struct gh_list_elem *prev; struct gh_list_elem *prev;
int allocated; /* nonzero if this element was the first (or only) in a group
that was allocated. This means we can safely free() it as /* nonzero if this element was the first (or only) in a group that was
long as we are OK with freeing others that were freed * allocated. This means we can safely free() it as long as we are OK with
with it ... */ * freeing others that were freed with it ... */
int allocated;
#ifndef NDEBUG #ifndef NDEBUG
unsigned long magic; unsigned long magic;
#endif #endif
} gh_list_elem; } gh_list_elem;
typedef struct gh_list { typedef struct gh_list {
int count; /* Number of elements in the list */ /* Number of elements in the list */
int count;
struct gh_list_elem *first; struct gh_list_elem *first;
struct gh_list_elem *last; struct gh_list_elem *last;
struct gh_list_elem *free; /* Instead of free()ing elements when something is removed from the list, we stick them here
for the next insert. */ /* Instead of free()ing elements when something is removed from the list, we
int last_alloc; /* The number of list elements in the most recent malloc */ * stick them here for the next insert. */
struct gh_list_elem *free;
/* The number of list elements in the most recent malloc */
int last_alloc;
#ifndef NDEBUG #ifndef NDEBUG
unsigned long magic; unsigned long magic;
#endif #endif
@@ -113,12 +126,22 @@ typedef struct gh_list {
int gh_list_init(gh_list *newlist); int gh_list_init(gh_list *newlist);
gh_list_elem *gh_list_append(gh_list *list, void *data); gh_list_elem *gh_list_append(gh_list *list, void *data);
gh_list_elem *gh_list_prepend(gh_list *list, void *data); gh_list_elem *gh_list_prepend(gh_list *list, void *data);
gh_list_elem *gh_list_insert_before(gh_list *list, gh_list_elem *before, void *data);
void *gh_list_pop(gh_list *list); void *gh_list_pop(gh_list *list);
int gh_list_remove(gh_list *list, void *data); int gh_list_remove(gh_list *list, void *data);
int gh_list_free(gh_list *list); int gh_list_free(gh_list *list);
int gh_list_move_front(gh_list *list, gh_list_elem *elem);
int gh_list_remove_elem(gh_list *list, gh_list_elem *elem); int gh_list_remove_elem(gh_list *list, gh_list_elem *elem);
#endif /* GH_LIST_H */ #endif /* GH_LIST_H */

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* netutils.c -- This contains some useful little network/socket related * * netutils.c -- This contains some useful little network/socket related *
* utility functions. * * utility functions. *
@@ -87,17 +86,15 @@
static int netutils_debugging = 0; static int netutils_debugging = 0;
/* maximize the number of file descriptors (including sockets) allowed /* maximize the number of file descriptors (including sockets) allowed for this
for this process and return that maximum value (note -- you better * process and return that maximum value (note -- you better not actually open
not actually open this many -- stdin, stdout, other files opened by * this many -- stdin, stdout, other files opened by libraries you use, etc. all
libraries you use, etc. all count toward this limit. Leave a * count toward this limit. Leave a little slack */
little slack */ int maximize_fdlimit(void) {
int maximize_fdlimit() {
#ifndef WIN32 #ifndef WIN32
struct rlimit r;
struct rlimit r; static int maxfds = -1;
static int maxfds = -1;
if (maxfds > 0) if (maxfds > 0)
return maxfds; return maxfds;
@@ -106,22 +103,31 @@ static int maxfds = -1;
if (!getrlimit(RLIMIT_NOFILE, &r)) { if (!getrlimit(RLIMIT_NOFILE, &r)) {
r.rlim_cur = r.rlim_max; r.rlim_cur = r.rlim_max;
if (setrlimit(RLIMIT_NOFILE, &r)) if (setrlimit(RLIMIT_NOFILE, &r))
if (netutils_debugging) perror("setrlimit RLIMIT_NOFILE failed"); if (netutils_debugging)
perror("setrlimit RLIMIT_NOFILE failed");
if (!getrlimit(RLIMIT_NOFILE, &r)) { if (!getrlimit(RLIMIT_NOFILE, &r)) {
maxfds = r.rlim_cur; maxfds = r.rlim_cur;
return maxfds; return maxfds;
} else return 0; } else {
return 0;
}
} }
#endif #endif
#if(defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE)) #if(defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE))
if (!getrlimit(RLIMIT_OFILE, &r)) { if (!getrlimit(RLIMIT_OFILE, &r)) {
r.rlim_cur = r.rlim_max; r.rlim_cur = r.rlim_max;
if (setrlimit(RLIMIT_OFILE, &r)) if (setrlimit(RLIMIT_OFILE, &r))
if (netutils_debugging) perror("setrlimit RLIMIT_OFILE failed"); if (netutils_debugging)
perror("setrlimit RLIMIT_OFILE failed");
if (!getrlimit(RLIMIT_OFILE, &r)) { if (!getrlimit(RLIMIT_OFILE, &r)) {
maxfds = r.rlim_cur; maxfds = r.rlim_cur;
return maxfds; return maxfds;
} else return 0; } else {
return 0;
}
} }
#endif #endif
#endif /* !WIN32 */ #endif /* !WIN32 */

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* netutils.h -- This contains some useful little network/socket related * * netutils.h -- This contains some useful little network/socket related *
* utility functions. * * utility functions. *
@@ -70,12 +69,11 @@
#include "nbase_winunix.h" #include "nbase_winunix.h"
#endif #endif
/* maximize the number of file descriptors (including sockets) allowed /* Maximize the number of file descriptors (including sockets) allowed for this
for this process and return that maximum value (note -- you better * process and return that maximum value (note -- you better not actually open
not actually open this many -- stdin, stdout, other files opened by * this many -- stdin, stdout, other files opened by libraries you use, etc. all
libraries you use, etc. all count toward this limit. Leave a * count toward this limit. Leave a little slack */
little slack */ int maximize_fdlimit(void);
int maximize_fdlimit();
#endif /* NETUTILS_H */ #endif /* NETUTILS_H */

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* nsock_connect.c -- This contains the functions for requesting TCP * * nsock_connect.c -- This contains the functions for requesting TCP *
* connections from the nsock parallel socket event library * * connections from the nsock parallel socket event library *
@@ -65,15 +64,14 @@
extern struct timeval nsock_tod; extern struct timeval nsock_tod;
/* Create the actual socket (nse->iod->sd) underlying the iod. This /* Create the actual socket (nse->iod->sd) underlying the iod. This unblocks the
unblocks the socket, binds to the localaddr address, sets IP options, * socket, binds to the localaddr address, sets IP options, and sets the
and sets the broadcast flag. Trying to change these functions after * broadcast flag. Trying to change these functions after making this call will
making this call will not have an effect. This function needs to be * not have an effect. This function needs to be called before you try to read
called before you try to read or write on the iod. */ * or write on the iod. */
static int nsock_make_socket(mspool *ms, msiod *iod, int family, int proto) { static int nsock_make_socket(mspool *ms, msiod *iod, int family, int proto) {
/* inheritable_socket is from nbase */ /* inheritable_socket is from nbase */
iod->sd = (int) inheritable_socket(family, iod->sd = (int)inheritable_socket(family, (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM, proto);
(proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM, proto);
if (iod->sd == -1) { if (iod->sd == -1) {
perror("Socket troubles"); perror("Socket troubles");
return -1; return -1;
@@ -85,34 +83,32 @@ static int nsock_make_socket(mspool *ms, msiod *iod, int family, int proto) {
if (iod->locallen) { if (iod->locallen) {
int one = 1; int one = 1;
setsockopt(iod->sd, SOL_SOCKET, SO_REUSEADDR, (const char *) &one, sizeof(one));
if (bind(iod->sd, (struct sockaddr *) &iod->local, (int) iod->locallen) == -1) { setsockopt(iod->sd, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, sizeof(one));
if (bind(iod->sd, (struct sockaddr *)&iod->local, (int) iod->locallen) == -1) {
if (ms->tracelevel > 0) if (ms->tracelevel > 0)
nsock_trace(ms, "Bind to %s failed (IOD #%li)", nsock_trace(ms, "Bind to %s failed (IOD #%li)",
inet_ntop_ez(&iod->local, iod->locallen), iod->id); inet_ntop_ez(&iod->local, iod->locallen), iod->id);
} }
} }
if (iod->ipoptslen && family == AF_INET) { if (iod->ipoptslen && family == AF_INET) {
if (setsockopt(iod->sd, IPPROTO_IP, IP_OPTIONS, (const char *) iod->ipopts, iod->ipoptslen) == -1) { if (setsockopt(iod->sd, IPPROTO_IP, IP_OPTIONS, (const char *)iod->ipopts, iod->ipoptslen) == -1) {
if (ms->tracelevel > 0) if (ms->tracelevel > 0)
nsock_trace(ms, "Setting of IP options failed (IOD #%li)", iod->id); nsock_trace(ms, "Setting of IP options failed (IOD #%li)", iod->id);
} }
} }
if (ms->broadcast) { if (ms->broadcast) {
if (setsockopt(iod->sd, SOL_SOCKET, SO_BROADCAST, (const char *)&(ms->broadcast), sizeof(int)) == -1) { if (setsockopt(iod->sd, SOL_SOCKET, SO_BROADCAST, (const char *)&(ms->broadcast), sizeof(int)) == -1) {
if (ms->tracelevel > 0) if (ms->tracelevel > 0)
nsock_trace(ms, "Setting of SO_BROADCAST failed (IOD #%li)", iod->id); nsock_trace(ms, "Setting of SO_BROADCAST failed (IOD #%li)", iod->id);
} }
} }
return iod->sd; return iod->sd;
} }
int nsock_setup_udp(nsock_pool nsp, nsock_iod ms_iod, int af) { int nsock_setup_udp(nsock_pool nsp, nsock_iod ms_iod, int af) {
mspool *ms = (mspool *) nsp; mspool *ms = (mspool *)nsp;
msiod *nsi = (msiod *) ms_iod; msiod *nsi = (msiod *)ms_iod;
assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);
@@ -127,21 +123,22 @@ int nsock_setup_udp(nsock_pool nsp, nsock_iod ms_iod, int af) {
return nsi->sd; return nsi->sd;
} }
/* This does the actual logistics of requesting a TCP connection. It is /* This does the actual logistics of requesting a TCP connection. It is shared
* shared by nsock_connect_tcp and nsock_connect_ssl */ * by nsock_connect_tcp and nsock_connect_ssl */
void nsock_connect_internal(mspool *ms, msevent *nse, int proto, void nsock_connect_internal(mspool *ms, msevent *nse, int proto, struct sockaddr_storage *ss, size_t sslen,
struct sockaddr_storage *ss, size_t sslen, unsigned short port) {
unsigned short port)
{ struct sockaddr_in *sin = (struct sockaddr_in *)ss;
struct sockaddr_in *sin = (struct sockaddr_in *) ss;
#if HAVE_IPV6 #if HAVE_IPV6
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ss; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss;
#endif #endif
msiod *iod = nse->iod; msiod *iod = nse->iod;
/* Now it is time to actually attempt the connection */ /* Now it is time to actually attempt the connection */
if (nsock_make_socket(ms, iod, ss->ss_family, proto) == -1) { if (nsock_make_socket(ms, iod, ss->ss_family, proto) == -1) {
nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = socket_errno(); nse->event_done = 1;
nse->status = NSE_STATUS_ERROR;
nse->errnum = socket_errno();
} else { } else {
if (sin->sin_family == AF_INET) { if (sin->sin_family == AF_INET) {
sin->sin_port = htons(port); sin->sin_port = htons(port);
@@ -155,10 +152,11 @@ void nsock_connect_internal(mspool *ms, msevent *nse, int proto,
} }
assert(sslen <= sizeof(iod->peer)); assert(sslen <= sizeof(iod->peer));
if (&iod->peer != ss)
memcpy(&iod->peer, ss, sslen); memcpy(&iod->peer, ss, sslen);
iod->peerlen = sslen; iod->peerlen = sslen;
if (connect(iod->sd, (struct sockaddr *) ss, sslen) == -1) { if (connect(iod->sd, (struct sockaddr *)ss, sslen) == -1) {
int err = socket_errno(); int err = socket_errno();
if (proto == IPPROTO_UDP || (err != EINPROGRESS && err != EAGAIN)) { if (proto == IPPROTO_UDP || (err != EINPROGRESS && err != EAGAIN)) {
@@ -167,27 +165,23 @@ void nsock_connect_internal(mspool *ms, msevent *nse, int proto,
nse->errnum = err; nse->errnum = err;
} }
} }
/* The callback handle_connect_result handles the connection once it /* The callback handle_connect_result handles the connection once it completes. */
completes. */
} }
} }
/* Request a TCP connection to another system (by IP address). The /* Request a TCP connection to another system (by IP address). The in_addr is
in_addr is normal network byte order, but the port number should be * normal network byte order, but the port number should be given in HOST BYTE
given in HOST BYTE ORDER. ss should be a sockaddr_storage, * ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as
sockaddr_in6, or sockaddr_in as appropriate (just like what you * appropriate (just like what you would pass to connect). sslen should be the
would pass to connect). sslen should be the sizeof the structure * sizeof the structure you are passing in. */
you are passing in. */ nsock_event_id nsock_connect_tcp(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
nsock_event_id nsock_connect_tcp(nsock_pool nsp, nsock_iod ms_iod, void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port) {
nsock_ev_handler handler, int timeout_msecs,
void *userdata, struct sockaddr *saddr,
size_t sslen, unsigned short port) {
msiod *nsi = (msiod *) ms_iod; msiod *nsi = (msiod *)ms_iod;
mspool *ms = (mspool *) nsp; mspool *ms = (mspool *)nsp;
msevent *nse; msevent *nse;
struct sockaddr_storage *ss = (struct sockaddr_storage *) saddr; struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;
assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);
@@ -208,21 +202,18 @@ nsock_event_id nsock_connect_tcp(nsock_pool nsp, nsock_iod ms_iod,
return nse->id; return nse->id;
} }
/* Request an SCTP association to another system (by IP address). The /* Request an SCTP association to another system (by IP address). The in_addr
in_addr is normal network byte order, but the port number should be * is normal network byte order, but the port number should be given in HOST
given in HOST BYTE ORDER. ss should be a sockaddr_storage, * BYTE ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as
sockaddr_in6, or sockaddr_in as appropriate (just like what you * appropriate (just like what you would pass to connect). sslen should be the
would pass to connect). sslen should be the sizeof the structure * sizeof the structure you are passing in. */
you are passing in. */ nsock_event_id nsock_connect_sctp(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
nsock_event_id nsock_connect_sctp(nsock_pool nsp, nsock_iod ms_iod, void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port) {
nsock_ev_handler handler, int timeout_msecs,
void *userdata, struct sockaddr *saddr,
size_t sslen, unsigned short port) {
msiod *nsi = (msiod *) ms_iod; msiod *nsi = (msiod *)ms_iod;
mspool *ms = (mspool *) nsp; mspool *ms = (mspool *)nsp;
msevent *nse; msevent *nse;
struct sockaddr_storage *ss = (struct sockaddr_storage *) saddr; struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;
assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);
@@ -243,28 +234,24 @@ nsock_event_id nsock_connect_sctp(nsock_pool nsp, nsock_iod ms_iod,
return nse->id; return nse->id;
} }
/* Request an SSL over TCP/SCTP connection to another system (by IP /* Request an SSL over TCP/SCTP connection to another system (by IP address).
address). The in_addr is normal network byte order, but the port * The in_addr is normal network byte order, but the port number should be given
number should be given in HOST BYTE ORDER. This function will call * in HOST BYTE ORDER. This function will call back only after it has made the
back only after it has made the connection AND done the initial * connection AND done the initial SSL negotiation. From that point on, you use
SSL negotiation. From that point on, you use the normal read/write * the normal read/write calls and decryption will happen transparently. ss
calls and decryption will happen transparently. ss should be a * should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate
sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate (just * (just like what you would pass to connect). sslen should be the sizeof the
like what you would pass to connect). sslen should be the sizeof * structure you are passing in. */
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,
nsock_event_id nsock_connect_ssl(nsock_pool nsp, nsock_iod nsiod, void *userdata, struct sockaddr *saddr, size_t sslen, int proto, unsigned short port, nsock_ssl_session ssl_session) {
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 #ifndef HAVE_OPENSSL
fatal("nsock_connect_ssl called - but nsock was built w/o SSL support. QUITTING"); fatal("nsock_connect_ssl called - but nsock was built w/o SSL support. QUITTING");
return (nsock_event_id) 0; /* UNREACHED */ return (nsock_event_id)0; /* UNREACHED */
#else #else
struct sockaddr_storage *ss = (struct sockaddr_storage *) saddr; struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;
msiod *nsi = (msiod *) nsiod; msiod *nsi = (msiod *)nsiod;
mspool *ms = (mspool *) nsp; mspool *ms = (mspool *)nsp;
msevent *nse; msevent *nse;
/* Just in case someone waits a long time and then does a new connect */ /* Just in case someone waits a long time and then does a new connect */
@@ -275,17 +262,15 @@ nsock_event_id nsock_connect_ssl(nsock_pool nsp, nsock_iod nsiod,
assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);
nse = msevent_new(ms, NSE_TYPE_CONNECT_SSL, nsi, timeout_msecs, handler, nse = msevent_new(ms, NSE_TYPE_CONNECT_SSL, nsi, timeout_msecs, handler, userdata);
userdata);
assert(nse); assert(nse);
/* Set our SSL_SESSION so we can benefit from session-id reuse. */ /* Set our SSL_SESSION so we can benefit from session-id reuse. */
nsi_set_ssl_session(nsi, (SSL_SESSION *) ssl_session); nsi_set_ssl_session(nsi, (SSL_SESSION *)ssl_session);
if (ms->tracelevel > 0) if (ms->tracelevel > 0)
nsock_trace(ms, "SSL connection requested to %s:%hu/%s (IOD #%li) EID %li", nsock_trace(ms, "SSL connection requested to %s:%hu/%s (IOD #%li) EID %li",
inet_ntop_ez(ss, sslen), port, (proto == IPPROTO_TCP ? "tcp" : "sctp"), inet_ntop_ez(ss, sslen), port, (proto == IPPROTO_TCP ? "tcp" : "sctp"), nsi->id, nse->id);
nsi->id, nse->id);
/* Do the actual connect() */ /* Do the actual connect() */
nsock_connect_internal(ms, nse, proto, ss, sslen, port); nsock_connect_internal(ms, nse, proto, ss, sslen, port);
@@ -295,21 +280,19 @@ nsock_event_id nsock_connect_ssl(nsock_pool nsp, nsock_iod nsiod,
#endif /* HAVE_OPENSSL */ #endif /* HAVE_OPENSSL */
} }
/* Request ssl connection over already established connection. /* Request ssl connection over already established connection. nsiod must be
nsiod must be socket that is already connected to target * socket that is already connected to target using nsock_connect_tcp or
using nsock_connect_tcp or nsock_connect_sctp. * nsock_connect_sctp. All parameters have the same meaning as in
All parameters have the same meaning as in 'nsock_connect_ssl' */ * 'nsock_connect_ssl' */
nsock_event_id nsock_reconnect_ssl(nsock_pool nsp, nsock_iod nsiod, nsock_event_id nsock_reconnect_ssl(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs,
nsock_ev_handler handler, int timeout_msecs, void *userdata, nsock_ssl_session ssl_session) {
void *userdata, nsock_ssl_session ssl_session)
{
#ifndef HAVE_OPENSSL #ifndef HAVE_OPENSSL
fatal("nsock_reconnect_ssl called - but nsock was built w/o SSL support. QUITTING"); fatal("nsock_reconnect_ssl called - but nsock was built w/o SSL support. QUITTING");
return (nsock_event_id) 0; /* UNREACHED */ return (nsock_event_id) 0; /* UNREACHED */
#else #else
msiod *nsi = (msiod *) nsiod; msiod *nsi = (msiod *)nsiod;
mspool *ms = (mspool *) nsp; mspool *ms = (mspool *)nsp;
msevent *nse; msevent *nse;
if (!ms->sslctx) if (!ms->sslctx)
@@ -319,7 +302,7 @@ nsock_event_id nsock_reconnect_ssl(nsock_pool nsp, nsock_iod nsiod,
assert(nse); assert(nse);
/* Set our SSL_SESSION so we can benefit from session-id reuse. */ /* Set our SSL_SESSION so we can benefit from session-id reuse. */
nsi_set_ssl_session(nsi, (SSL_SESSION *) ssl_session); nsi_set_ssl_session(nsi, (SSL_SESSION *)ssl_session);
if (ms->tracelevel > 0) if (ms->tracelevel > 0)
nsock_trace(ms, "SSL reconnection requested (IOD #%li) EID %li", nsi->id, nse->id); nsock_trace(ms, "SSL reconnection requested (IOD #%li) EID %li", nsi->id, nse->id);
@@ -328,73 +311,65 @@ nsock_event_id nsock_reconnect_ssl(nsock_pool nsp, nsock_iod nsiod,
nse->event_done = 0; nse->event_done = 0;
nse->status = NSE_STATUS_SUCCESS; nse->status = NSE_STATUS_SUCCESS;
nsp_add_event(ms, nse); nsp_add_event(ms, nse);
return nse->id; return nse->id;
#endif /* HAVE_OPENSSL */ #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) {
/* Request a UDP "connection" to another system (by IP address). The msiod *nsi = (msiod *)nsiod;
in_addr is normal network byte order, but the port number should be mspool *ms = (mspool *)nsp;
given in HOST BYTE ORDER. Since this is UDP, no packets are msevent *nse;
actually sent. The destination IP and port are just associated struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;
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) {
msiod *nsi = (msiod *) nsiod; assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);
mspool *ms = (mspool *) nsp;
msevent *nse;
struct sockaddr_storage *ss = (struct sockaddr_storage *) saddr;
assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); /* Just in case someone waits a long time and then does a new connect */
gettimeofday(&nsock_tod, NULL);
/* Just in case someone waits a long time and then does a new connect */ nse = msevent_new(ms, NSE_TYPE_CONNECT, nsi, -1, handler, userdata);
gettimeofday(&nsock_tod, NULL); assert(nse);
nse = msevent_new(ms, NSE_TYPE_CONNECT, nsi, -1, handler, userdata); if (ms->tracelevel > 0)
assert(nse);
if (ms->tracelevel > 0)
nsock_trace(ms, "UDP connection requested to %s:%hu (IOD #%li) EID %li", inet_ntop_ez(ss, sslen), port, nsi->id, nse->id); nsock_trace(ms, "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, IPPROTO_UDP, ss, sslen, port); nsock_connect_internal(ms, nse, IPPROTO_UDP, ss, sslen, port);
nsp_add_event(ms, nse); nsp_add_event(ms, nse);
return nse->id; return nse->id;
} }
/* Returns that host/port/protocol information for the last /* Returns that host/port/protocol information for the last communication (or
communication (or comm. attempt) this nsi has been involved with. * comm. attempt) this nsi has been involved with. By "involved" with I mean
By "involved" with I mean interactions like establishing (or trying * interactions like establishing (or trying to) a connection or sending a UDP
to) a connection or sending a UDP datagram through an unconnected * datagram through an unconnected nsock_iod. AF is the address family (AF_INET
nsock_iod. AF is the address family (AF_INET or AF_INET6), Protocl * or AF_INET6), Protocl is IPPROTO_TCP or IPPROTO_UDP. Pass NULL for
is IPPROTO_TCP or IPPROTO_UDP. Pass NULL for information you do * information you do not need. If ANY of the information you requested is not
not need. If ANY of the information you requested is not * available, 0 will be returned and the unavailable sockets are zeroed. If
available, 0 will be returned and the unavailable sockets are * protocol or af is requested but not available, it will be set to -1 (and 0
zeroed. If protocol or af is requested but not available, it will * returned). The pointers you pass in must be NULL or point to allocated
be set to -1 (and 0 returned). The pointers you pass in must be * address space. The sockaddr members should actually be sockaddr_storage,
NULL or point to allocated address space. The sockaddr members * sockaddr_in6, or sockaddr_in with the socklen of them set appropriately (eg
should actually be sockaddr_storage, sockaddr_in6, or sockaddr_in * sizeof(sockaddr_storage) if that is what you are passing). */
with the socklen of them set appropriately (eg int nsi_getlastcommunicationinfo(nsock_iod ms_iod, int *protocol, int *af, struct sockaddr *local,
sizeof(sockaddr_storage) if that is what you are passing). */
int nsi_getlastcommunicationinfo(nsock_iod ms_iod, int *protocol,
int *af, struct sockaddr *local,
struct sockaddr *remote, size_t socklen) { struct sockaddr *remote, size_t socklen) {
msiod *nsi = (msiod *) ms_iod; msiod *nsi = (msiod *)ms_iod;
int ret = 1; int ret = 1;
struct sockaddr_storage sock; struct sockaddr_storage sock;
socklen_t slen = sizeof(struct sockaddr_storage); socklen_t slen = sizeof(struct sockaddr_storage);
@@ -410,11 +385,11 @@ int nsi_getlastcommunicationinfo(nsock_iod ms_iod, int *protocol,
if (*protocol == -1) res = 0; if (*protocol == -1) res = 0;
} }
if (af) { if (af) {
*af = ((struct sockaddr_in *) &nsi->peer)->sin_family; *af = ((struct sockaddr_in *)&nsi->peer)->sin_family;
} }
if (local) { if (local) {
if (nsi->sd >= 0) { if (nsi->sd >= 0) {
res = getsockname(nsi->sd, (struct sockaddr *) &sock, &slen); res = getsockname(nsi->sd, (struct sockaddr *)&sock, &slen);
if (res == -1) { if (res == -1) {
memset(local, 0, socklen); memset(local, 0, socklen);
ret = 0; ret = 0;
@@ -430,10 +405,19 @@ int nsi_getlastcommunicationinfo(nsock_iod ms_iod, int *protocol,
} else { } else {
if (local || remote || protocol || af) if (local || remote || protocol || af)
ret = 0; ret = 0;
if (remote) memset(remote, 0, socklen);
if (local) memset(local, 0, socklen); if (remote)
if (protocol) *protocol = -1; memset(remote, 0, socklen);
if (af) *af = -1;
if (local)
memset(local, 0, socklen);
if (protocol)
*protocol = -1;
if (af)
*af = -1;
} }
return ret; return ret;
} }

File diff suppressed because it is too large Load Diff

107
nsock/src/nsock_engines.c Normal file
View File

@@ -0,0 +1,107 @@
/***************************************************************************
* 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-2011 Insecure.Com *
* 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, Insecure.Com LLC *
* may be willing to sell alternative licenses (contact *
* sales@insecure.com ). *
* *
* As a special exception to the GPL terms, Insecure.Com 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 (none *
* have been found so far). *
* *
* 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 nmap-dev@insecure.org for possible incorporation into the main *
* distribution. By sending these changes to Fyodor or one of the *
* Insecure.Org development mailing lists, it is assumed that you are *
* offering the Nmap Project (Insecure.Com 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_EPOLL
extern struct io_engine engine_epoll;
#define ENGINE_EPOLL &engine_epoll,
#else
#define ENGINE_EPOLL
#endif /* HAVE_EPOLL */
/* 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_SELECT
NULL
};
struct io_engine *get_io_engine(const char *engine_hint) {
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;
}

View File

@@ -86,55 +86,106 @@ int nse_eof(nsock_event nse) {
} }
/* Obtains the nsock_iod (see below) associated with the event. Note that /* 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 * some events (such as timers) don't have an nsock_iod associated with them */
*/
nsock_iod nse_iod(nsock_event ms_event) { nsock_iod nse_iod(nsock_event ms_event) {
msevent *nse = (msevent *) ms_event; msevent *nse = (msevent *)ms_event;
return (nsock_iod) nse->iod; return (nsock_iod) nse->iod;
} }
/* This next function returns the errno style error code -- which is only /* This next function returns the errno style error code -- which is only valid
valid if the status is NSE_STATUS_ERROR */ * if the status is NSE_STATUS_ERROR */
int nse_errorcode(nsock_event nse) { int nse_errorcode(nsock_event nse) {
msevent *me = (msevent *)nse; msevent *me = (msevent *)nse;
return me->errnum; return me->errnum;
} }
/* Every event has an ID which will be unique throughout the program's execution unless you use (literally) billions of them */ /* 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) { nsock_event_id nse_id(nsock_event nse) {
msevent *me = (msevent *)nse; msevent *me = (msevent *)nse;
return me->id; return me->id;
} }
/* If you did a read request, and the result was STATUS_SUCCESS, this /* If you did a read request, and the result was STATUS_SUCCESS, this function
function provides the buffer that was read in as well as the number * provides the buffer that was read in as well as the number of chars read.
of chars read. The buffer should not be modified or free'd */ * The buffer should not be modified or free'd */
char *nse_readbuf(nsock_event nse, int *nbytes) { char *nse_readbuf(nsock_event nse, int *nbytes) {
msevent *me = (msevent *)nse; msevent *me = (msevent *)nse;
if (nbytes) { if (nbytes)
*nbytes = FILESPACE_LENGTH(&(me->iobuf)); *nbytes = FILESPACE_LENGTH(&(me->iobuf));
}
return FILESPACE_STR(&(me->iobuf)); return FILESPACE_STR(&(me->iobuf));
} }
static void first_ev_next(msevent *nse, gh_list_elem **first) {
if (!first || !*first)
return;
/* Cancel an event (such as a timer or read request). If notify is if ((msevent *)GH_LIST_ELEM_DATA(*first) == nse) {
nonzero, the requester will be sent an event CANCELLED status back to gh_list_elem *next;
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 next = GH_LIST_ELEM_NEXT(*first);
which case 0 can be passed to skip the step. This function returns if (next) {
zero if the event is not found, nonzero otherwise */ msevent *nse2 = (msevent *)GH_LIST_ELEM_DATA(next);
if (nse2->iod == nse->iod)
*first = next;
else
*first = NULL;
} else {
*first = NULL;
}
}
}
void update_first_events(msevent *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);
break;
case NSE_TYPE_READ:
first_ev_next(nse, &nse->iod->first_read);
break;
case NSE_TYPE_WRITE:
first_ev_next(nse, &nse->iod->first_write);
break;
#if HAVE_PCAP
case NSE_TYPE_PCAP_READ:
first_ev_next(nse, &nse->iod->first_read);
first_ev_next(nse, &nse->iod->first_pcap_read);
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 ) { int nsock_event_cancel(nsock_pool ms_pool, nsock_event_id id, int notify ) {
mspool *nsp = (mspool *) ms_pool; mspool *nsp = (mspool *)ms_pool;
enum nse_type type = get_event_id_type(id); enum nse_type type;
gh_list *event_list = NULL; gh_list *event_list = NULL, *event_list2 = NULL;
gh_list *event_list2 = NULL;
gh_list_elem *current, *next; gh_list_elem *current, *next;
msevent *nse = NULL; msevent *nse = NULL;
assert(nsp); assert(nsp);
type = get_event_id_type(id);
if (nsp->tracelevel > 0) { if (nsp->tracelevel > 0) {
nsock_trace(nsp, "Event #%li (type %s) cancelled", id, nse_type2str(type)); nsock_trace(nsp, "Event #%li (type %s) cancelled", id, nse_type2str(type));
} }
@@ -142,42 +193,45 @@ int nsock_event_cancel(nsock_pool ms_pool, nsock_event_id id, int notify ) {
/* First we figure out what list it is in */ /* First we figure out what list it is in */
switch(type) { switch(type) {
case NSE_TYPE_CONNECT: case NSE_TYPE_CONNECT:
event_list = &nsp->evl.connect_events; event_list = &nsp->connect_events;
break; break;
case NSE_TYPE_READ: case NSE_TYPE_READ:
event_list = &nsp->evl.read_events; event_list = &nsp->read_events;
break; break;
case NSE_TYPE_WRITE: case NSE_TYPE_WRITE:
event_list = &nsp->evl.write_events; event_list = &nsp->write_events;
break; break;
case NSE_TYPE_TIMER: case NSE_TYPE_TIMER:
event_list = &nsp->evl.timer_events; event_list = &nsp->timer_events;
break; break;
#if HAVE_PCAP #if HAVE_PCAP
case NSE_TYPE_PCAP_READ: case NSE_TYPE_PCAP_READ:
event_list = &nsp->evl.read_events; event_list = &nsp->read_events;
event_list2 = &nsp->evl.pcap_read_events; event_list2 = &nsp->pcap_read_events;
break; break;
#endif #endif
default: default:
fatal("Bogus event type in nsock_event_cancel"); break; fatal("Bogus event type in nsock_event_cancel"); break;
} }
/* Now we try to find the event in the list */ /* Now we try to find the event in the list */
for(current = GH_LIST_FIRST_ELEM(event_list); current != NULL; for (current = GH_LIST_FIRST_ELEM(event_list); current != NULL; current = next) {
current = next) {
next = GH_LIST_ELEM_NEXT(current); next = GH_LIST_ELEM_NEXT(current);
nse = (msevent *) GH_LIST_ELEM_DATA(current); nse = (msevent *)GH_LIST_ELEM_DATA(current);
if (nse->id == id) if (nse->id == id)
break; break;
} }
if (current == NULL && event_list2){ if (current == NULL && event_list2){
event_list = event_list2; event_list = event_list2;
for(current = GH_LIST_FIRST_ELEM(event_list); current != NULL; for (current = GH_LIST_FIRST_ELEM(event_list); current != NULL; current = next) {
current = next) {
next = GH_LIST_ELEM_NEXT(current); next = GH_LIST_ELEM_NEXT(current);
nse = (msevent *) GH_LIST_ELEM_DATA(current); nse = (msevent *)GH_LIST_ELEM_DATA(current);
if (nse->id == id) if (nse->id == id)
break; break;
} }
@@ -188,104 +242,108 @@ int nsock_event_cancel(nsock_pool ms_pool, nsock_event_id id, int notify ) {
return msevent_cancel(nsp, nse, event_list, current, notify); return msevent_cancel(nsp, nse, event_list, current, notify);
} }
/* An inernal function for cancelling an event when you already have a /* An inernal function for cancelling an event when you already have a pointer
pointer to the msevent (use nsock_event_cancel if you just have an * to the msevent (use nsock_event_cancel if you just have an ID). The
ID). The event_list passed in should correspond to the type of the * event_list passed in should correspond to the type of the event. For example,
event. For example, with NSE_TYPE_READ, you would pass in * with NSE_TYPE_READ, you would pass in &nsp->read_events;. elem is the list
&nsp->evl.read_events;. elem is the list element in event_list which * element in event_list which holds the event. Pass a nonzero for notify if
holds the event. Pass a nonzero for notify if you want the * you want the program owning the event to be notified that it has been
program owning the event to be notified that it has been cancelled */ * cancelled */
int msevent_cancel(mspool *nsp, msevent *nse, gh_list *event_list, gh_list_elem *elem, int msevent_cancel(mspool *nsp, msevent *nse, gh_list *event_list, gh_list_elem *elem, int notify) {
int notify) {
if (nse->event_done) { if (nse->event_done) {
/* This event has already been marked for death somewhere else -- it /* This event has already been marked for death somewhere else -- it will be
will be gone soon (and if we try to kill it now all hell will break * gone soon (and if we try to kill it now all hell will break loose due to
loose due to reentrancy */ * reentrancy. */
return 0; return 0;
} }
/* Now that we found the event ... we go through the motions of cleanly if (nsp->tracelevel > 0)
cancelling it */ nsock_trace(nsp, "msevent_cancel() on event #%li (type %s)", nse->id, nse_type2str(nse->type));
/* Now that we found the event... we go through the motions of cleanly
* cancelling it */
switch(nse->type) { switch(nse->type) {
case NSE_TYPE_CONNECT: case NSE_TYPE_CONNECT:
case NSE_TYPE_CONNECT_SSL: case NSE_TYPE_CONNECT_SSL:
handle_connect_result(nsp, nse, NSE_STATUS_CANCELLED); handle_connect_result(nsp, nse, NSE_STATUS_CANCELLED);
break; break;
case NSE_TYPE_READ: case NSE_TYPE_READ:
handle_read_result(nsp, nse, NSE_STATUS_CANCELLED); handle_read_result(nsp, nse, NSE_STATUS_CANCELLED);
break; break;
case NSE_TYPE_WRITE: case NSE_TYPE_WRITE:
handle_write_result(nsp, nse, NSE_STATUS_CANCELLED); handle_write_result(nsp, nse, NSE_STATUS_CANCELLED);
break; break;
case NSE_TYPE_TIMER: case NSE_TYPE_TIMER:
handle_timer_result(nsp, nse, NSE_STATUS_CANCELLED); handle_timer_result(nsp, nse, NSE_STATUS_CANCELLED);
break; break;
#if HAVE_PCAP #if HAVE_PCAP
case NSE_TYPE_PCAP_READ: case NSE_TYPE_PCAP_READ:
handle_pcap_read_result(nsp, nse, NSE_STATUS_CANCELLED); handle_pcap_read_result(nsp, nse, NSE_STATUS_CANCELLED);
break; break;
#endif #endif
default: default:
assert(0); assert(0);
} }
assert(nse->event_done); assert(nse->event_done);
update_first_events(nse);
gh_list_remove_elem(event_list, elem); gh_list_remove_elem(event_list, elem);
if (nsp->tracelevel > 8) if (nsp->tracelevel > 8)
nsock_trace(nsp, "NSE #%lu: Removing event from some event_list", nse->id); nsock_trace(nsp, "NSE #%lu: Removing event from list", nse->id);
#if HAVE_PCAP #if HAVE_PCAP
#if PCAP_BSD_SELECT_HACK #if PCAP_BSD_SELECT_HACK
if(nse->type==NSE_TYPE_PCAP_READ){ if (nse->type == NSE_TYPE_PCAP_READ) {
if (nsp->tracelevel > 8) if (nsp->tracelevel > 8)
nsock_trace(nsp, "PCAP NSE #%lu: CANCELL TEST el.pcap=%p el.read=%p el.curr=%p sd=%i", nsock_trace(nsp, "PCAP NSE #%lu: CANCEL TEST pcap=%p read=%p curr=%p sd=%i",
nse->id, &nsp->evl.pcap_read_events, &nsp->evl.read_events, event_list,((mspcap *) nse->iod->pcap)->pcap_desc ); nse->id, &nsp->pcap_read_events, &nsp->read_events,
/* If event occured, and we're in BSD_HACK mode, than this event was added event_list,((mspcap *)nse->iod->pcap)->pcap_desc);
* to two queues. evl.read_event and evl.pcap_read_event
* Of coure we should destroy it only once.
* I assume we're now in evl.read_event, co just unlink this event from
* evl.pcap_read_event */
if(((mspcap *) nse->iod->pcap)->pcap_desc >= 0 && /* If event occured, and we're in BSD_HACK mode, than this event was added to
event_list == &nsp->evl.read_events){ * two queues. read_event and pcap_read_event Of course we should
/* event is done, list is read_events and we're in BSD_HACK mode. * destroy it only once. I assume we're now in read_event, so just unlink
* So unlink event from pcap_read_events */ * this event from pcap_read_event */
gh_list_remove(&nsp->evl.pcap_read_events, nse); 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);
if (nsp->tracelevel > 8) if (nsp->tracelevel > 8)
nsock_trace(nsp, "PCAP NSE #%lu: Removing event from PCAP_READ_EVENTS", nse->id); nsock_trace(nsp, "PCAP NSE #%lu: Removing event from PCAP_READ_EVENTS", nse->id);
} }
if(((mspcap *) nse->iod->pcap)->pcap_desc >= 0 &&
event_list == &nsp->evl.pcap_read_events){ 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. /* event is done, list is read_events and we're in BSD_HACK mode.
* So unlink event from pcap_read_events */ * So unlink event from read_events */
gh_list_remove(&nsp->evl.read_events, nse); gh_list_remove(&nsp->read_events, nse);
if (nsp->tracelevel > 8) if (nsp->tracelevel > 8)
nsock_trace(nsp, "PCAP NSE #%lu: Removing event from READ_EVENTS", nse->id); nsock_trace(nsp, "PCAP NSE #%lu: Removing event from READ_EVENTS", nse->id);
} }
} }
#endif #endif
#endif #endif
msevent_dispatch_and_delete(nsp, nse, notify); msevent_dispatch_and_delete(nsp, nse, notify);
return 1; return 1;
} }
/* Adjust various statistics, dispatches the event handler (if notify is /* Adjust various statistics, dispatches the event handler (if notify is
nonzero) and then deletes the event. This function does NOT delete * nonzero) and then deletes the event. This function does NOT delete the event
the event from any lists it might be on (eg nsp->evl.read_list etc.) * from any lists it might be on (eg nsp->read_list etc.) nse->event_done
nse->event_done MUST be true when you call this */ * MUST be true when you call this */
void msevent_dispatch_and_delete(mspool *nsp, msevent *nse, int notify) { void msevent_dispatch_and_delete(mspool *nsp, msevent *nse, int notify) {
assert(nsp); assert(nsp);
assert(nse); assert(nse);
assert(nse->event_done); assert(nse->event_done);
nsp->evl.events_pending--; nsp->events_pending--;
assert(nsp->evl.events_pending >= 0); assert(nsp->events_pending >= 0);
if (nse->iod) { if (nse->iod) {
nse->iod->events_pending--; nse->iod->events_pending--;
@@ -297,23 +355,24 @@ void msevent_dispatch_and_delete(mspool *nsp, msevent *nse, int notify) {
nse->handler(nsp, nse, nse->userdata); nse->handler(nsp, nse, nse->userdata);
} }
/* FIXME: We should be updating stats here ... */ /* FIXME: We should be updating stats here ... */
/* Now we clobber the event ... */ /* Now we clobber the event ... */
msevent_delete(nsp, nse); msevent_delete(nsp, nse);
} }
/* OK -- the idea is that we want the type included in the rightmost /* OK -- the idea is that we want the type included in the rightmost two bits
two bits and the serial number in the leftmost 30 or 62. But we * and the serial number in the leftmost 30 or 62. But we also want to insure a
also want to insure a correct wrap-around in the case of an obscene * correct wrap-around in the case of an obscene number of event. One
number of event. One definition of a "correct" wraparound is that * definition of a "correct" wraparound is that it goes from the highest number
it goes from the highest number back to one (not zero) because we * back to one (not zero) because we don't want event numbers to ever be zero.
don't want event numbers to ever be zero. */ * */
nsock_event_id get_new_event_id(mspool *ms, enum nse_type type) { nsock_event_id get_new_event_id(mspool *ms, enum nse_type type) {
int type_code = (int) type; int type_code = (int)type;
unsigned long serial = ms->next_event_serial++; unsigned long serial = ms->next_event_serial++;
unsigned long max_serial_allowed; unsigned long max_serial_allowed;
int shiftbits; int shiftbits;
assert(type < NSE_TYPE_MAX); assert(type < NSE_TYPE_MAX);
shiftbits = sizeof(nsock_event_id) * 8 - TYPE_CODE_NUM_BITS; shiftbits = sizeof(nsock_event_id) * 8 - TYPE_CODE_NUM_BITS;
@@ -328,19 +387,15 @@ nsock_event_id get_new_event_id(mspool *ms, enum nse_type type) {
/* Take an event ID and return the type (NSE_TYPE_CONNECT, etc */ /* Take an event ID and return the type (NSE_TYPE_CONNECT, etc */
enum nse_type get_event_id_type(nsock_event_id event_id) { enum nse_type get_event_id_type(nsock_event_id event_id) {
return (enum nse_type)((event_id & ((1 << TYPE_CODE_NUM_BITS) - 1)));
return (enum nse_type) ((event_id & ((1 << TYPE_CODE_NUM_BITS) - 1)));
} }
/* Create a new event structure -- must be deleted later with msevent_delete, /* Create a new event structure -- must be deleted later with msevent_delete,
unless it returns NULL (failure). NULL can be passed in for the * unless it returns NULL (failure). NULL can be passed in for the msiod and
msiod and the userdata if not available */ * the userdata if not available */
msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod, msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod, int timeout_msecs,
int timeout_msecs, nsock_ev_handler handler, nsock_ev_handler handler, void *userdata) {
void *userdata) {
msevent *nse; msevent *nse;
if (msiod) { if (msiod) {
@@ -349,24 +404,30 @@ msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod,
} }
/* First we check if one is available from the free list ... */ /* First we check if one is available from the free list ... */
nse = (msevent *) gh_list_pop(&nsp->evl.free_events); nse = (msevent *)gh_list_pop(&nsp->free_events);
if (!nse) nse = (msevent *) safe_malloc(sizeof(msevent)); if (!nse)
memset(nse, 0, sizeof(*nse)); nse = (msevent *)safe_malloc(sizeof(msevent));
memset(nse, 0, sizeof(msevent));
nse->id = get_new_event_id(nsp, type); nse->id = get_new_event_id(nsp, type);
nse->type = type; nse->type = type;
nse->status = NSE_STATUS_NONE; nse->status = NSE_STATUS_NONE;
#if HAVE_OPENSSL #if HAVE_OPENSSL
nse->sslinfo.ssl_desire = SSL_ERROR_NONE; nse->sslinfo.ssl_desire = SSL_ERROR_NONE;
#endif #endif
if (type == NSE_TYPE_READ || type == NSE_TYPE_WRITE) { if (type == NSE_TYPE_READ || type == NSE_TYPE_WRITE)
filespace_init(&(nse->iobuf), 1024); filespace_init(&(nse->iobuf), 1024);
}
#if HAVE_PCAP #if HAVE_PCAP
if (type == NSE_TYPE_PCAP_READ) { if (type == NSE_TYPE_PCAP_READ) {
mspcap *mp;
int sz;
assert(msiod != NULL); assert(msiod != NULL);
mspcap *mp = (mspcap *) msiod->pcap; mp = (mspcap *)msiod->pcap;
assert(mp); assert(mp);
int sz = mp->snaplen+1 + sizeof(nsock_pcap);
sz = mp->snaplen+1 + sizeof(nsock_pcap);
filespace_init(&(nse->iobuf), sz); filespace_init(&(nse->iobuf), sz);
} }
#endif #endif
@@ -375,41 +436,32 @@ msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod,
assert(timeout_msecs >= 0); assert(timeout_msecs >= 0);
TIMEVAL_MSEC_ADD(nse->timeout, nsock_tod, timeout_msecs); TIMEVAL_MSEC_ADD(nse->timeout, nsock_tod, timeout_msecs);
} }
nse->iod = msiod; nse->iod = msiod;
nse->handler = handler; nse->handler = handler;
nse->userdata = userdata; nse->userdata = userdata;
nse->time_created = nsock_tod; nse->time_created = nsock_tod;
if (nsp->tracelevel > 3) { if (nsp->tracelevel > 3) {
if(nse->iod == NULL) { if (nse->iod == NULL)
nsock_trace(nsp, "msevent_new (IOD #NULL) (EID #%li)", nsock_trace(nsp, "msevent_new (IOD #NULL) (EID #%li)", nse->id);
nse->id); else
} else { nsock_trace(nsp, "msevent_new (IOD #%li) (EID #%li)", nse->iod->id, nse->id);
nsock_trace(nsp, "msevent_new (IOD #%li) (EID #%li)",
nse->iod->id,
nse->id);
} }
}
return nse; return nse;
} }
/* Free an msevent which was allocated with msevent_new, including all /* Free an msevent which was allocated with msevent_new, including all internal
internal resources. Note -- we assume that * resources. Note -- we assume that nse->iod->events_pending (if it exists)
nse->iod->events_pending (if it exists) has ALREADY been * has ALREADY been decremented (done during msevent_dispatch_and_delete) -- so
decremented (done during msevent_dispatch_and_delete) -- so * remember to do this if you call msevent_delete() directly */
remember to do this if you call msevent_delete() directly */
void msevent_delete(mspool *nsp, msevent *nse) { void msevent_delete(mspool *nsp, msevent *nse) {
if (nsp->tracelevel > 3) { if (nsp->tracelevel > 3) {
if(nse->iod == NULL) { if (nse->iod == NULL)
nsock_trace(nsp, "msevent_delete (IOD #NULL) (EID #%li)", nsock_trace(nsp, "msevent_delete (IOD #NULL) (EID #%li)", nse->id);
nse->id); else
} else { nsock_trace(nsp, "msevent_delete (IOD #%li) (EID #%li)", nse->iod->id, nse->id);
nsock_trace(nsp, "msevent_delete (IOD #%li) (EID #%li)",
nse->iod->id,
nse->id);
}
} }
/* First free the IOBuf inside it if neccessary */ /* First free the IOBuf inside it if neccessary */
@@ -425,13 +477,12 @@ void msevent_delete(mspool *nsp, msevent *nse) {
#endif #endif
/* Now we add the event back into the free pool */ /* Now we add the event back into the free pool */
gh_list_prepend(&nsp->evl.free_events, nse); gh_list_prepend(&nsp->free_events, nse);
} }
/* Takes an nse_type (as returned by nse_type() and returns a static /* Takes an nse_type (as returned by nse_type() and returns a static string name
string name that you can use for printing, etc. */ * that you can use for printing, etc. */
const char *nse_type2str(enum nse_type type) { const char *nse_type2str(enum nse_type type) {
switch(type) { switch(type) {
case NSE_TYPE_CONNECT: return "CONNECT"; case NSE_TYPE_CONNECT: return "CONNECT";
@@ -445,8 +496,8 @@ const char *nse_type2str(enum nse_type type) {
} }
} }
/* Takes an nse_status (as returned by nse_status() and returns a static /* Takes an nse_status (as returned by nse_status() and returns a static string
string name that you can use for printing, etc. */ * name that you can use for printing, etc. */
const char *nse_status2str(enum nse_status status) { const char *nse_status2str(enum nse_status status) {
switch(status) { switch(status) {
case NSE_STATUS_NONE: return "NONE"; case NSE_STATUS_NONE: return "NONE";
@@ -461,9 +512,3 @@ const char *nse_status2str(enum nse_status status) {
} }
} }

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* nsock_internal.h -- PRIVATE interface definitions for the guts of the * * nsock_internal.h -- PRIVATE interface definitions for the guts of the *
* nsock paralle socket event library. Applications calling this library * * nsock paralle socket event library. Applications calling this library *
@@ -103,290 +102,353 @@
#define IPPROTO_SCTP 132 #define IPPROTO_SCTP 132
#endif #endif
/********* STRUCTURES **************/
/* This is geared to handling state for select calls, perhaps at /* ------------------- CONSTANTS ------------------- */
some point I'll add a USE_POLL_NOT_SELECT define which causes it to
do poll()s instead. */
struct nsock_io_info {
fd_set fds_master_r; /* Descriptors from which have pending READ events */
fd_set fds_master_w; /* Descriptors which we are tryint to WRITE to */
fd_set fds_master_x; /* looking for exceptional events -- used with connect */
/* For keeping track of the select results */ enum nsock_read_types {
fd_set fds_results_r, fds_results_w, fds_results_x; NSOCK_READLINES,
NSOCK_READBYTES,
/* The highest sd we have set in any of our fd_set's (max_sd + 1 is NSOCK_READ
used in select() calls). Note that it can be -1, when there are no
valid sockets */
int max_sd;
int results_left; /* The number of descriptors contained in the sets that
we have not yet dealt with. */
}; };
struct event_lists { enum msiod_state {
/* We keep the events seperate because we want to handle them in the NSIOD_STATE_DELETED,
order: connect => read => write => timer for several reasons: NSIOD_STATE_INITIAL,
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().
*/
gh_list connect_events;
gh_list read_events;
gh_list write_events;
gh_list timer_events;
#if HAVE_PCAP
gh_list pcap_read_events;
#endif
gh_list free_events; /* When an event is deleted, we stick it here for
later reuse */
struct timeval next_ev; /* The soonest time that either a timer event goes
off or a read/write/connect expires. It is
updated each main loop round as we go through
the events. It is an absolute time. If there
are no events, tv_sec is 0 */
int events_pending; /* Number of events pending (total) on all lists */
/* sd was provided to us in nsi_new2 (see nsock_pool.c) */
NSIOD_STATE_UNKNOWN,
NSIOD_STATE_CONNECTED_TCP,
NSIOD_STATE_CONNECTED_UDP
}; };
enum nsock_read_types { NSOCK_READLINES, NSOCK_READBYTES, NSOCK_READ }; /* 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 { struct readinfo {
enum nsock_read_types read_type; enum nsock_read_types read_type;
int num; /* num lines; num bytes; whatever (depends on read_type) */ /* num lines; num bytes; whatever (depends on read_type) */
int num;
}; };
struct writeinfo { struct writeinfo {
struct sockaddr_storage dest; struct sockaddr_storage dest;
size_t destlen; size_t destlen;
int written_so_far; /* Number of bytes successfully written */ /* Number of bytes successfully written */
int written_so_far;
}; };
/* remember that callers of this library should NOT be accessing these /* Remember that callers of this library should NOT be accessing these
fields directly */ * fields directly */
typedef struct { typedef struct {
unsigned long id; /* Every mst has a unique (accross the
program execution) id */
struct nsock_io_info mioi; /* info for keeping track of select() I/O */ /* Every msp has a unique (accross the program execution) id */
struct event_lists evl; /* Lists of pending events we are waiting on */ unsigned long id;
void *userdata; /* User Data, if it has been set. Otherwise NULL */ /* User data, NULL if unset */
gh_list free_iods; /* msiod structures that have been freed for reuse */ void *userdata;
gh_list active_iods; /* msiod structures that have been allocated */
unsigned long next_event_serial; /* serial # of next event (used to create /* IO Engine vtable */
next nsock_event_id */ struct io_engine *engine;
unsigned long next_iod_serial; /* Serial # of next iod to be created */ /* IO Engine internal data */
int errnum; /* If nsock_loop() returns NSOCK_LOOP_ERROR, this is where we void *engine_data;
describe the error (errnum fashion) */
int tracelevel; /* Trace/debug level - set by nsp_settrace. If positive, /* Active network events */
trace logs are printted to tracefile. */ gh_list connect_events;
gh_list read_events;
gh_list write_events;
gh_list timer_events;
#if HAVE_PCAP
gh_list pcap_read_events;
#endif
/* Active iods and related lists of events */
gh_list active_iods;
/* msiod structures that have been freed for reuse */
gh_list free_iods;
/* When an event is deleted, we stick it here for later reuse */
gh_list free_events;
/* The soonest time that either a timer event goes
* off or a read/write/connect expires. It is
* updated each main loop round as we go through
* the events. It is an absolute time. If there
* are no events, tv_sec is 0 */
struct timeval next_ev;
/* 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;
/* Trace/debug level - set by nsp_settrace. If positive, trace logs are
* printted to tracefile. */
int tracelevel;
FILE *tracefile; FILE *tracefile;
int broadcast; /* If true, new sockets will have SO_BROADCAST set */
/* This time is subtracted from the current time for trace reports */ /* This time is subtracted from the current time for trace reports */
struct timeval tracebasetime; struct timeval tracebasetime;
/* If true, new sockets will have SO_BROADCAST set */
int broadcast;
/* If true, exit the next iteration of nsock_loop with a status of /* If true, exit the next iteration of nsock_loop with a status of
NSOCK_LOOP_QUIT. */ * NSOCK_LOOP_QUIT. */
int quit; int quit;
#if HAVE_OPENSSL #if HAVE_OPENSSL
SSL_CTX *sslctx; /* The SSL Context (options and such) */ /* The SSL Context (options and such) */
SSL_CTX *sslctx;
#endif #endif
} mspool; } mspool;
typedef struct msevent msevent; /* nsock_iod is like a "file descriptor" for the nsock library. You use it to
* request events. */
typedef struct {
/* The socket descriptor related to the event */
int sd;
typedef struct msiod msiod; /* Number of pending events on this iod */
int events_pending;
enum msiod_state { NSIOD_STATE_DELETED, NSIOD_STATE_INITIAL, /* Pending events */
NSIOD_STATE_UNKNOWN /* sd was provided to us in nsi_new2 */, gh_list_elem *first_connect;
NSIOD_STATE_CONNECTED_TCP, NSIOD_STATE_CONNECTED_UDP }; gh_list_elem *first_read;
gh_list_elem *first_write;
#if HAVE_PCAP
gh_list_elem *first_pcap_read;
#endif
/* struct sslinfo defined in nsock_ssl.h */
/* typedef struct msiod msiod; */
/* nsock_iod is like a "file descriptor" for the nsock library. You
use it to request events. */
struct msiod {
int sd; /* The socket descriptor related to the event */
int events_pending; /* Number of pending events on this iod */
/* These are counts of how many events are waiting to read from or write to
the socket. When they are 0 we stop watching the socket for readability or
writability. */
int readsd_count; int readsd_count;
int writesd_count; int writesd_count;
#if HAVE_PCAP
int readpcapsd_count; int readpcapsd_count;
mspool *nsp; /* The mspool used to create the iod (used for deletion) */ #endif
enum msiod_state state;
struct sockaddr_storage peer; /* The host and port we are connected to
using sd (saves a call to getpeername) */
struct sockaddr_storage local; /* The host and port to bind to with sd */
/* The length of peer/local actually used (sizeof(sockaddr_in) or int watched_events;
sizeof(sockaddr_in6), or 0 if peer/local has not been filled in */
size_t locallen, peerlen; /* The mspool used to create the iod (used for deletion) */
int lastproto; /* -1 if none yet, otherwise IPPROTO_TCP, etc. */ mspool *nsp;
gh_list_elem *entry_in_nsp_active_iods; /* The mspool keeps track of
msiods that have been enum msiod_state state;
allocated so that it can
destroy them if the msp /* The host and port we are connected to using sd (saves a call to getpeername) */
is deleted. This pointer struct sockaddr_storage peer;
makes it easy to remove /* The host and port to bind to with sd */
this msiod from the struct sockaddr_storage local;
allocated list when
neccessary */ /* The length of peer/local actually used (sizeof(sockaddr_in) or
* sizeof(sockaddr_in6), 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 mspool keeps track of msiods that have been allocated so that it can
* destroy them if the msp is deleted. This pointer makes it easy to remove
* this msiod from the allocated list when neccessary */
gh_list_elem *entry_in_nsp_active_iods;
#define IOD_REGISTERED 0x01
#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. */ /* Used for SSL Server Name Indication. */
char *hostname; char *hostname;
#if HAVE_OPENSSL #if HAVE_OPENSSL
SSL *ssl; /* An SSL connection (or NULL if none) */ /* An SSL connection (or NULL if none) */
SSL_SESSION *ssl_session; /* SSL SESSION ID (or NULL if none) */ SSL *ssl;
/* SSL SESSION ID (or NULL if none) */
SSL_SESSION *ssl_session;
#else #else
char *ssl; /* Because there are many if (nsi->ssl) cases in the code */ /* Because there are many if (nsi->ssl) cases in the code */
char *ssl;
#endif #endif
unsigned long id; /* Every iod has an id which is always unique for the /* Every iod has an id which is always unique for the same nspool (unless you
same nspool (unless you create billions of them) */ * 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;
unsigned long read_count; /* No. of bytes read from the sd*/
unsigned long write_count; /* No. of bytes written to the sd */
void *userdata; void *userdata;
/* IP options to set on socket before connect() */ /* IP options to set on socket before connect() */
void *ipopts; void *ipopts;
int ipoptslen; int ipoptslen;
void *pcap; /* Pointer to mspcap struct (used only if pcap support is included) */ /* Pointer to mspcap struct (used only if pcap support is included) */
}; void *pcap;
} msiod;
/* nsock_event_t handles a single event. Its ID is generally returned when the
* event is created, and the event is included in callbacks */
typedef struct {
/* 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;
/* 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 msevent {
nsock_event_id id; /* Every event has an ID which is unique for a given nsock
unless you blow through more than 500,000,000 events */
enum nse_type type; enum nse_type type;
enum nse_status status; enum nse_status status;
struct filespace iobuf; /* for write events, this is the data to be written, /* For write events, this is the data to be written, for read events, this is
for read events, this is what we will read into */ * 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;
struct timeval timeout; /* The timeout of the event -- absolute time
except that tv_sec == 0 means no timeout */
struct readinfo readinfo; /* Info pertaining to READ requests */
struct writeinfo writeinfo; /* Info pertaining to WRITE requests */
#if HAVE_OPENSSL #if HAVE_OPENSSL
struct sslinfo sslinfo; struct sslinfo sslinfo;
#endif #endif
int errnum; /* If we return a status of NSE_STATUS_ERROR, this must be set */
/* If we return a status of NSE_STATUS_ERROR, this must be set */
int errnum;
int eof; int eof;
msiod *iod; /* The nsock I/O descriptor related to event (if applicable) */
nsock_ev_handler handler; /* The handler to call when event is complete */ /* The nsock I/O descriptor related to event (if applicable) */
msiod *iod;
/* The handler to call when event is complete */
nsock_ev_handler handler;
/* Optional (NULL if unset) pointer to pass to the handler */
void *userdata; void *userdata;
int event_done; /* If this event is all filled out and ready for
immediate delivery, event_done is nonzero. Used /* If this event is all filled out and ready for immediate delivery,
when event is finished at unexpected time and we * event_done is nonzero. Used when event is finished at unexpected time and
want to dispatch it later to avoid duplicating * we want to dispatch it later to avoid duplicating stat update code and all
stat update code and all that other crap */ * that other crap */
int event_done;
struct timeval time_created; struct timeval time_created;
} msevent;
struct io_engine {
/* Human readable identifier for this engine. */
const char *name;
/* Engine constructor */
int (*init)(mspool *nsp);
/* Engine destructor */
void (*destroy)(mspool *nsp);
/* Register a new IOD to the engine */
int (*iod_register)(mspool *nsp, msiod *iod, int ev);
/* Remove a registered IOD */
int (*iod_unregister)(mspool *nsp, msiod *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)(mspool *nsp, msiod *iod, int ev_set, int ev_clr);
/* Main engine loop */
int (*loop)(mspool *nsp, int msec_timeout);
}; };
/* ------------------- PROTOTYPES ------------------- */
/********* PROTOTYPES **************/
/* Get a new nsock_event_id, given a type */ /* Get a new nsock_event_id, given a type */
nsock_event_id get_new_event_id(mspool *nsp, enum nse_type type); nsock_event_id get_new_event_id(mspool *nsp, enum nse_type type);
/* Take an event ID and return the type (NSE_TYPE_CONNECT, etc */ /* Take an event ID and return the type (NSE_TYPE_CONNECT, etc */
enum nse_type get_event_id_type(nsock_event_id event_id); enum nse_type get_event_id_type(nsock_event_id event_id);
/* Create a new event structure -- must be deleted later with msevent_delete, /* Create a new event structure -- must be deleted later with msevent_delete,
unless it returns NULL (failure). NULL can be passed in for the * unless it returns NULL (failure). NULL can be passed in for the msiod and
msiod and the userdata if not available. */ * the userdata if not available. */
msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod, msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod, int timeout_msecs, nsock_ev_handler handler, void *userdata);
int timeout_msecs, nsock_ev_handler handler,
void *userdata);
/* An inernal function for cancelling an event when you already have a /* An internal function for cancelling an event when you already have a pointer
pointer to the msevent (use nsock_event_cancel if you just have an * to the msevent (use nsock_event_cancel if you just have an ID). The
ID). The event_list passed in should correspond to the type of the * event_list passed in should correspond to the type of the event. For
event. For example, with NSE_TYPE_READ, you would pass in * example, with NSE_TYPE_READ, you would pass in &iod->read_events;. elem
&nsp->evl.read_events;. elem is the list element in event_list * is the list element in event_list which holds the event. Pass a nonzero for
which holds the event. Pass a nonzero for notify if you want the * notify if you want the program owning the event to be notified that it has
program owning the event to be notified that it has been cancelled */ * been cancelled */
int msevent_cancel(mspool *nsp, msevent *nse, gh_list *event_list, int msevent_cancel(mspool *nsp, msevent *nse, gh_list *event_list, gh_list_elem *elem, int notify);
gh_list_elem *elem, int notify);
/* Adjust various statistics, dispatches the event handler (if notify is /* Adjust various statistics, dispatches the event handler (if notify is
nonzero) and then deletes the event. This function does NOT delete * nonzero) and then deletes the event. This function does NOT delete the event
the event from any lists it might be on (eg nsp->evl.read_list etc.) * from any lists it might be on (eg nsp->read_list etc.) nse->event_done
nse->event_done MUST be true when you call this */ * MUST be true when you call this */
void msevent_dispatch_and_delete(mspool *nsp, msevent *nse, int notify); void msevent_dispatch_and_delete(mspool *nsp, msevent *nse, int notify);
/* Free an msevent which was allocated with msevent_new, including all /* Free an msevent which was allocated with msevent_new, including all internal
internal resources. Note -- we assume that * resources. Note -- we assume that nse->iod->events_pending (if it exists)
nse->iod->events_pending (if it exists) has ALREADY been * has ALREADY been decremented (done during msevent_dispatch_and_delete) -- so
decremented (done during msevent_dispatch_and_delete) -- so * remember to do this if you call msevent_delete() directly */
remember to do this if you call msevent_delete() directly */
void msevent_delete(mspool *nsp, msevent *nse); void msevent_delete(mspool *nsp, msevent *nse);
/* Adds an event to the appropriate nsp event list, handles housekeeping /* Add an event to the appropriate nsp event list, handles housekeeping such as
such as adjusting the descriptor select/poll lists, registering the * adjusting the descriptor select/poll lists, registering the timeout value,
timeout value, etc. */ * etc. */
void nsp_add_event(mspool *nsp, msevent *nse); void nsp_add_event(mspool *nsp, msevent *nse);
void nsock_connect_internal(mspool *ms, msevent *nse, int proto, void nsock_connect_internal(mspool *ms, msevent *nse, int proto, struct sockaddr_storage *ss, size_t sslen, unsigned short port);
struct sockaddr_storage *ss, size_t sslen,
unsigned short port);
/* Comments on using the following handle_*_result functions are available /* Comments on using the following handle_*_result functions are available in nsock_core.c */
in nsock_core.c */
/* handle_connect_results assumes that select or poll have already
shown the descriptor to be active */
void handle_connect_result(mspool *ms, msevent *nse,
enum nse_status status);
void handle_read_result(mspool *ms, msevent *nse, /* handle_connect_results assumes that select or poll have already shown the
enum nse_status status); * descriptor to be active */
void handle_connect_result(mspool *ms, msevent *nse, enum nse_status status);
void handle_write_result(mspool *ms, msevent *nse, void handle_read_result(mspool *ms, msevent *nse, enum nse_status status);
enum nse_status status);
void handle_timer_result(mspool *ms, msevent *nse, void handle_write_result(mspool *ms, msevent *nse, enum nse_status status);
enum nse_status status);
void handle_timer_result(mspool *ms, msevent *nse, enum nse_status status);
#if HAVE_PCAP #if HAVE_PCAP
void handle_pcap_read_result(mspool *ms, msevent *nse, void handle_pcap_read_result(mspool *ms, msevent *nse, enum nse_status status);
enum nse_status status);
#endif #endif
void nsock_trace(mspool *ms, char *fmt, ...) void nsock_trace(mspool *ms, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
__attribute__ ((format (printf, 2, 3)));
/* An event has been completed and the handler is about to be called. This function /* An event has been completed and the handler is about to be called. This
writes out tracing data about the event if neccessary */ * function writes out tracing data about the event if necessary */
void nsock_trace_handler_callback(mspool *ms, msevent *nse); void nsock_trace_handler_callback(mspool *ms, msevent *nse);
#if HAVE_OPENSSL #if HAVE_OPENSSL
/* sets the ssl session of an nsock_iod, increments usage count. The /* Sets the ssl session of an nsock_iod, increments usage count. The session
session should not have been set yet (as no freeing is done) */ * should not have been set yet (as no freeing is done) */
void nsi_set_ssl_session(msiod *iod, SSL_SESSION *sessid); void nsi_set_ssl_session(msiod *iod, SSL_SESSION *sessid);
#endif #endif
#endif /* NSOCK_INTERNAL_H */ #endif /* NSOCK_INTERNAL_H */

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* nsock_iod.c -- This contains the functions relating to nsock_iod (and * * nsock_iod.c -- This contains the functions relating to nsock_iod (and *
* its nsock internal manifistation -- nsockiod. This is is similar to a * * its nsock internal manifistation -- nsockiod. This is is similar to a *
@@ -69,30 +68,29 @@
#include <string.h> #include <string.h>
/* nsock_iod is like a "file descriptor" for the nsock library. You /* nsock_iod is like a "file descriptor" for the nsock library. You use it to
use it to request events. And here is how you create an nsock_iod. * request events. And here is how you create an nsock_iod. nsi_new returns
nsi_new returns NULL if the iod cannot be allocated. Pass NULL as * NULL if the iod cannot be allocated. Pass NULL as userdata if you don't want
userdata if you don't want to immediately associate any user data * to immediately associate any user data with the iod. */
with the iod. */
nsock_iod nsi_new(nsock_pool nsockp, void *userdata) { nsock_iod nsi_new(nsock_pool nsockp, void *userdata) {
return nsi_new2(nsockp, -1, userdata); return nsi_new2(nsockp, -1, userdata);
} }
/* This version allows you to associate an existing sd with the msi /* This version allows you to associate an existing sd with the msi so that you
so that you can read/write it using the nsock infrastructure. For example, * can read/write it using the nsock infrastructure. For example, you may want
you may want to watch for data from STDIN_FILENO at the same time as you * to watch for data from STDIN_FILENO at the same time as you read/write
read/write various sockets. STDIN_FILENO is a special case, however. Any * various sockets. STDIN_FILENO is a special case, however. Any other sd is
other sd is dup()ed, so you may close or otherwise manipulate your copy. * dup()ed, so you may close or otherwise manipulate your copy. The duped copy
The duped copy will be destroyed when the nsi is destroyed * will be destroyed when the nsi is destroyed. */
*/
nsock_iod nsi_new2(nsock_pool nsockp, int sd, void *userdata) { nsock_iod nsi_new2(nsock_pool nsockp, int sd, void *userdata) {
mspool *nsp = (mspool *) nsockp; mspool *nsp = (mspool *)nsockp;
msiod *nsi; msiod *nsi;
nsi = (msiod *) gh_list_pop(&nsp->free_iods); nsi = (msiod *)gh_list_pop(&nsp->free_iods);
if (!nsi) nsi = (msiod * ) safe_malloc(sizeof(msiod)); if (!nsi) {
nsi = (msiod *)safe_malloc(sizeof(msiod));
memset(nsi, 0, sizeof(*nsi)); memset(nsi, 0, sizeof(*nsi));
}
if (sd == -1) { if (sd == -1) {
nsi->sd = -1; nsi->sd = -1;
@@ -110,16 +108,22 @@ nsock_iod nsi_new2(nsock_pool nsockp, int sd, void *userdata) {
nsi->state = NSIOD_STATE_UNKNOWN; nsi->state = NSIOD_STATE_UNKNOWN;
} }
nsi->locallen = 0; nsi->first_connect = NULL;
nsi->first_read = NULL;
nsi->first_write = NULL;
#if HAVE_PCAP
nsi->first_pcap_read = NULL;
#endif
nsi->readsd_count = 0;
nsi->write_count = 0;
nsi->readpcapsd_count = 0;
nsi->userdata = userdata; nsi->userdata = userdata;
nsi->nsp = (mspool *) nsockp; nsi->nsp = (mspool *)nsockp;
nsi->events_pending = 0;
nsi->readsd_count = 0; nsi->read_count = 0;
nsi->writesd_count = 0; nsi->write_count = 0;
nsi->readpcapsd_count = 0;
nsi->read_count=0;
nsi->write_count=0;
nsi->hostname = NULL; nsi->hostname = NULL;
@@ -131,66 +135,73 @@ nsock_iod nsi_new2(nsock_pool nsockp, int sd, void *userdata) {
#endif #endif
nsi->id = nsp->next_iod_serial++; nsi->id = nsp->next_iod_serial++;
if (nsi->id == 0) nsi->id = nsp->next_iod_serial++; if (nsi->id == 0)
nsi->id = nsp->next_iod_serial++;
/* The nsp keeps track of active msiods so it can delete them /* The nsp keeps track of active msiods so it can delete them if it is deleted */
if it is deleted */ nsi->entry_in_nsp_active_iods = gh_list_append(&nsp->active_iods, nsi);
nsi->entry_in_nsp_active_iods = gh_list_append(&nsi->nsp->active_iods, nsi); return (nsock_iod)nsi;
return (nsock_iod) nsi;
} }
/* Defined in nsock_core.c. */ /* Defined in nsock_core.c. */
int socket_count_zero(msiod *iod, mspool *ms); int socket_count_zero(msiod *iod, mspool *ms);
/* If msiod_new returned success, you must free the iod when you are /* If msiod_new returned success, you must free the iod when you are done with
done with it to conserve memory (and in some cases, sockets). * it to conserve memory (and in some cases, sockets). After this call,
After this call, nsockiod may no longer be used -- you need to * nsockiod may no longer be used -- you need to create a new one with
create a new one with nsi_new(). pending_response tells what to do * nsi_new(). pending_response tells what to do with any events that are
with any events that are pending on this nsock_iod. This can be * pending on this nsock_iod. This can be NSOCK_PENDING_NOTIFY (send a KILL
NSOCK_PENDING_NOTIFY (send a KILL notification to each event), * notification to each event), NSOCK_PENDING_SILENT (do not send notification
NSOCK_PENDING_SILENT (do not send notification to the killed * to the killed events), or NSOCK_PENDING_ERROR (print an error message and
events), or NSOCK_PENDING_ERROR (print an error message and quiit * quiit the program) */
the program) */
void nsi_delete(nsock_iod nsockiod, int pending_response) { void nsi_delete(nsock_iod nsockiod, int pending_response) {
msiod *nsi = (msiod *) nsockiod; msiod *nsi = (msiod *)nsockiod;
gh_list *elist_ar[3]; gh_list_elem *evlist_ar[3];
int elist; gh_list *corresp_list[3];
gh_list_elem *currev_elem, *next_elem; int i;
msevent *currev; gh_list_elem *current, *next;
assert(nsi); assert(nsi);
if (nsi->nsp->tracelevel > 1)
nsock_trace(nsi->nsp, "nsi_delete() (IOD #%lu)", nsi->id);
if (nsi->state == NSIOD_STATE_DELETED) { if (nsi->state == NSIOD_STATE_DELETED) {
fatal("nsi_delete() called on nsock_iod which appears to have already been deleted"); /* This nsi is already marked as deleted, will probably be removed from the
* list very soon. Just return to avoid breaking reentrancy. */
return;
} }
if (nsi->events_pending > 0) { if (nsi->events_pending > 0) {
/* shit -- they killed the msiod while an event was still pending /* shit -- they killed the msiod while an event was still pending on it.
on it. Maybe I should store the pending events in the msiod. * Maybe I should store the pending events in the msiod. On the other hand,
On the other hand, this should be a pretty rare occurance and * this should be a pretty rare occurance and so I'll save space and hassle
so I'll save space and hassle by just locating the events here * by just locating the events here by searching through the active events
by searching through the active events list */ * list */
if (pending_response == NSOCK_PENDING_ERROR) if (pending_response == NSOCK_PENDING_ERROR)
fatal("nsi_delete called with argument NSOCK_PENDING_ERROR on a nsock_iod that has %d pending event(s) associated with it", nsi->events_pending); fatal("nsi_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); assert(pending_response == NSOCK_PENDING_NOTIFY || pending_response == NSOCK_PENDING_SILENT);
elist_ar[0] = &(nsi->nsp->evl.read_events);
elist_ar[1] = &(nsi->nsp->evl.write_events); evlist_ar[0] = nsi->first_connect;
elist_ar[2] = &(nsi->nsp->evl.connect_events); evlist_ar[1] = nsi->first_read;
for(elist = 0; elist < 3 && nsi->events_pending > 0; elist++) { evlist_ar[2] = nsi->first_write;
currev_elem = GH_LIST_FIRST_ELEM(elist_ar[elist]);
while(currev_elem) { corresp_list[0] = &nsi->nsp->connect_events;
currev = (msevent *) GH_LIST_ELEM_DATA(currev_elem); corresp_list[1] = &nsi->nsp->read_events;
next_elem = GH_LIST_ELEM_NEXT(currev_elem); corresp_list[2] = &nsi->nsp->write_events;
if (currev->iod == nsi) {
/* OK - we found an event pending on this IOD. Kill it. */ for (i = 0; i < 3 && nsi->events_pending > 0; i++) {
/* printf("Found an outstanding event (out of %d), removing\n", nsi->events_pending); */ for (current = evlist_ar[i]; current != NULL; current = next) {
msevent_cancel(nsi->nsp, currev, elist_ar[elist], currev_elem, pending_response == NSOCK_PENDING_NOTIFY); next = GH_LIST_ELEM_NEXT(current);
} msevent *nse = (msevent *)GH_LIST_ELEM_DATA(current);
if (nsi->events_pending == 0)
/* we're done with this list of events for the current IOD */
if (nse->iod != nsi)
break; break;
currev_elem = next_elem;
msevent_cancel(nsi->nsp, nse, corresp_list[i], current, pending_response == NSOCK_PENDING_NOTIFY);
} }
} }
} }
@@ -199,7 +210,7 @@ void nsi_delete(nsock_iod nsockiod, int pending_response) {
fatal("Trying to delete NSI, but could not find %d of the purportedly pending events on that IOD.\n", nsi->events_pending); 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 /* Make sure we no longer select on this socket, in case the socket counts
weren't already decremented to zero. */ * weren't already decremented to zero. */
if (nsi->sd >= 0) if (nsi->sd >= 0)
socket_count_zero(nsi, nsi->nsp); socket_count_zero(nsi, nsi->nsp);
@@ -209,22 +220,24 @@ void nsi_delete(nsock_iod nsockiod, int pending_response) {
/* Close any SSL resources */ /* Close any SSL resources */
if (nsi->ssl) { if (nsi->ssl) {
/* No longer free session because copy nsi stores is not reference counted */ /* No longer free session because copy nsi stores is not reference counted */
/* if (nsi->ssl_session) #if 0
if (nsi->ssl_session)
SSL_SESSION_free(nsi->ssl_session); SSL_SESSION_free(nsi->ssl_session);
nsi->ssl_session = NULL; */ nsi->ssl_session = NULL;
#endif
if (SSL_shutdown(nsi->ssl) == -1) { if (SSL_shutdown(nsi->ssl) == -1) {
if (nsi->nsp->tracelevel > 1) if (nsi->nsp->tracelevel > 1)
nsock_trace(nsi->nsp, nsock_trace(nsi->nsp, "nsi_delete(): SSL shutdown failed (%s) on NSI %li",
"nsi_delete(): SSL shutdown failed (%s) on NSI %li", ERR_reason_error_string(SSL_get_error(nsi->ssl, -1)), nsi->id);
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 /* 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 * make the SD blocking temporarily for this, but I'm hoping it will succeed
succeed 95% of the time because we can usually write to a socket. */ * 95% of the time because we can usually write to a socket. */
SSL_free(nsi->ssl); SSL_free(nsi->ssl);
nsi->ssl = NULL; nsi->ssl = NULL;
} }
#endif #endif
@@ -240,17 +253,18 @@ void nsi_delete(nsock_iod nsockiod, int pending_response) {
free(nsi->ipopts); free(nsi->ipopts);
#if HAVE_PCAP #if HAVE_PCAP
if(nsi->pcap){ if (nsi->pcap){
mspcap *mp = (mspcap *) nsi->pcap; mspcap *mp = (mspcap *)nsi->pcap;
if(mp->pt){
if (mp->pt){
pcap_close(mp->pt); pcap_close(mp->pt);
mp->pt=NULL; mp->pt = NULL;
} }
if(mp->pcap_desc){ if (mp->pcap_desc) {
// Should I close pcap_desc or pcap_close does this for me? /* pcap_close() will close the associated pcap descriptor */
mp->pcap_desc = -1; mp->pcap_desc = -1;
} }
if(mp->pcap_device){ if (mp->pcap_device) {
free(mp->pcap_device); free(mp->pcap_device);
mp->pcap_device = NULL; mp->pcap_device = NULL;
} }
@@ -258,14 +272,10 @@ void nsi_delete(nsock_iod nsockiod, int pending_response) {
nsi->pcap = NULL; nsi->pcap = NULL;
} }
#endif #endif
gh_list_remove_elem(&nsi->nsp->active_iods, nsi->entry_in_nsp_active_iods);
gh_list_prepend(&nsi->nsp->free_iods, nsi);
} }
/* Returns the ID of an nsock_iod . This ID is always unique amongst /* Returns the ID of an nsock_iod . This ID is always unique amongst ids for a
ids for a given nspool (unless you blow through billions of them). */ * given nspool (unless you blow through billions of them). */
unsigned long nsi_id(nsock_iod nsockiod) { unsigned long nsi_id(nsock_iod nsockiod) {
assert(nsockiod); assert(nsockiod);
return ((msiod *)nsockiod)->id; return ((msiod *)nsockiod)->id;
@@ -280,7 +290,7 @@ nsock_ssl nsi_getssl(nsock_iod nsockiod) {
#endif #endif
} }
/* Returns the SSL_SESSION of an nsock_iod, and increments it's usage count */ /* Returns the SSL_SESSION of an nsock_iod, and increments it's usage count. */
nsock_ssl_session nsi_get1_ssl_session(nsock_iod nsockiod) { nsock_ssl_session nsi_get1_ssl_session(nsock_iod nsockiod) {
#if HAVE_OPENSSL #if HAVE_OPENSSL
return SSL_get1_session(((msiod *)nsockiod)->ssl); return SSL_get1_session(((msiod *)nsockiod)->ssl);
@@ -289,7 +299,7 @@ nsock_ssl_session nsi_get1_ssl_session(nsock_iod nsockiod) {
#endif #endif
} }
/* Returns the SSL_SESSION without incrementing usage count */ /* Returns the SSL_SESSION without incrementing usage count. */
nsock_ssl_session nsi_get0_ssl_session(nsock_iod nsockiod) { nsock_ssl_session nsi_get0_ssl_session(nsock_iod nsockiod) {
#if HAVE_OPENSSL #if HAVE_OPENSSL
return SSL_get0_session(((msiod *)nsockiod)->ssl); return SSL_get0_session(((msiod *)nsockiod)->ssl);
@@ -298,62 +308,61 @@ nsock_ssl_session nsi_get0_ssl_session(nsock_iod nsockiod) {
#endif #endif
} }
/* sets the ssl session of an nsock_iod, increments usage count. The /* sets the ssl session of an nsock_iod, increments usage count. The session
session should not have been set yet (as no freeing is done) */ * should not have been set yet (as no freeing is done) */
#if HAVE_OPENSSL #if HAVE_OPENSSL
void nsi_set_ssl_session(msiod *iod, SSL_SESSION *sessid) { void nsi_set_ssl_session(msiod *iod, SSL_SESSION *sessid) {
if (sessid) { if (sessid) {
iod->ssl_session = sessid; iod->ssl_session = sessid;
/* No reference counting for the copy stored briefly in nsiod */ /* No reference counting for the copy stored briefly in nsiod */
} }
} }
#endif #endif
/* Sometimes it is useful to store a pointer to information inside /* Sometimes it is useful to store a pointer to information inside the msiod so
the msiod so you can retrieve it during a callback. */ * you can retrieve it during a callback. */
void nsi_setud(nsock_iod nsockiod, void *data) { void nsi_setud(nsock_iod nsockiod, void *data) {
assert(nsockiod); assert(nsockiod);
((msiod *)nsockiod)->userdata = data; ((msiod *)nsockiod)->userdata = data;
} }
/* And the function above wouldn't make much sense if we didn't have a way /* And the function above wouldn't make much sense if we didn't have a way to
to retrieve that data ... */ * retrieve that data... */
void *nsi_getud(nsock_iod nsockiod) { void *nsi_getud(nsock_iod nsockiod) {
assert(nsockiod); assert(nsockiod);
return ((msiod *)nsockiod)->userdata; return ((msiod *)nsockiod)->userdata;
} }
/* Returns 1 if an NSI is communicating via SSL, 0 otherwise */ /* Returns 1 if an NSI is communicating via SSL, 0 otherwise. */
int nsi_checkssl(nsock_iod nsockiod) { int nsi_checkssl(nsock_iod nsockiod) {
return ((msiod *)nsockiod)->ssl? 1 : 0; return (((msiod *)nsockiod)->ssl) ? 1 : 0;
} }
/* Returns the remote peer port (or -1 if unavailable). Note the /* Returns the remote peer port (or -1 if unavailable). Note the return value
return value is a whole int so that -1 can be distinguished from * is a whole int so that -1 can be distinguished from 65535. Port is returned
65535. Port is returned in host byte order. */ * in host byte order. */
int nsi_peerport(nsock_iod nsockiod) { int nsi_peerport(nsock_iod nsockiod) {
msiod *nsi = (msiod *) nsockiod; msiod *nsi = (msiod *)nsockiod;
int fam; int fam;
if (nsi->peerlen <= 0) if (nsi->peerlen <= 0)
return -1; return -1;
fam = ((struct sockaddr_in *) &nsi->peer)->sin_family; fam = ((struct sockaddr_in *)&nsi->peer)->sin_family;
if (fam == AF_INET) if (fam == AF_INET)
return ntohs(((struct sockaddr_in *) &nsi->peer)->sin_port); return ntohs(((struct sockaddr_in *)&nsi->peer)->sin_port);
#if HAVE_IPV6 #if HAVE_IPV6
else if (fam == AF_INET6) else if (fam == AF_INET6)
return ntohs(((struct sockaddr_in6 *) &nsi->peer)->sin6_port); return ntohs(((struct sockaddr_in6 *)&nsi->peer)->sin6_port);
#endif #endif
return -1; return -1;
} }
/* Sets the local address to bind to before connect() */ /* Sets the local address to bind to before connect() */
int nsi_set_localaddr(nsock_iod nsi, struct sockaddr_storage *ss, size_t sslen) int nsi_set_localaddr(nsock_iod nsi, struct sockaddr_storage *ss, size_t sslen) {
{ msiod *iod = (msiod *)nsi;
msiod *iod = (msiod *) nsi;
assert(iod); assert(iod);
@@ -365,13 +374,11 @@ int nsi_set_localaddr(nsock_iod nsi, struct sockaddr_storage *ss, size_t sslen)
return 0; return 0;
} }
/* Sets IPv4 options to apply before connect(). It makes a copy of the /* Sets IPv4 options to apply before connect(). It makes a copy of the options,
* options, so you can free() yours if necessary. This copy is freed * so you can free() yours if necessary. This copy is freed when the iod is
* when the iod is destroyed * destroyed. */
*/ int nsi_set_ipoptions(nsock_iod nsi, void *opts, size_t optslen) {
int nsi_set_ipoptions(nsock_iod nsi, void *opts, size_t optslen) msiod *iod = (msiod *)nsi;
{
msiod *iod = (msiod *) nsi;
assert(iod); assert(iod);
@@ -384,17 +391,24 @@ int nsi_set_ipoptions(nsock_iod nsi, void *opts, size_t optslen)
return 0; return 0;
} }
/* I didn't want to do this. Its an ugly hack, but I suspect it will /* I didn't want to do this. Its an ugly hack, but I suspect it will be
be neccessary. I certainly can't reproduce in nsock EVERYTHING you * neccessary. I certainly can't reproduce in nsock EVERYTHING you might want
might want to do with a socket. So I'm offering you this function * to do with a socket. So I'm offering you this function to obtain the socket
to obtain the socket descriptor which is (usually) wrapped in a * descriptor which is (usually) wrapped in a nsock_iod). You can do
nsock_iod). You can do "reasonable" things with it, like setting * "reasonable" things with it, like setting socket receive buffers. But don't
socket receive buffers. But don't create havok by closing the * create havok by closing the descriptor! If the descriptor you get back is
descriptor! If the descriptor you get back is -1, the iod does not * -1, the iod does not currently possess a valid descriptor */
currently possess a valid descriptor */
int nsi_getsd(nsock_iod nsockiod) { int nsi_getsd(nsock_iod nsockiod) {
msiod *iod = (msiod *)nsockiod;
assert(nsockiod); assert(nsockiod);
return ((msiod *)nsockiod)->sd;
#if HAVE_PCAP
if (iod->pcap)
return ((mspcap *)iod->pcap)->pcap_desc;
else
#endif
return iod->sd;
} }
unsigned long nsi_get_read_count(nsock_iod nsockiod){ unsigned long nsi_get_read_count(nsock_iod nsockiod){
@@ -405,17 +419,18 @@ unsigned long nsi_get_read_count(nsock_iod nsockiod){
unsigned long nsi_get_write_count(nsock_iod nsockiod){ unsigned long nsi_get_write_count(nsock_iod nsockiod){
assert(nsockiod); assert(nsockiod);
return ((msiod *)nsockiod)->write_count; return ((msiod *)nsockiod)->write_count;
} }
int nsi_set_hostname(nsock_iod nsi, const char *hostname) { int nsi_set_hostname(nsock_iod nsi, const char *hostname) {
msiod *iod = (msiod *) nsi; msiod *iod = (msiod *)nsi;
if (iod->hostname != NULL) if (iod->hostname != NULL)
free(iod->hostname); free(iod->hostname);
iod->hostname = strdup(hostname); iod->hostname = strdup(hostname);
if (iod->hostname == NULL) if (iod->hostname == NULL)
return -1; return -1;
return 0; return 0;
} }

View File

@@ -1,3 +1,60 @@
/***************************************************************************
* 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-2011 Insecure.Com *
* 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, Insecure.Com LLC *
* may be willing to sell alternative licenses (contact *
* sales@insecure.com ). *
* *
* As a special exception to the GPL terms, Insecure.Com 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 (none *
* have been found so far). *
* *
* 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 nmap-dev@insecure.org for possible incorporation into the main *
* distribution. By sending these changes to Fyodor or one of the *
* Insecure.Org development mailing lists, it is assumed that you are *
* offering the Nmap Project (Insecure.Com 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.h"
#include "nsock_internal.h" #include "nsock_internal.h"
@@ -8,7 +65,7 @@
#if HAVE_NET_BPF_H #if HAVE_NET_BPF_H
#ifdef _AIX #ifdef _AIX
/* Prevent bpf.h from redefining the DLT_ values to their IFT_ values. (See /* Prevent bpf.h from redefining the DLT_ values to their IFT_ values. (See
similar comment in libpcap/pcap-bpf.c.) */ * similar comment in libpcap/pcap-bpf.c.) */
#undef _AIX #undef _AIX
#include <net/bpf.h> #include <net/bpf.h>
#define _AIX #define _AIX
@@ -23,25 +80,20 @@ extern struct timeval nsock_tod;
#if HAVE_PCAP #if HAVE_PCAP
static int nsock_pcap_get_l3_offset(pcap_t *pt, int *dl); static int nsock_pcap_get_l3_offset(pcap_t *pt, int *dl);
char * nsock_pcap_set_filter(pcap_t *pt, const char *device, const char *bpf); static char * nsock_pcap_set_filter(pcap_t *pt, const char *device, const char *bpf);
/* /* Convert new nsiod to pcap descriptor. Other parameters have the same meaning
* Convert new nsiod to pcap descriptor. Other parameters have the * as for pcap_open_live in pcap(3).
* same meaning as for pcap_open_live in pcap(3).
* device : pcap-style device name * device : pcap-style device name
* snaplen : size of packet to be copied to hanler * snaplen : size of packet to be copied to hanler
* promisc : whether to open device in promiscous mode * promisc : whether to open device in promiscous mode
* bpf_fmt : berkeley filter * bpf_fmt : berkeley filter
* return value: NULL if everything was okay, or error string if error occurred * return value: NULL if everything was okay, or error string if error occurred. */
* */ char* nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod, const char *pcap_device, int snaplen,
char* nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod, int promisc, const char *bpf_fmt, ...) {
const char *pcap_device, int snaplen, int promisc, msiod *nsi = (msiod *)nsiod;
const char *bpf_fmt, ...) mspool *ms = (mspool *)nsp;
mspcap *mp = (mspcap *)nsi->pcap;
{
msiod *nsi = (msiod *) nsiod;
mspool *ms = (mspool *) nsp;
mspcap *mp = (mspcap *) nsi->pcap;
static char errorbuf[128]; static char errorbuf[128];
char err0r[PCAP_ERRBUF_SIZE]; char err0r[PCAP_ERRBUF_SIZE];
/* packet filter string */ /* packet filter string */
@@ -52,38 +104,45 @@ char* nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod,
gettimeofday(&nsock_tod, NULL); gettimeofday(&nsock_tod, NULL);
#ifdef PCAP_CAN_DO_SELECT #ifdef PCAP_CAN_DO_SELECT
#if PCAP_BSD_SELECT_HACK
#if PCAP_BSD_SELECT_HACK
/* MacOsX reports error if to_ms is too big (like INT_MAX) with error /* MacOsX reports error if to_ms is too big (like INT_MAX) with error
* FAILED. Reported error: BIOCSRTIMEOUT: Invalid argument * FAILED. Reported error: BIOCSRTIMEOUT: Invalid argument
* INT_MAX/6 (=357913941) seems to be working...*/ * INT_MAX/6 (=357913941) seems to be working... */
int to_ms = 357913941; int to_ms = 357913941;
#else #else
int to_ms = 200; int to_ms = 200;
#endif #endif /* PCAP_BSD_SELECT_HACK */
#else
#else
int to_ms = 1; int to_ms = 1;
#endif #endif
if(mp) return "nsock-pcap: this nsi already has pcap device opened";
if (mp)
return "nsock-pcap: this nsi already has pcap device opened";
mp = (mspcap *)safe_zalloc(sizeof(mspcap)); mp = (mspcap *)safe_zalloc(sizeof(mspcap));
nsi->pcap = (void*)mp; nsi->pcap = (void *)mp;
va_start(ap, bpf_fmt); va_start(ap, bpf_fmt);
if(Vsnprintf(bpf, sizeof(bpf), bpf_fmt, ap) >= (int) sizeof(bpf)){ if (Vsnprintf(bpf, sizeof(bpf), bpf_fmt, ap) >= (int)sizeof(bpf)) {
va_end(ap); va_end(ap);
return "nsock-pcap: nsock_pcap_open called with too-large bpf filter arg"; return "nsock-pcap: nsock_pcap_open called with too-large bpf filter arg";
} }
va_end(ap); va_end(ap);
if (ms->tracelevel > 0) if (ms->tracelevel > 0)
nsock_trace(ms, "PCAP requested on device '%s' with berkeley filter '%s' (promisc=%i snaplen=%i to_ms=%i) (IOD #%li)", nsock_trace(ms,
"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); pcap_device,bpf, promisc, snaplen, to_ms, nsi->id);
failed = 0; failed = 0;
do { do {
mp->pt = pcap_open_live((char*)pcap_device, snaplen, promisc, to_ms, err0r); mp->pt = pcap_open_live((char* )pcap_device, snaplen, promisc, to_ms, err0r);
if (mp->pt) /* okay, opened!*/ if (mp->pt) /* okay, opened!*/
break; break;
/* sorry, something failed*/ /* sorry, something failed*/
if (++failed >= 3) { if (++failed >= 3) {
mp->pcap_device = strdup(pcap_device); mp->pcap_device = strdup(pcap_device);
@@ -98,95 +157,101 @@ char* nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod,
return "nsock-pcap: can't open pcap! are you root?"; return "nsock-pcap: can't open pcap! are you root?";
} }
fprintf(stderr, "pcap_open_live(%s, %d, %d, %d) FAILED. Reported error: %s. Will wait %d seconds then retry.\n", fprintf(stderr,
"pcap_open_live(%s, %d, %d, %d) FAILED. Reported error: %s. Will wait %d seconds then retry.\n",
pcap_device, snaplen, promisc, to_ms, err0r, 4*failed); pcap_device, snaplen, promisc, to_ms, err0r, 4*failed);
sleep(4* failed); sleep(4* failed);
}while(1); } while (1);
e = nsock_pcap_set_filter(mp->pt, pcap_device, bpf); e = nsock_pcap_set_filter(mp->pt, pcap_device, bpf);
if(e) return e; if (e)
return e;
#ifdef WIN32
#ifdef WIN32
/* We want any responses back ASAP */ /* We want any responses back ASAP */
pcap_setmintocopy(mp->pt, 1); pcap_setmintocopy(mp->pt, 1);
#endif #endif
mp->l3_offset = nsock_pcap_get_l3_offset(mp->pt, &datalink); mp->l3_offset = nsock_pcap_get_l3_offset(mp->pt, &datalink);
mp->snaplen = snaplen; mp->snaplen = snaplen;
mp->datalink = datalink; mp->datalink = datalink;
mp->pcap_device = strdup(pcap_device); mp->pcap_device = strdup(pcap_device);
#ifdef PCAP_CAN_DO_SELECT #ifdef PCAP_CAN_DO_SELECT
mp->pcap_desc = pcap_get_selectable_fd(mp->pt); mp->pcap_desc = pcap_get_selectable_fd(mp->pt);
#else #else
mp->pcap_desc = -1; mp->pcap_desc = -1;
#endif #endif
mp->readsd_count = 0; mp->readsd_count = 0;
/* Without setting this ioctl, some systems (BSDs, though it depends on /* Without setting this ioctl, some systems (BSDs, though it depends on the
the release) will buffer packets in non-blocking mode and only * release) will buffer packets in non-blocking mode and only return them in a
return them in a bunch when the buffer is full. Setting the ioctl * bunch when the buffer is full. Setting the ioctl makes each one be
makes each one be delivered immediately. This is how Linux works by * delivered immediately. This is how Linux works by default. See the comments
default. See the comments surrounding the ssetting of BIOCIMMEDIATE * surrounding the ssetting of BIOCIMMEDIATE in libpcap/pcap-bpf.c. */
in libpcap/pcap-bpf.c. */
#ifdef BIOCIMMEDIATE #ifdef BIOCIMMEDIATE
if (mp->pcap_desc != -1) { if (mp->pcap_desc != -1) {
int immediate = 1; int immediate = 1;
if (ioctl(mp->pcap_desc, BIOCIMMEDIATE, &immediate) < 0) if (ioctl(mp->pcap_desc, BIOCIMMEDIATE, &immediate) < 0)
fatal("Cannot set BIOCIMMEDIATE on pcap descriptor"); fatal("Cannot set BIOCIMMEDIATE on pcap descriptor");
} }
#endif #endif
/* Set device non-blocking */ /* Set device non-blocking */
if(pcap_setnonblock(mp->pt, 1, err0r) < 0){ if (pcap_setnonblock(mp->pt, 1, err0r) < 0) {
/* I can't do select() on pcap! blockig + no_select is fatal */ /* I can't do select() on pcap! blockig + no_select is fatal */
if(mp->pcap_desc < 0){ if(mp->pcap_desc < 0){
Snprintf(errorbuf, sizeof(errorbuf),"nsock-pcap: Failed to set pcap descriptor on device %s to nonblocking state: %s", pcap_device, err0r); Snprintf(errorbuf, sizeof(errorbuf),
"nsock-pcap: Failed to set pcap descriptor on device %s to nonblocking state: %s",
pcap_device, err0r);
return errorbuf; return errorbuf;
} }
/* When we use bsd hack we also need to set non-blocking */ /* When we use bsd hack we also need to set non-blocking */
#ifdef PCAP_BSD_SELECT_HACK #ifdef PCAP_BSD_SELECT_HACK
Snprintf(errorbuf, sizeof(errorbuf),"nsock-pcap: Failed to set pcap descriptor on device %s to nonblocking state: %s", pcap_device, err0r); Snprintf(errorbuf, sizeof(errorbuf),
"nsock-pcap: Failed to set pcap descriptor on device %s to nonblocking state: %s",
pcap_device, err0r);
return errorbuf; return errorbuf;
#endif #endif
/* in other case, we can accept blocking pcap */ /* in other case, we can accept blocking pcap */
fprintf(stderr, "Failed to set pcap descriptor on device %s to nonblocking state: %s", pcap_device, err0r); fprintf(stderr, "Failed to set pcap descriptor on device %s to nonblocking state: %s",
pcap_device, err0r);
} }
if (ms->tracelevel > 0) if (ms->tracelevel > 0)
nsock_trace(ms, "PCAP created successfully on device '%s' (pcap_desc=%i bsd_hack=%i to_valid=%i l3_offset=%i) (IOD #%li)", nsock_trace(ms, "PCAP created successfully on device '%s' (pcap_desc=%i bsd_hack=%i to_valid=%i l3_offset=%i) (IOD #%li)",
pcap_device, pcap_device,
mp->pcap_desc, mp->pcap_desc,
#if PCAP_BSD_SELECT_HACK #if PCAP_BSD_SELECT_HACK
1, 1,
#else #else
0, 0,
#endif #endif
#if PCAP_RECV_TIMEVAL_VALID #if PCAP_RECV_TIMEVAL_VALID
1, 1,
#else #else
0, 0,
#endif #endif
mp->l3_offset, mp->l3_offset,
nsi->id); nsi->id);
return NULL; return NULL;
} }
char *nsock_pcap_set_filter(pcap_t *pt, const char *device, const char *bpf) char *nsock_pcap_set_filter(pcap_t *pt, const char *device, const char *bpf) {
{
struct bpf_program fcode; struct bpf_program fcode;
static char errorbuf[128]; static char errorbuf[128];
// log_write(LOG_STDOUT, "Packet capture filter (device %s): %s\n", device, buf); /* log_write(LOG_STDOUT, "Packet capture filter (device %s): %s\n", device, buf); */
if (pcap_compile(pt, &fcode, (char*)bpf, 1, 0) < 0){ if (pcap_compile(pt, &fcode, (char*)bpf, 1, 0) < 0) {
Snprintf(errorbuf, sizeof(errorbuf), "Error compiling our pcap filter: %s\n", pcap_geterr(pt)); Snprintf(errorbuf, sizeof(errorbuf), "Error compiling our pcap filter: %s\n", pcap_geterr(pt));
return errorbuf; return errorbuf;
} }
if (pcap_setfilter(pt, &fcode) < 0 ){ if (pcap_setfilter(pt, &fcode) < 0 ) {
Snprintf(errorbuf, sizeof(errorbuf),"Failed to set the pcap filter: %s\n", pcap_geterr(pt)); Snprintf(errorbuf, sizeof(errorbuf),"Failed to set the pcap filter: %s\n", pcap_geterr(pt));
return errorbuf; return errorbuf;
} }
@@ -195,16 +260,16 @@ char *nsock_pcap_set_filter(pcap_t *pt, const char *device, const char *bpf)
return NULL; return NULL;
} }
static int nsock_pcap_get_l3_offset(pcap_t *pt, int *dl){ int nsock_pcap_get_l3_offset(pcap_t *pt, int *dl) {
int datalink; int datalink;
unsigned int offset = 0; unsigned int offset = 0;
/* New packet capture device, need to recompute offset */ /* New packet capture device, need to recompute offset */
if ( (datalink = pcap_datalink(pt)) < 0) if ((datalink = pcap_datalink(pt)) < 0)
fatal("Cannot obtain datalink information: %s", pcap_geterr(pt)); fatal("Cannot obtain datalink information: %s", pcap_geterr(pt));
/* NOTE: IF A NEW OFFSET EVER EXCEEDS THE CURRENT MAX (24), ADJUST /* XXX NOTE:
MAX_LINK_HEADERSZ in tcpip.h */ * if a new offset ever exceeds the current max (24), adjust max_link_headersz in tcpip.h */
switch(datalink) { switch(datalink) {
case DLT_EN10MB: offset = 14; break; case DLT_EN10MB: offset = 14; break;
case DLT_IEEE802: offset = 22; break; case DLT_IEEE802: offset = 22; break;
@@ -262,48 +327,39 @@ static int nsock_pcap_get_l3_offset(pcap_t *pt, int *dl){
default: /* Sorry, link type is unknown. */ default: /* Sorry, link type is unknown. */
fatal("Unknown datalink type %d.\n", datalink); fatal("Unknown datalink type %d.\n", datalink);
} }
if(dl) if (dl)
*dl = datalink; *dl = datalink;
return(offset); return (offset);
} }
/* Requests exacly one packet to be captured. */
/*
* Requests exacly one packet to be captured.
* */
nsock_event_id nsock_pcap_read_packet(nsock_pool nsp, nsock_iod nsiod, nsock_event_id nsock_pcap_read_packet(nsock_pool nsp, nsock_iod nsiod,
nsock_ev_handler handler, int timeout_msecs, nsock_ev_handler handler, int timeout_msecs, void *userdata) {
void *userdata) msiod *nsi = (msiod *)nsiod;
{ mspool *ms = (mspool *)nsp;
msiod *nsi = (msiod *) nsiod;
mspool *ms = (mspool *) nsp;
msevent *nse; msevent *nse;
nse = msevent_new(ms, NSE_TYPE_PCAP_READ, nsi, timeout_msecs, handler, userdata); nse = msevent_new(ms, NSE_TYPE_PCAP_READ, nsi, timeout_msecs, handler, userdata);
assert(nse); assert(nse);
if (ms->tracelevel > 0) { if (ms->tracelevel > 0)
nsock_trace(ms, "Pcap read request from IOD #%li EID %li", nsock_trace(ms, "Pcap read request from IOD #%li EID %li",
nsi->id, nse->id); nsi->id, nse->id);
}
nsp_add_event(ms, nse); nsp_add_event(ms, nse);
return nse->id; return nse->id;
} }
/* /* Remember that pcap descriptor is in nonblocking state. */
* Remember that pcap descriptor is in nonblocking state. */ int do_actual_pcap_read(msevent *nse) {
int do_actual_pcap_read(msevent *nse) mspcap *mp = (mspcap *)nse->iod->pcap;
{
msiod *iod = nse->iod;
mspcap *mp = (mspcap *) iod->pcap;
nsock_pcap npp; nsock_pcap npp;
nsock_pcap *n; nsock_pcap *n;
struct pcap_pkthdr *pkt_header; struct pcap_pkthdr *pkt_header;
const unsigned char *pkt_data = NULL; const unsigned char *pkt_data = NULL;
int rc; int rc;
memset(&npp, 0, sizeof(nsock_pcap)); memset(&npp, 0, sizeof(nsock_pcap));
if (nse->iod->nsp->tracelevel > 2) if (nse->iod->nsp->tracelevel > 2)
@@ -313,7 +369,7 @@ int do_actual_pcap_read(msevent *nse)
assert( FILESPACE_LENGTH(&(nse->iobuf)) == 0 ); assert( FILESPACE_LENGTH(&(nse->iobuf)) == 0 );
rc = pcap_next_ex(mp->pt, &pkt_header, &pkt_data); rc = pcap_next_ex(mp->pt, &pkt_header, &pkt_data);
switch(rc){ switch(rc) {
case 1: /* read good packet */ case 1: /* read good packet */
#ifdef PCAP_RECV_TIMEVAL_VALID #ifdef PCAP_RECV_TIMEVAL_VALID
npp.ts = pkt_header->ts; npp.ts = pkt_header->ts;
@@ -324,19 +380,24 @@ int do_actual_pcap_read(msevent *nse)
npp.len = pkt_header->len; npp.len = pkt_header->len;
npp.caplen = pkt_header->caplen; npp.caplen = pkt_header->caplen;
npp.packet = pkt_data; npp.packet = pkt_data;
fscat(&(nse->iobuf), (char*)&npp, sizeof(npp));
fscat(&(nse->iobuf), (char*)pkt_data, npp.caplen); fscat(&(nse->iobuf), (char *)&npp, sizeof(npp));
n = (nsock_pcap *) FILESPACE_STR(&(nse->iobuf)); fscat(&(nse->iobuf), (char *)pkt_data, npp.caplen);
n->packet = (unsigned char*)FILESPACE_STR(&(nse->iobuf))+sizeof(npp); n = (nsock_pcap *)FILESPACE_STR(&(nse->iobuf));
n->packet = (unsigned char *)FILESPACE_STR(&(nse->iobuf)) + sizeof(npp);
if (nse->iod->nsp->tracelevel > 2) if (nse->iod->nsp->tracelevel > 2)
nsock_trace(nse->iod->nsp, "PCAP do_actual_pcap_read READ (IOD #%li) (EID #%li) size=%i", nsock_trace(nse->iod->nsp, "PCAP do_actual_pcap_read READ (IOD #%li) (EID #%li) size=%i",
nse->iod->id, nse->id, pkt_header->caplen); nse->iod->id, nse->id, pkt_header->caplen);
return(1); return(1);
case 0: /* timeout */ case 0: /* timeout */
return(0); return(0);
case -1: /* error */ case -1: /* error */
fatal("pcap_next_ex() fatal error while reading from pcap: %s\n", pcap_geterr(mp->pt)); fatal("pcap_next_ex() fatal error while reading from pcap: %s\n", pcap_geterr(mp->pt));
break; break;
case -2: /* no more packets in savefile (if reading from one) */ case -2: /* no more packets in savefile (if reading from one) */
default: default:
assert(0); assert(0);
@@ -344,53 +405,59 @@ int do_actual_pcap_read(msevent *nse)
return 0; return 0;
} }
void nse_readpcap(nsock_event nsee, void nse_readpcap(nsock_event nsee, const unsigned char **l2_data, size_t *l2_len,
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) {
const unsigned char **l3_data, size_t *l3_len,
size_t *packet_len, struct timeval *ts)
{
msevent *nse = (msevent *)nsee; msevent *nse = (msevent *)nsee;
msiod *iod = nse->iod; msiod *iod = nse->iod;
mspcap *mp = (mspcap *) iod->pcap; mspcap *mp = (mspcap *)iod->pcap;
size_t l2l; size_t l2l;
size_t l3l; size_t l3l;
nsock_pcap *n = (nsock_pcap *) FILESPACE_STR(&(nse->iobuf)); nsock_pcap *n = (nsock_pcap *)FILESPACE_STR(&(nse->iobuf));
if(FILESPACE_LENGTH(&(nse->iobuf)) < sizeof(nsock_pcap)){ if (FILESPACE_LENGTH(&(nse->iobuf)) < sizeof(nsock_pcap)) {
if(l2_data) *l2_data = NULL; if (l2_data)
if(l2_len ) *l2_len = 0; *l2_data = NULL;
if(l3_data) *l3_data = NULL; if (l2_len)
if(l3_len ) *l3_len = 0; *l2_len = 0;
if(packet_len) *packet_len = 0; if (l3_data)
*l3_data = NULL;
if (l3_len)
*l3_len = 0;
if (packet_len)
*packet_len = 0;
return; return;
} }
l2l = MIN(mp->l3_offset, n->caplen); l2l = MIN(mp->l3_offset, n->caplen);
l3l = MAX(0, n->caplen-mp->l3_offset); l3l = MAX(0, n->caplen-mp->l3_offset);
if(l2_data) *l2_data = n->packet; if (l2_data)
if(l2_len ) *l2_len = l2l; *l2_data = n->packet;
if(l3_data) *l3_data = l3l>0? n->packet+l2l : NULL; if (l2_len)
if(l3_len ) *l3_len = l3l; *l2_len = l2l;
if(packet_len) *packet_len = n->len; if (l3_data)
if(ts) *ts = n->ts; *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; return;
} }
int nsi_pcap_linktype(nsock_iod nsiod){ int nsi_pcap_linktype(nsock_iod nsiod) {
msiod *nsi = (msiod *) nsiod; msiod *nsi = (msiod *)nsiod;
mspcap *mp = (mspcap *) nsi->pcap; mspcap *mp = (mspcap *)nsi->pcap;
assert(mp); assert(mp);
return(mp->datalink); return (mp->datalink);
} }
int nsi_is_pcap(nsock_iod nsiod){ int nsi_is_pcap(nsock_iod nsiod) {
msiod *nsi = (msiod *) nsiod; msiod *nsi = (msiod *)nsiod;
mspcap *mp = (mspcap *) nsi->pcap; mspcap *mp = (mspcap *)nsi->pcap;
return(mp!=NULL); return (mp != NULL);
} }
#endif /* HAVE_PCAP */
#endif // HAVE_PCAP

View File

@@ -1,3 +1,60 @@
/***************************************************************************
* 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-2011 Insecure.Com *
* 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, Insecure.Com LLC *
* may be willing to sell alternative licenses (contact *
* sales@insecure.com ). *
* *
* As a special exception to the GPL terms, Insecure.Com 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 (none *
* have been found so far). *
* *
* 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 nmap-dev@insecure.org for possible incorporation into the main *
* distribution. By sending these changes to Fyodor or one of the *
* Insecure.Org development mailing lists, it is assumed that you are *
* offering the Nmap Project (Insecure.Com 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 #ifndef NSOCK_PCAP_H
#define NSOCK_PCAP_H #define NSOCK_PCAP_H
@@ -23,9 +80,9 @@
* If that fails than we can't do any sniffing from that box. * If that fails than we can't do any sniffing from that box.
* *
* In all cases we try to set descriptor to non-blocking mode. * In all cases we try to set descriptor to non-blocking mode.
* */ */
// Returns whether the system supports pcap_get_selectable_fd() properly /* Returns whether the system supports pcap_get_selectable_fd() properly */
#if !defined(WIN32) && !defined(SOLARIS) #if !defined(WIN32) && !defined(SOLARIS)
#define PCAP_CAN_DO_SELECT 1 #define PCAP_CAN_DO_SELECT 1
#endif #endif
@@ -54,14 +111,14 @@
* on BPF devices, so the workaround isn't necessary, although it does no harm.) * on BPF devices, so the workaround isn't necessary, although it does no harm.)
*/ */
#if defined(MACOSX) || defined(FREEBSD) || defined(OPENBSD) #if defined(MACOSX) || defined(FREEBSD) || defined(OPENBSD)
// Well, now select() is not receiving any pcap events on MACOSX, but maybe it will someday :) /* 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. * in both cases. It never hurts to enable this feature. It just has performance penalty. */
#define PCAP_BSD_SELECT_HACK 1 #define PCAP_BSD_SELECT_HACK 1
#endif #endif
// Returns whether the packet receive time value obtained from libpcap /* Returns whether the packet receive time value obtained from libpcap
// (and thus by readip_pcap()) should be considered valid. When * (and thus by readip_pcap()) should be considered valid. When
// invalid (Windows and Amiga), readip_pcap returns the time you called it. * invalid (Windows and Amiga), readip_pcap returns the time you called it. */
#if !defined(WIN32) && !defined(__amigaos__) #if !defined(WIN32) && !defined(__amigaos__)
#define PCAP_RECV_TIMEVAL_VALID 1 #define PCAP_RECV_TIMEVAL_VALID 1
#endif #endif
@@ -71,7 +128,7 @@ typedef struct{
pcap_t *pt; pcap_t *pt;
int pcap_desc; int pcap_desc;
/* Like the corresponding member in msiod, when this reaches 0 we stop /* Like the corresponding member in msiod, when this reaches 0 we stop
watching the socket for readability. */ * watching the socket for readability. */
int readsd_count; int readsd_count;
int datalink; int datalink;
int l3_offset; int l3_offset;
@@ -79,15 +136,15 @@ typedef struct{
char *pcap_device; char *pcap_device;
} mspcap; } mspcap;
typedef struct{ typedef struct{
struct timeval ts; struct timeval ts;
int caplen; int caplen;
int len; int len;
const unsigned char *packet; // caplen bytes const unsigned char *packet; /* caplen bytes */
} nsock_pcap; } nsock_pcap;
int do_actual_pcap_read(msevent *nse); int do_actual_pcap_read(msevent *nse);
#endif /* HAVE_PCAP */ #endif /* HAVE_PCAP */
#endif /* NSOCK_PCAP_H */ #endif /* NSOCK_PCAP_H */

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* nsock_pool.c -- This contains the functions that deal with creating, * * nsock_pool.c -- This contains the functions that deal with creating, *
* destroying, and otherwise manipulating nsock_pools (and their internal * * destroying, and otherwise manipulating nsock_pools (and their internal *
@@ -71,15 +70,210 @@
#endif #endif
#include <signal.h> #include <signal.h>
extern struct timeval nsock_tod; extern struct timeval nsock_tod;
unsigned long nsp_next_id = 2; unsigned long nsp_next_id = 2;
static int nsocklib_initialized = 0; /* To use this library, the first thing /* To use this library, the first thing they must do is create a pool
they must do is create a pool -- so * so we do the initialization during the first pool creation */
we do the initialization during the static int nsocklib_initialized = 0;
first pool creation */
static void nsock_library_initialize(void) {
/* defined in nsock_engines.h */
struct io_engine *get_io_engine(const char *engine_hint);
/* ---- INTERNAL FUNCTIONS PROTOTYPES ---- */
static void nsock_library_initialize(void);
/* --------------------------------------- */
/* Every mst has an ID that is unique across the program execution */
unsigned long nsp_getid(nsock_pool nsp) {
mspool *mt = (mspool *)nsp;
return mt->id;
}
/* 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 nsp_geterrorcode(nsock_pool nsp) {
mspool *mt = (mspool *)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 nsp_setud(nsock_pool nsp, void *data) {
mspool *mt = (mspool *)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 *nsp_getud(nsock_pool nsp) {
mspool *mt = (mspool *)nsp;
return mt->userdata;
}
/* Sets a trace/debug level and stream. A level of 0 (the default) turns
* tracing off, while higher numbers are more verbose. If the stream given is
* NULL, it defaults to stdout. This is generally only used for debugging
* purposes. A level of 1 or 2 is usually sufficient, but 10 will ensure you get
* everything. The basetime can be NULL to print trace lines with the current
* time, otherwise the difference between the current time and basetime will be
* used (the time program execution starts would be a good candidate) */
void nsp_settrace(nsock_pool nsp, FILE *file, int level, const struct timeval *basetime) {
mspool *mt = (mspool *)nsp;
if (file == NULL)
mt->tracefile = stdout;
else
mt->tracefile = file;
mt->tracelevel = level;
if (!basetime)
memset(&mt->tracebasetime, 0, sizeof(struct timeval));
else
mt->tracebasetime = *basetime;
}
/* Turns on or off broadcast support on new sockets. Default is off (0, false)
* set in nsp_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 nsp_setbroadcast(nsock_pool nsp, int optval) {
mspool *mt = (mspool *)nsp;
mt->broadcast = optval;
}
/* 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 nsp_new(void *userdata) {
mspool *nsp;
/* initialize the library in not already done */
if (!nsocklib_initialized) {
nsock_library_initialize();
nsocklib_initialized = 1;
}
nsp = (mspool *)safe_malloc(sizeof(*nsp));
memset(nsp, 0, sizeof(*nsp));
gettimeofday(&nsock_tod, NULL);
nsp_settrace(nsp, NULL, 0, NULL);
nsp->id = nsp_next_id++;
nsp->userdata = userdata;
nsp->engine = get_io_engine(NULL);
nsp->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 list */
gh_list_init(&nsp->timer_events);
/* 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;
#if HAVE_OPENSSL
nsp->sslctx = NULL;
#endif
return (nsock_pool)nsp;
}
/* If nsp_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 nsp_delete(nsock_pool ms_pool) {
mspool *nsp = (mspool *)ms_pool;
msevent *nse;
msiod *nsi;
int i;
gh_list_elem *current, *next;
gh_list *event_lists[] = {
&nsp->connect_events,
&nsp->read_events,
&nsp->write_events,
&nsp->timer_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) {
nse = (msevent *)gh_list_pop(event_lists[i]);
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);
}
msevent_delete(nsp, nse);
}
gh_list_free(event_lists[i]);
}
/* foreach msiod */
for (current = GH_LIST_FIRST_ELEM(&nsp->active_iods); current != NULL; current = next) {
next = GH_LIST_ELEM_NEXT(current);
nsi = (msiod *)GH_LIST_ELEM_DATA(current);
nsi_delete(nsi, NSOCK_PENDING_ERROR);
gh_list_remove_elem(&nsp->active_iods, current);
gh_list_prepend(&nsp->free_iods, nsi);
}
/* Now we free all the memory in the free iod list */
while ((nsi = (msiod *)gh_list_pop(&nsp->free_iods))) {
free(nsi);
}
while ((nse = (msevent *)gh_list_pop(&nsp->free_events))) {
free(nse);
}
gh_list_free(&nsp->active_iods);
gh_list_free(&nsp->free_iods);
gh_list_free(&nsp->free_events);
nsp->engine->destroy(nsp);
#if HAVE_OPENSSL
if (nsp->sslctx != NULL)
SSL_CTX_free(nsp->sslctx);
#endif
free(nsp);
}
void nsock_library_initialize(void) {
int res; int res;
/* We want to make darn sure the evil SIGPIPE is ignored */ /* We want to make darn sure the evil SIGPIPE is ignored */
@@ -94,183 +288,3 @@ static void nsock_library_initialize(void) {
#endif #endif
} }
/* Every mst has an ID that is unique across the program execution */
unsigned long nsp_getid(nsock_pool nsp) {
mspool *mt = (mspool *) nsp;
return mt->id;
}
/* 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 nsp_geterrorcode(nsock_pool nsp) {
mspool *mt = (mspool *) 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 nsp_setud(nsock_pool nsp, void *data) {
mspool *mt = (mspool *) 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 *nsp_getud(nsock_pool nsp) {
mspool *mt = (mspool *) nsp;
return mt->userdata;
}
/* Sets a trace/debug level and stream. A level of 0 (the default)
turns tracing off, while higher numbers are more verbose. If the
stream given is NULL, it defaults to stdout. This is generally only
used for debugging purposes. A level of 1 or 2 is usually sufficient,
but 10 will ensure you get everything. The basetime can be NULL to
print trace lines with the current time, otherwise the difference
between the current time and basetime will be used (the time program
execution starts would be a good candidate) */
void nsp_settrace(nsock_pool nsp, FILE *file, int level, const struct timeval *basetime) {
mspool *mt = (mspool *) nsp;
if (file == NULL)
mt->tracefile = stdout;
else
mt->tracefile = file;
mt->tracelevel = level;
if (!basetime)
memset(&(mt->tracebasetime), 0, sizeof(struct timeval));
else mt->tracebasetime = *basetime;
}
/* Turns on or off broadcast support on new sockets. Default is off
(0, false) set in nsp_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 nsp_setbroadcast(nsock_pool nsp, int optval) {
mspool *mt = (mspool *) nsp;
mt->broadcast = optval;
}
/* 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 nsp_new(void *userdata) {
mspool *nsp;
nsp = (mspool *) safe_malloc(sizeof(*nsp));
memset(nsp, 0, sizeof(*nsp));
gettimeofday(&nsock_tod, NULL);
nsp_settrace(nsp, NULL, 0, NULL);
nsp->broadcast = 0;
if (!nsocklib_initialized) {
nsock_library_initialize();
nsocklib_initialized = 1;
}
nsp->id = nsp_next_id++;
/* Now to init the nsock_io_info */
FD_ZERO(&nsp->mioi.fds_master_r);
FD_ZERO(&nsp->mioi.fds_master_w);
FD_ZERO(&nsp->mioi.fds_master_x);
nsp->mioi.max_sd = -1;
nsp->mioi.results_left = 0;
/* Next comes the event list structure */
gh_list_init(&nsp->evl.connect_events);
gh_list_init(&nsp->evl.read_events);
gh_list_init(&nsp->evl.write_events);
gh_list_init(&nsp->evl.timer_events);
#if HAVE_PCAP
gh_list_init(&nsp->evl.pcap_read_events);
#endif
gh_list_init(&nsp->evl.free_events);
nsp->evl.next_ev.tv_sec = 0;
nsp->evl.events_pending = 0;
nsp->userdata = userdata;
gh_list_init(&nsp->free_iods);
gh_list_init(&nsp->active_iods);
nsp->next_event_serial = 1;
nsp->quit = 0;
#if HAVE_OPENSSL
nsp->sslctx = NULL;
#endif
return (nsock_pool) nsp;
}
/* If nsp_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 nsp_delete(nsock_pool ms_pool) {
mspool *nsp = (mspool *) ms_pool;
gh_list *event_lists[] = { &nsp->evl.connect_events,
&nsp->evl.read_events,
&nsp->evl.write_events,
&nsp->evl.timer_events,
#if HAVE_PCAP
&nsp->evl.pcap_read_events,
#endif
0
};
int current_list_idx;
msevent *nse;
msiod *nsi;
gh_list_elem *current, *next;
assert(nsp);
/* First I go through all the events sending NSE_STATUS_KILL */
/* foreach list */
for(current_list_idx = 0; event_lists[current_list_idx] != NULL;
current_list_idx++) {
while(GH_LIST_COUNT(event_lists[current_list_idx]) > 0) {
nse = (msevent *) gh_list_pop(event_lists[current_list_idx]);
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);
}
msevent_delete(nsp, nse);
}
gh_list_free(event_lists[current_list_idx]);
}
/* Then I go through and kill the iods */
for(current = GH_LIST_FIRST_ELEM(&nsp->active_iods);
current != NULL; current = next) {
next = GH_LIST_ELEM_NEXT(current);
nsi = (msiod *) GH_LIST_ELEM_DATA(current);
nsi_delete(nsi, NSOCK_PENDING_ERROR);
}
/* Now we free all the memory in the free iod list */
while((nsi = (msiod *) gh_list_pop(&nsp->free_iods))) {
free(nsi);
}
while((nsi = (msiod *) gh_list_pop(&nsp->evl.free_events))) {
free(nsi);
}
gh_list_free(&nsp->evl.free_events);
gh_list_free(&nsp->active_iods);
gh_list_free(&nsp->free_iods);
#if HAVE_OPENSSL
if (nsp->sslctx != NULL)
SSL_CTX_free(nsp->sslctx);
#endif
free(nsp);
}

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* nsock_read.c -- This contains the functions for requesting various read * * nsock_read.c -- This contains the functions for requesting various read *
* events from the nsock parallel socket event library * * events from the nsock parallel socket event library *
@@ -58,30 +57,27 @@
#include "nsock_internal.h" #include "nsock_internal.h"
/* 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 tiemout 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) {
msiod *nsi = (msiod *) ms_iod;
mspool *ms = (mspool *) nsp;
msevent *nse;
/* 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 tiemout 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) {
msiod *nsi = (msiod *)ms_iod;
mspool *ms = (mspool *)nsp;
msevent *nse;
nse = msevent_new(ms, NSE_TYPE_READ, nsi, timeout_msecs, handler, userdata); nse = msevent_new(ms, NSE_TYPE_READ, nsi, timeout_msecs, handler, userdata);
assert(nse); assert(nse);
if (ms->tracelevel > 0) { if (ms->tracelevel > 0) {
if (nsi->peerlen > 0) if (nsi->peerlen > 0)
nsock_trace(ms, "Read request for %d lines from IOD #%li [%s:%hu] EID %li", nlines, nsi->id, nsock_trace(ms, "Read request for %d lines from IOD #%li [%s:%d] EID %li", nlines, nsi->id,
inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi), nse->id); inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi), nse->id);
else else
nsock_trace(ms, "Read request for %d lines from IOD #%li (peer unspecified) EID %li", nlines, nsock_trace(ms, "Read request for %d lines from IOD #%li (peer unspecified) EID %li", nlines, nsi->id, nse->id);
nsi->id, nse->id);
} }
nse->readinfo.read_type = NSOCK_READLINES; nse->readinfo.read_type = NSOCK_READLINES;
@@ -92,14 +88,12 @@ nsock_event_id nsock_readlines(nsock_pool nsp, nsock_iod ms_iod,
return nse->id; return nse->id;
} }
/* Same as above, except it tries to read at least 'nbytes' instead of /* Same as above, except it tries to read at least 'nbytes' instead of 'nlines'. */
'nlines'. */ nsock_event_id nsock_readbytes(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
nsock_event_id nsock_readbytes(nsock_pool nsp, nsock_iod ms_iod,
nsock_ev_handler handler, int timeout_msecs,
void *userdata, int nbytes) { void *userdata, int nbytes) {
msiod *nsi = (msiod *) ms_iod; msiod *nsi = (msiod *)ms_iod;
mspool *ms = (mspool *) nsp; mspool *ms = (mspool *)nsp;
msevent *nse; msevent *nse;
nse = msevent_new(ms, NSE_TYPE_READ, nsi, timeout_msecs, handler, userdata); nse = msevent_new(ms, NSE_TYPE_READ, nsi, timeout_msecs, handler, userdata);
@@ -107,11 +101,10 @@ nsock_event_id nsock_readbytes(nsock_pool nsp, nsock_iod ms_iod,
if (ms->tracelevel > 0) { if (ms->tracelevel > 0) {
if (nsi->peerlen > 0) if (nsi->peerlen > 0)
nsock_trace(ms, "Read request for %d bytes from IOD #%li [%s:%hu] EID %li", nbytes, nsi->id, nsock_trace(ms, "Read request for %d bytes from IOD #%li [%s:%d] EID %li", nbytes, nsi->id,
inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi), nse->id); inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi), nse->id);
else else
nsock_trace(ms, "Read request for %d bytes from IOD #%li (peer unspecified) EID %li", nbytes, nsock_trace(ms, "Read request for %d bytes from IOD #%li (peer unspecified) EID %li", nbytes, nsi->id, nse->id);
nsi->id, nse->id);
} }
nse->readinfo.read_type = NSOCK_READBYTES; nse->readinfo.read_type = NSOCK_READBYTES;
@@ -120,18 +113,14 @@ nsock_event_id nsock_readbytes(nsock_pool nsp, nsock_iod ms_iod,
nsp_add_event(ms, nse); nsp_add_event(ms, nse);
return nse->id; return nse->id;
} }
/* The simplest read function -- returns NSE_STATUS_SUCCESS when it /* The simplest read function -- returns NSE_STATUS_SUCCESS when it
reads anything, otherwise it returns timeout, eof, or error as * reads anything, otherwise it returns timeout, eof, or error as appropriate */
appropriate */ nsock_event_id nsock_read(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs, void *userdata) {
nsock_event_id nsock_read(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, msiod *nsi = (msiod *)ms_iod;
int timeout_msecs, void *userdata) { mspool *ms = (mspool *)nsp;
msiod *nsi = (msiod *) ms_iod;
mspool *ms = (mspool *) nsp;
msevent *nse; msevent *nse;
nse = msevent_new(ms, NSE_TYPE_READ, nsi, timeout_msecs, handler, userdata); nse = msevent_new(ms, NSE_TYPE_READ, nsi, timeout_msecs, handler, userdata);
@@ -139,9 +128,11 @@ nsock_event_id nsock_read(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler han
if (ms->tracelevel > 0) { if (ms->tracelevel > 0) {
if (nsi->peerlen > 0) if (nsi->peerlen > 0)
nsock_trace(ms, "Read request from IOD #%li [%s:%hu] (timeout: %dms) EID %li", nsi->id, inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi), timeout_msecs, nse->id); nsock_trace(ms, "Read request from IOD #%li [%s:%d] (timeout: %dms) EID %li", nsi->id,
inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi), timeout_msecs, nse->id);
else else
nsock_trace(ms, "Read request from IOD #%li (peer unspecified) (timeout: %dms) EID %li", nsi->id, timeout_msecs, nse->id); nsock_trace(ms, "Read request from IOD #%li (peer unspecified) (timeout: %dms) EID %li",
nsi->id, timeout_msecs, nse->id);
} }
nse->readinfo.read_type = NSOCK_READ; nse->readinfo.read_type = NSOCK_READ;
@@ -149,6 +140,5 @@ nsock_event_id nsock_read(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler han
nsp_add_event(ms, nse); nsp_add_event(ms, nse);
return nse->id; return nse->id;
} }

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* nsock_ssl.c -- This contains functions that relate somewhat exclusively * * nsock_ssl.c -- This contains functions that relate somewhat exclusively *
* to SSL (over TCP) support in nsock. Where SSL support is incidental, * * to SSL (over TCP) support in nsock. Where SSL support is incidental, *
@@ -67,88 +66,87 @@
#if HAVE_OPENSSL #if HAVE_OPENSSL
/* Disallow anonymous ciphers (Diffie-Hellman key agreement), low bit-strength /* Disallow anonymous ciphers (Diffie-Hellman key agreement), low bit-strength
ciphers, export-crippled ciphers, and MD5. Prefer ciphers in decreasing order * 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 * 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. To see exactly what ciphers are enabled, use the command
openssl ciphers -v '...' * openssl ciphers -v '...'
where ... is the string below. */ * where ... is the string below. */
#define CIPHERS_SECURE "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH" #define CIPHERS_SECURE "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
/* This list of ciphers is for speed and compatibility, not security. Any cipher /* 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 * 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. */ * (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" #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; extern struct timeval nsock_tod;
/* Create an SSL_CTX and do initialization that is common to nsp_ssl_init and /* Create an SSL_CTX and do initialization that is common to nsp_ssl_init and
nsp_ssl_init_max_speed. */ * nsp_ssl_init_max_speed. */
static SSL_CTX *ssl_init_common() { static SSL_CTX *ssl_init_common() {
SSL_CTX *ctx; SSL_CTX *ctx;
SSL_load_error_strings(); SSL_load_error_strings();
SSL_library_init(); SSL_library_init();
ctx = SSL_CTX_new( SSLv23_client_method() ); ctx = SSL_CTX_new(SSLv23_client_method());
if ( ! ctx ) { if (!ctx) {
fatal("OpenSSL failed to create a new SSL_CTX: %s", fatal("OpenSSL failed to create a new SSL_CTX: %s",
ERR_error_string(ERR_get_error(), NULL)); ERR_error_string(ERR_get_error(), NULL));
} }
/* Our SSL* will always have the SSL_SESSION* inside it, so we neither /* Our SSL* will always have the SSL_SESSION* inside it, so we neither need to
need to use nor waste memory for the session cache. * use nor waste memory for the session cache. (Use '1' because '0' means
(Use '1' because '0' means 'infinite'.) */ * 'infinite'.) */
SSL_CTX_set_session_cache_mode( SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF|SSL_SESS_CACHE_NO_AUTO_CLEAR);
ctx, SSL_SESS_CACHE_OFF | SSL_SESS_CACHE_NO_AUTO_CLEAR ); SSL_CTX_sess_set_cache_size(ctx, 1);
SSL_CTX_sess_set_cache_size( ctx, 1 ); SSL_CTX_set_timeout(ctx, 3600); /* pretty unnecessary */
SSL_CTX_set_timeout( ctx, 3600); /* pretty unnecessary */
return ctx; return ctx;
} }
#endif /* HAVE_OPENSSL */ #endif /* HAVE_OPENSSL */
/* Initializes an Nsock pool to create SSL connections. This sets an internal /* 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 * 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 * 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 * ciphers but no server certificate verification is done. Returns the SSL_CTX
so you can set your own options. */ * so you can set your own options. */
nsock_ssl_ctx nsp_ssl_init(nsock_pool ms_pool) { nsock_ssl_ctx nsp_ssl_init(nsock_pool ms_pool) {
#if HAVE_OPENSSL #if HAVE_OPENSSL
mspool *ms = (mspool *) ms_pool; mspool *ms = (mspool *)ms_pool;
char rndbuf[128]; char rndbuf[128];
if (ms->sslctx == NULL) if (ms->sslctx == NULL)
ms->sslctx = ssl_init_common(); ms->sslctx = ssl_init_common();
/* get_random_bytes may or may not provide high-quality randomness. Add it to /* 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 * the entropy pool without increasing the entropy estimate (third argument of
RAND_add is 0). We rely on OpenSSL's entropy gathering, called implicitly * 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. */ * by RAND_status, to give us what we need, or else bail out if it fails. */
get_random_bytes(rndbuf, sizeof(rndbuf)); get_random_bytes(rndbuf, sizeof(rndbuf));
RAND_add(rndbuf, sizeof(rndbuf), 0); RAND_add(rndbuf, sizeof(rndbuf), 0);
if (!RAND_status()) if (!RAND_status())
fatal("nsp_ssl_init: Failed to seed OpenSSL PRNG (RAND_status returned false)."); fatal("nsp_ssl_init: Failed to seed OpenSSL PRNG (RAND_status returned false).");
/* By default, do no server certificate verification. To enable it, do /* By default, do no server certificate verification. To enable it, do
something like * something like:
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); * 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 * on the SSL_CTX returned. If you do, it is then up to the application to
SSL_CTX_set_default_verify_paths, or else every connection will fail. It is * load trusted certificates with SSL_CTX_load_verify_locations or
also up to the application to do any further checks such as domain name * SSL_CTX_set_default_verify_paths, or else every connection will fail. It
validation. */ * is also up to the application to do any further checks such as domain name
* validation. */
SSL_CTX_set_verify(ms->sslctx, SSL_VERIFY_NONE, NULL); SSL_CTX_set_verify(ms->sslctx, SSL_VERIFY_NONE, NULL);
/* SSL_OP_ALL sets bug-compatibility for pretty much everything. /* 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 * SSL_OP_NO_SSLv2 disables the less-secure SSLv2 while allowing us to use the
SSLv2-compatible SSLv23_client_method. */ * SSLv2-compatible SSLv23_client_method. */
SSL_CTX_set_options(ms->sslctx, SSL_OP_ALL | SSL_OP_NO_SSLv2); SSL_CTX_set_options(ms->sslctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
if (!SSL_CTX_set_cipher_list(ms->sslctx, CIPHERS_SECURE)) { if (!SSL_CTX_set_cipher_list(ms->sslctx, CIPHERS_SECURE)) {
fatal("Unable to set OpenSSL cipher list: %s", fatal("Unable to set OpenSSL cipher list: %s",
ERR_error_string(ERR_get_error(), NULL)); ERR_error_string(ERR_get_error(), NULL));
} }
return ms->sslctx; return ms->sslctx;
#else #else
fatal("%s called with no OpenSSL support", __func__); fatal("%s called with no OpenSSL support", __func__);
@@ -156,11 +154,11 @@ nsock_ssl_ctx nsp_ssl_init(nsock_pool ms_pool) {
} }
/* Initializes an Nsock pool to create SSL connections that emphasize speed over /* Initializes an Nsock pool to create SSL connections that emphasize speed over
security. Insecure ciphers are used when they are faster and no certificate * 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. */ * verification is done. Returns the SSL_CTX so you can set your own options. */
nsock_ssl_ctx nsp_ssl_init_max_speed(nsock_pool ms_pool) { nsock_ssl_ctx nsp_ssl_init_max_speed(nsock_pool ms_pool) {
#if HAVE_OPENSSL #if HAVE_OPENSSL
mspool *ms = (mspool *) ms_pool; mspool *ms = (mspool *)ms_pool;
char rndbuf[128]; char rndbuf[128];
if (ms->sslctx == NULL) if (ms->sslctx == NULL)
@@ -176,7 +174,6 @@ nsock_ssl_ctx nsp_ssl_init_max_speed(nsock_pool ms_pool) {
fatal("Unable to set OpenSSL cipher list: %s", fatal("Unable to set OpenSSL cipher list: %s",
ERR_error_string(ERR_get_error(), NULL)); ERR_error_string(ERR_get_error(), NULL));
} }
return ms->sslctx; return ms->sslctx;
#else #else
fatal("%s called with no OpenSSL support", __func__); fatal("%s called with no OpenSSL support", __func__);
@@ -184,15 +181,15 @@ nsock_ssl_ctx nsp_ssl_init_max_speed(nsock_pool ms_pool) {
} }
/* Check server certificate verification, after a connection is established. We /* Check server certificate verification, after a connection is established. We
check first that a certificate was even offered, then call * check first that a certificate was even offered, then call
SSL_get_verify_result to get the overall status of verification. (Just * SSL_get_verify_result to get the overall status of verification. (Just
calling SSL_get_verify_result is not enough because that function returns * 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 * 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 * SSL object is SSL_VERIFY_NONE, or if OpenSSL is disabled, this function
always returns true. */ * always returns true. */
int nsi_ssl_post_connect_verify(const nsock_iod nsockiod) { int nsi_ssl_post_connect_verify(const nsock_iod nsockiod) {
#if HAVE_OPENSSL #if HAVE_OPENSSL
msiod *iod = (msiod *) nsockiod; msiod *iod = (msiod *)nsockiod;
assert(iod->ssl != NULL); assert(iod->ssl != NULL);
if (SSL_get_verify_mode(iod->ssl) != SSL_VERIFY_NONE) { if (SSL_get_verify_mode(iod->ssl) != SSL_VERIFY_NONE) {
@@ -202,6 +199,7 @@ int nsi_ssl_post_connect_verify(const nsock_iod nsockiod) {
if (cert == NULL) if (cert == NULL)
/* No certificate presented. */ /* No certificate presented. */
return 0; return 0;
X509_free(cert); X509_free(cert);
if (SSL_get_verify_result(iod->ssl) != X509_V_OK) if (SSL_get_verify_result(iod->ssl) != X509_V_OK)
@@ -209,6 +207,6 @@ int nsi_ssl_post_connect_verify(const nsock_iod nsockiod) {
return 0; return 0;
} }
#endif #endif
return 1; return 1;
} }

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* nsock_ssl.c -- This contains functions that relate somewhat exclusively * * nsock_ssl.c -- This contains functions that relate somewhat exclusively *
* to SSL (over TCP) support in nsock. Where SSL support is incidental, * * to SSL (over TCP) support in nsock. Where SSL support is incidental, *
@@ -73,7 +72,7 @@
struct sslinfo { struct sslinfo {
/* SSL_ERROR_NONE, SSL_ERROR_WANT_CONNECT, SSL_ERROR_WAINT_READ, or /* SSL_ERROR_NONE, SSL_ERROR_WANT_CONNECT, SSL_ERROR_WAINT_READ, or
SSL_ERROR_WANT_WRITE */ * SSL_ERROR_WANT_WRITE */
int ssl_desire; int ssl_desire;
}; };
@@ -81,3 +80,4 @@ int nsi_ssl_post_connect_verify(const nsock_iod nsockiod);
#endif /* HAVE_OPENSSL */ #endif /* HAVE_OPENSSL */
#endif /* NSOCK_SSL_H */ #endif /* NSOCK_SSL_H */

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* nsock_read.c -- This contains the functions for requesting timers * * nsock_read.c -- This contains the functions for requesting timers *
* from the nsock parallel socket event library * * from the nsock parallel socket event library *
@@ -58,19 +57,18 @@
#include "nsock_internal.h" #include "nsock_internal.h"
/* Send back an NSE_TYPE_TIMER after the number of milliseconds specified. Of course it can also return due to error, cancellation, etc. */ /* 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, nsock_event_id nsock_timer_create(nsock_pool ms_pool, nsock_ev_handler handler,
int timeout_msecs, void *userdata) { int timeout_msecs, void *userdata) {
mspool *nsp = (mspool *) ms_pool; mspool *nsp = (mspool *)ms_pool;
msevent *nse; msevent *nse;
nse = msevent_new(nsp, NSE_TYPE_TIMER, NULL, timeout_msecs, handler, nse = msevent_new(nsp, NSE_TYPE_TIMER, NULL, timeout_msecs, handler, userdata);
userdata);
assert(nse); assert(nse);
if (nsp->tracelevel > 0) { if (nsp->tracelevel > 0)
nsock_trace(nsp, "Timer created - %dms from now. EID %li", timeout_msecs, nse->id); nsock_trace(nsp, "Timer created - %dms from now. EID %li", timeout_msecs, nse->id);
}
nsp_add_event(nsp, nse); nsp_add_event(nsp, nse);

View File

@@ -1,4 +1,3 @@
/*************************************************************************** /***************************************************************************
* nsock_write.c -- This contains the functions relating to writing to * * nsock_write.c -- This contains the functions relating to writing to *
* sockets using the nsock parallel socket event library * * sockets using the nsock parallel socket event library *
@@ -63,21 +62,18 @@
#include <stdarg.h> #include <stdarg.h>
#include <errno.h> #include <errno.h>
nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod, nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
nsock_ev_handler handler, int timeout_msecs, void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port, const char *data, int datalen) {
void *userdata, struct sockaddr *saddr, size_t sslen, mspool *nsp = (mspool *)ms_pool;
unsigned short port, const char *data, int datalen) { msiod *nsi = (msiod *)ms_iod;
mspool *nsp = (mspool *) ms_pool;
msiod *nsi = (msiod *) ms_iod;
msevent *nse; msevent *nse;
char displaystr[256]; char displaystr[256];
struct sockaddr_in *sin = (struct sockaddr_in *) saddr; struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
#if HAVE_IPV6 #if HAVE_IPV6
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) saddr; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)saddr;
#endif #endif
nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata);
userdata);
assert(nse); assert(nse);
if (sin->sin_family == AF_INET) { if (sin->sin_family == AF_INET) {
@@ -124,17 +120,18 @@ nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod,
return nse->id; 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 */ /* 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_event_id nsock_write(nsock_pool ms_pool, nsock_iod ms_iod,
nsock_ev_handler handler, int timeout_msecs, nsock_ev_handler handler, int timeout_msecs, void *userdata, const char *data, int datalen) {
void *userdata, const char *data, int datalen) { mspool *nsp = (mspool *)ms_pool;
mspool *nsp = (mspool *) ms_pool; msiod *nsi = (msiod *)ms_iod;
msiod *nsi = (msiod *) ms_iod;
msevent *nse; msevent *nse;
char displaystr[256]; char displaystr[256];
nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata);
userdata);
assert(nse); assert(nse);
nse->writeinfo.dest.ss_family = AF_UNSPEC; nse->writeinfo.dest.ss_family = AF_UNSPEC;
@@ -150,7 +147,7 @@ nsock_event_id nsock_write(nsock_pool ms_pool, nsock_iod ms_iod,
replacenonprintable(displaystr + 2, datalen, '.'); replacenonprintable(displaystr + 2, datalen, '.');
} else displaystr[0] = '\0'; } else displaystr[0] = '\0';
if (nsi->peerlen > 0) if (nsi->peerlen > 0)
nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li [%s:%hu]%s", datalen, nsi->id, nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li [%s:%d]%s", datalen, nsi->id,
nse->id, inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi), displaystr); nse->id, inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi), displaystr);
else else
nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li (peer unspecified)%s", datalen, nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li (peer unspecified)%s", datalen,
@@ -166,11 +163,9 @@ nsock_event_id nsock_write(nsock_pool ms_pool, nsock_iod ms_iod,
/* Same as nsock_write except you can use a printf-style format and you can only use this for ASCII strings */ /* 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_event_id nsock_printf(nsock_pool ms_pool, nsock_iod ms_iod,
nsock_ev_handler handler, int timeout_msecs, nsock_ev_handler handler, int timeout_msecs, void *userdata, char *format, ... ) {
void *userdata, char *format, ... ) { mspool *nsp = (mspool *)ms_pool;
msiod *nsi = (msiod *)ms_iod;
mspool *nsp = (mspool *) ms_pool;
msiod *nsi = (msiod *) ms_iod;
msevent *nse; msevent *nse;
char buf[4096]; char buf[4096];
char *buf2 = NULL; char *buf2 = NULL;
@@ -181,8 +176,7 @@ nsock_event_id nsock_printf(nsock_pool ms_pool, nsock_iod ms_iod,
va_list ap; va_list ap;
va_start(ap,format); va_start(ap,format);
nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata);
userdata);
assert(nse); assert(nse);
res = Vsnprintf(buf, sizeof(buf), format, ap); res = Vsnprintf(buf, sizeof(buf), format, ap);
@@ -190,12 +184,13 @@ nsock_event_id nsock_printf(nsock_pool ms_pool, nsock_iod ms_iod,
if (res != -1) { if (res != -1) {
if (res > sizeof(buf)) { if (res > sizeof(buf)) {
buf2 = (char * ) safe_malloc(res + 16); buf2 = (char * )safe_malloc(res + 16);
res2 = Vsnprintf(buf2, sizeof(buf), format, ap); res2 = Vsnprintf(buf2, sizeof(buf), format, ap);
if (res2 == -1 || res2 > res) { if (res2 == -1 || res2 > res) {
free(buf2); free(buf2);
buf2 = NULL; buf2 = NULL;
} else strlength = res2; } else
strlength = res2;
} else { } else {
buf2 = buf; buf2 = buf;
strlength = res; strlength = res;
@@ -221,18 +216,19 @@ nsock_event_id nsock_printf(nsock_pool ms_pool, nsock_iod ms_iod,
memcpy(displaystr + 2, buf2, strlength); memcpy(displaystr + 2, buf2, strlength);
displaystr[2 + strlength] = '\0'; displaystr[2 + strlength] = '\0';
replacenonprintable(displaystr + 2, strlength, '.'); replacenonprintable(displaystr + 2, strlength, '.');
} else displaystr[0] = '\0'; } else {
displaystr[0] = '\0';
}
if (nsi->peerlen > 0) if (nsi->peerlen > 0)
nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li [%s:%hu]%s", strlength, nsi->id, nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li [%s:%d]%s", strlength, nsi->id,
nse->id, inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi), displaystr); nse->id, inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi), displaystr);
else else
nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li (peer unspecified)%s", strlength, nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li (peer unspecified)%s", strlength,
nsi->id, nse->id, displaystr); nsi->id, nse->id, displaystr);
} }
if (buf2 != buf) { if (buf2 != buf)
free(buf2); free(buf2);
}
nsp_add_event(nsp, nse); nsp_add_event(nsp, nse);