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:
@@ -1,5 +1,11 @@
|
||||
# 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 the new --script-args-file option which allows you to specify
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* nsock.h -- public interface definitions for the nsock parallel socket *
|
||||
* event library *
|
||||
@@ -56,11 +55,6 @@
|
||||
|
||||
/* $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
|
||||
#define NSOCK_H
|
||||
|
||||
@@ -89,38 +83,34 @@ extern "C" {
|
||||
/* The read calls will generally return after reading at least this
|
||||
* much data so that the caller can process it and so that the
|
||||
* connection spewing data doesn't monopolize resources. The caller
|
||||
* can always initiate another read request to ask for more.
|
||||
*/
|
||||
* can always initiate another read request to ask for more. */
|
||||
#define NSOCK_READ_CHUNK_SIZE 0x8FFFF
|
||||
|
||||
/********************* TYPEDEFS ********************/
|
||||
|
||||
/* ------------------- TYPEDEFS ------------------- */
|
||||
|
||||
/* nsock_pool, nsock_iod, and nsock_event are opaque objects that should
|
||||
only be accessed using the appropriate accessor functions (described
|
||||
below).
|
||||
*/
|
||||
* only be accessed using the appropriate accessor functions (described below). */
|
||||
|
||||
/* An nsock_pool aggregates and manages events and i/o descriptors */
|
||||
typedef void *nsock_pool;
|
||||
|
||||
/* nsock_iod is an I/O descriptor -- you create it and then use it to
|
||||
make calls to do connect()s, read()s, write()s, etc. A single IOD
|
||||
can handle multiple event calls, but only one at a time. Also the
|
||||
event calls must be in a "reasonable" order. For example, you
|
||||
might start with nsock_connect_tcp() followed by a bunch of
|
||||
nsock_read* and nsock_write* calls. Then you either destroy the
|
||||
iod for good with nsi_delete() and allocate a new one via nsi_new
|
||||
for your next connection. */
|
||||
* make calls to do connect()s, read()s, write()s, etc. A single IOD can handle
|
||||
* multiple event calls, but only one at a time. Also the event calls must be in
|
||||
* a "reasonable" order. For example, you might start with nsock_connect_tcp()
|
||||
* followed by a bunch of nsock_read* and nsock_write* calls. Then you either
|
||||
* destroy the iod for good with nsi_delete() and allocate a new one via nsi_new
|
||||
* for your next connection. */
|
||||
typedef void *nsock_iod;
|
||||
|
||||
/* An event is created when you do various calls (for reading, writing,
|
||||
connecting, timers, etc) and is provided back to you in the callback
|
||||
when the call completes/fails. It is automatically destroyed after
|
||||
the callback
|
||||
*/
|
||||
* connecting, timers, etc) and is provided back to you in the callback when the
|
||||
* call completes/fails. It is automatically destroyed after the callback */
|
||||
typedef void *nsock_event;
|
||||
|
||||
/* Provided by calls which (internally) create an nsock_event. This allows
|
||||
you to cancel the event */
|
||||
/* Provided by calls which (internally) create an nsock_event. This allows you
|
||||
* to cancel the event */
|
||||
typedef unsigned long nsock_event_id;
|
||||
|
||||
/* This is used to save SSL sessionids between SSL connections */
|
||||
@@ -128,28 +118,34 @@ typedef void *nsock_ssl_session;
|
||||
typedef void *nsock_ssl_ctx;
|
||||
typedef void *nsock_ssl;
|
||||
|
||||
/******************** PROTOTYPES *******************/
|
||||
|
||||
/* ------------------- PROTOTYPES ------------------- */
|
||||
|
||||
/* Here is the all important looping function that tells the event
|
||||
engine to start up and begin processing events. It will continue
|
||||
until all events have been delivered (including new ones started
|
||||
from event handlers), or the msec_timeout is reached, or a major
|
||||
error has occured. Use -1 if you don't want to set a maximum time
|
||||
for it to run. A timeout of 0 will return after 1 non-blocking
|
||||
loop. The nsock loop can be restarted again after it returns. For
|
||||
example you could do a series of 15 second runs, allowing you to do
|
||||
other stuff between them. Or you could just schedule a timer to
|
||||
call you back every 15 seconds.*/
|
||||
enum nsock_loopstatus { NSOCK_LOOP_NOEVENTS = 2, NSOCK_LOOP_TIMEOUT, NSOCK_LOOP_ERROR, NSOCK_LOOP_QUIT };
|
||||
* engine to start up and begin processing events. It will continue until all
|
||||
* events have been delivered (including new ones started from event handlers),
|
||||
* or the msec_timeout is reached, or a major error has occured. Use -1 if you
|
||||
* don't want to set a maximum time for it to run. A timeout of 0 will return
|
||||
* after 1 non-blocking loop. The nsock loop can be restarted again after it
|
||||
* returns. For example you could do a series of 15 second runs, allowing you
|
||||
* to do other stuff between them. Or you could just schedule a timer to call
|
||||
* you back every 15 seconds. */
|
||||
enum nsock_loopstatus {
|
||||
NSOCK_LOOP_NOEVENTS = 2,
|
||||
NSOCK_LOOP_TIMEOUT,
|
||||
NSOCK_LOOP_ERROR,
|
||||
NSOCK_LOOP_QUIT
|
||||
};
|
||||
|
||||
|
||||
enum nsock_loopstatus nsock_loop(nsock_pool nsp, int msec_timeout);
|
||||
|
||||
/* Calling this function will cause nsock_loop to quit on its next iteration
|
||||
with a return value of NSOCK_LOOP_QUIT. */
|
||||
* with a return value of NSOCK_LOOP_QUIT. */
|
||||
void nsock_loop_quit(nsock_pool nsp);
|
||||
|
||||
/* This next function returns the errno style error code -- which is only
|
||||
valid if the status is NSOCK_LOOP_ERROR was returned by nsock_loop() */
|
||||
/* This next function returns the errno style error code -- which is only valid
|
||||
* if the status is NSOCK_LOOP_ERROR was returned by nsock_loop() */
|
||||
int nsp_geterrorcode(nsock_pool nsp);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Note that nsi_get1_ssl_session will increment the usage count
|
||||
* of the SSL_SESSION, since nsock does a free when the nsi is
|
||||
* destroyed. It's up to any calling function/etc to do a
|
||||
* SSL_SESSION_free() on it. nsi_get0_ssl_session doesn't
|
||||
* increment, and is for informational purposes only.
|
||||
*/
|
||||
/* Note that nsi_get1_ssl_session will increment the usage count of the
|
||||
* SSL_SESSION, since nsock does a free when the nsi is destroyed. It's up to
|
||||
* any calling function/etc to do a SSL_SESSION_free() on it.
|
||||
* nsi_get0_ssl_session doesn't increment, and is for informational purposes
|
||||
* only. */
|
||||
nsock_ssl_session nsi_get1_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
|
||||
the NSP so you can retrieve it during a callback. */
|
||||
/* 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);
|
||||
|
||||
/* And the function above wouldn't make much sense if we didn't have a way
|
||||
to retrieve that data ... */
|
||||
/* And the function above wouldn't make much sense if we didn't have a way to
|
||||
* retrieve that data ... */
|
||||
void *nsp_getud(nsock_pool nsp);
|
||||
|
||||
/* 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) */
|
||||
/* 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);
|
||||
|
||||
/* 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 */
|
||||
/* 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);
|
||||
|
||||
/* Initializes an Nsock pool to create SSL connections. This sets an internal
|
||||
SSL_CTX, which is like a template that sets options for all connections that
|
||||
are made from it. Returns the SSL_CTX so you can set your own options. */
|
||||
* 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. */
|
||||
nsock_ssl_ctx nsp_ssl_init(nsock_pool ms_pool);
|
||||
|
||||
/* Initializes an Nsock pool to create SSL connections that emphasize speed over
|
||||
security. Insecure ciphers are used when they are faster and no certificate
|
||||
verification is done. Returns the SSL_CTX so you can set your own options. */
|
||||
* 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. */
|
||||
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 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. */
|
||||
/* 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);
|
||||
|
||||
/* 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. */
|
||||
/* 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 nsp);
|
||||
|
||||
/* nsock_event handles a single event. Its ID is generally returned when
|
||||
the event is created, and the event itself is included in callbacks */
|
||||
/* IF YOU ADD NEW NSE_TYPES YOU MUST INCREASE TYPE_CODE_NUM_BITS SO THAT
|
||||
IT IS ALWAYS log2(maximum_nse_type_value + 1) */
|
||||
/* nsock_event handles a single event. Its ID is generally returned when the
|
||||
* event is created, and the event itself is included in callbacks
|
||||
*
|
||||
* ---------------------------------------------------------------------------
|
||||
* IF YOU ADD NEW NSE_TYPES YOU MUST INCREASE TYPE_CODE_NUM_BITS SO THAT IT IS
|
||||
* ALWAYS log2(maximum_nse_type_value + 1)
|
||||
* --------------------------------------------------------------------------- */
|
||||
#define TYPE_CODE_NUM_BITS 3
|
||||
enum nse_type {
|
||||
NSE_TYPE_CONNECT=0,
|
||||
NSE_TYPE_CONNECT_SSL=1,
|
||||
NSE_TYPE_READ=2,
|
||||
NSE_TYPE_WRITE=3,
|
||||
NSE_TYPE_TIMER=4,
|
||||
NSE_TYPE_PCAP_READ=5,
|
||||
NSE_TYPE_MAX=6,
|
||||
NSE_TYPE_CONNECT = 0,
|
||||
NSE_TYPE_CONNECT_SSL = 1,
|
||||
NSE_TYPE_READ = 2,
|
||||
NSE_TYPE_WRITE = 3,
|
||||
NSE_TYPE_TIMER = 4,
|
||||
NSE_TYPE_PCAP_READ = 5,
|
||||
NSE_TYPE_MAX = 6,
|
||||
}; /* At some point I was considering a NSE_TYPE_START and NSE_TYPE_CUSTOM */
|
||||
|
||||
/* Find the type of an event that spawned a callback */
|
||||
enum nse_type nse_type(nsock_event nse);
|
||||
|
||||
/* Takes an nse_type (as returned by nse_type() and returns a static
|
||||
string name that you can use for printing, etc. */
|
||||
/* Takes an nse_type (as returned by nse_type() and returns a static string name
|
||||
* that you can use for printing, etc. */
|
||||
const char *nse_type2str(enum nse_type type);
|
||||
|
||||
/* Did the event succeed? What is the status? */
|
||||
enum nse_status { NSE_STATUS_NONE = 0, /* User should never see this */
|
||||
enum nse_status {
|
||||
NSE_STATUS_NONE = 0, /* User should never see this */
|
||||
NSE_STATUS_SUCCESS, /* Everything went A-OK! */
|
||||
NSE_STATUS_ERROR, /* Uh-oh! Problem, check the
|
||||
nse_errorcode() */
|
||||
NSE_STATUS_TIMEOUT, /* The async call surpassed the
|
||||
timeout you specified */
|
||||
NSE_STATUS_CANCELLED, /* Someone cancelled the
|
||||
event. (by calling
|
||||
nsock_event_cancel. */
|
||||
NSE_STATUS_KILL, /* The event has been killed, this
|
||||
generally means the nspool is
|
||||
being deleted -- you should free
|
||||
up any resources you have
|
||||
allocated and exit. Don't you
|
||||
NSE_STATUS_ERROR, /* Uh-oh! Problem, check the nse_errorcode() */
|
||||
NSE_STATUS_TIMEOUT, /* The async call surpassed the timeout you specified */
|
||||
NSE_STATUS_CANCELLED, /* Someone cancelled the event. (by calling nsock_event_cancel. */
|
||||
NSE_STATUS_KILL, /* The event has been killed, this generally means the
|
||||
nspool is being deleted -- you should free up any
|
||||
resources you have allocated and exit. Don't you
|
||||
dare make any more async nsock calls! */
|
||||
NSE_STATUS_EOF /* We got EOF and NO DATA -- if we got data
|
||||
first, SUCCESS is reported (see nse_eof()
|
||||
*/
|
||||
};
|
||||
NSE_STATUS_EOF /* We got EOF and NO DATA -- if we got data first,
|
||||
SUCCESS is reported (see nse_eof() */
|
||||
};
|
||||
|
||||
enum nse_status nse_status(nsock_event nse);
|
||||
|
||||
/* Takes an nse_status (as returned by nse_status() and returns a static
|
||||
string name that you can use for printing, etc. */
|
||||
/* Takes an nse_status (as returned by nse_status() and returns a static string
|
||||
* name that you can use for printing, etc. */
|
||||
const char *nse_status2str(enum nse_status status);
|
||||
|
||||
/* This next function tells whether we received an EOF when we
|
||||
were reading. It is generally a better way to check for EOF
|
||||
than looking at the status because sometimes we read some data
|
||||
before getting the EOF, in which SUCCESS is returned (although
|
||||
another read attempt would return a status of EOF). nse_eof
|
||||
returns nonzero if we have reached EOF, zero if we have NOT
|
||||
reach EOF. */
|
||||
/* This next function tells whether we received an EOF when we were reading. It
|
||||
* is generally a better way to check for EOF than looking at the status because
|
||||
* sometimes we read some data before getting the EOF, in which SUCCESS is
|
||||
* returned (although another read attempt would return a status of EOF).
|
||||
* nse_eof returns nonzero if we have reached EOF, zero if we have NOT reach
|
||||
* EOF. */
|
||||
int nse_eof(nsock_event nse);
|
||||
|
||||
/* This next function returns the errno style error code -- which is only
|
||||
valid if the status is NSE_STATUS_ERROR (this is a normal errno style
|
||||
errorcode */
|
||||
/* This next function returns the errno style error code -- which is only valid
|
||||
* if the status is NSE_STATUS_ERROR (this is a normal errno style errorcode). */
|
||||
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);
|
||||
|
||||
/* If you did a read request, and the result was STATUS_SUCCESS, this
|
||||
function provides the buffer that was read in as well as the number
|
||||
of chars read. The buffer should not be modified or free'd . It is not
|
||||
guaranteed to be NUL-terminated and it may even contain nuls */
|
||||
/* If you did a read request, and the result was STATUS_SUCCESS, this function
|
||||
* provides the buffer that was read in as well as the number of chars read.
|
||||
* The buffer should not be modified or free'd . It is not guaranteed to be
|
||||
* NUL-terminated and it may even contain nuls */
|
||||
char *nse_readbuf(nsock_event nse, int *nbytes);
|
||||
|
||||
/* Obtains the nsock_iod (see below) associated with the event. Note that
|
||||
some events (such as timers) don't have an nsock_iod associated with them
|
||||
*/
|
||||
/* Obtains the nsock_iod (see below) associated with the event. Note that some
|
||||
* events (such as timers) don't have an nsock_iod associated with them */
|
||||
nsock_iod nse_iod(nsock_event nse);
|
||||
|
||||
|
||||
/* nsock_iod is like a "file descriptor" for the nsock library. You
|
||||
use it to request events. And here is how you create an nsock_iod.
|
||||
nsi_new returns NULL if the iod cannot be allocated. Pass NULL as
|
||||
userdata if you don't want to immediately associate any user data
|
||||
with the iod. */
|
||||
/* nsock_iod is like a "file descriptor" for the nsock library. You use it to
|
||||
* request events. And here is how you create an nsock_iod. nsi_new returns
|
||||
* NULL if the iod cannot be allocated. Pass NULL as userdata if you don't want
|
||||
* to immediately associate any user data with the iod. */
|
||||
nsock_iod nsi_new(nsock_pool nsockp, void *userdata);
|
||||
|
||||
/* This version allows you to associate an existing sd with the msi
|
||||
so that you can read/write it using the nsock infrastructure. For example,
|
||||
you may want to watch for data from STDIN_FILENO at the same time as you
|
||||
read/write various sockets. STDIN_FILENO is a special case, however. Any
|
||||
other sd is dup()ed, so you may close or otherwise manipulate your copy.
|
||||
The duped copy will be destroyed when the nsi is destroyed
|
||||
*/
|
||||
/* This version allows you to associate an existing sd with the msi so that you
|
||||
* can read/write it using the nsock infrastructure. For example, you may want
|
||||
* to watch for data from STDIN_FILENO at the same time as you read/write
|
||||
* various sockets. STDIN_FILENO is a special case, however. Any other sd is
|
||||
* dup()ed, so you may close or otherwise manipulate your copy. The duped copy
|
||||
* will be destroyed when the nsi is destroyed */
|
||||
nsock_iod nsi_new2(nsock_pool nsockp, int sd, void *userdata);
|
||||
|
||||
/* If msiod_new returned success, you must free the iod when you are
|
||||
done with it to conserve memory (and in some cases, sockets).
|
||||
After this call, nsockiod may no longer be used -- you need to
|
||||
create a new one with nsi_new(). pending_response tells what to do
|
||||
with any events that are pending on this nsock_iod. This can be
|
||||
NSOCK_PENDING_NOTIFY (send a KILL notification to each event),
|
||||
NSOCK_PENDING_SILENT (do not send notification to the killed
|
||||
events), or NSOCK_PENDING_ERROR (print an error message and quiit
|
||||
the program) */
|
||||
/* If msiod_new returned success, you must free the iod when you are done with
|
||||
* it to conserve memory (and in some cases, sockets). After this call,
|
||||
* nsockiod may no longer be used -- you need to create a new one with
|
||||
* nsi_new(). pending_response tells what to do with any events that are
|
||||
* pending on this nsock_iod. This can be NSOCK_PENDING_NOTIFY (send a KILL
|
||||
* notification to each event), NSOCK_PENDING_SILENT (do not send notification
|
||||
* to the killed events), or NSOCK_PENDING_ERROR (print an error message and
|
||||
* quiit the program) */
|
||||
#define NSOCK_PENDING_NOTIFY 1
|
||||
#define NSOCK_PENDING_SILENT 2
|
||||
#define NSOCK_PENDING_ERROR 4
|
||||
void nsi_delete(nsock_iod nsockiod, int pending_response);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* And the function above wouldn't make much sense if we didn't have a way
|
||||
to retrieve that data ... */
|
||||
/* And the function above wouldn't make much sense if we didn't have a way to
|
||||
* retrieve that data ... */
|
||||
void *nsi_getud(nsock_iod nsiod);
|
||||
|
||||
/* I didn't want to do this. Its an ugly hack, but I suspect it will
|
||||
be neccessary. I certainly can't reproduce in nsock EVERYTHING you
|
||||
might want to do with a socket. So I'm offering you this function
|
||||
to obtain the socket descriptor which is (usually) wrapped in a
|
||||
nsock_iod). You can do "reasonable" things with it, like setting
|
||||
socket receive buffers. But don't create havok by closing the
|
||||
descriptor! If the descriptor you get back is -1, the iod does not
|
||||
currently possess a valid descriptor */
|
||||
/* I didn't want to do this. Its an ugly hack, but I suspect it will be
|
||||
* neccessary. I certainly can't reproduce in nsock EVERYTHING you might want
|
||||
* to do with a socket. So I'm offering you this function to obtain the socket
|
||||
* descriptor which is (usually) wrapped in a nsock_iod). You can do
|
||||
* "reasonable" things with it, like setting socket receive buffers. But don't
|
||||
* create havok by closing the descriptor! If the descriptor you get back is
|
||||
* -1, the iod does not currently possess a valid descriptor */
|
||||
int nsi_getsd(nsock_iod nsiod);
|
||||
|
||||
/* Returns the ID of an nsock_iod . This ID is always unique amongst
|
||||
ids for a given nspool (unless you blow through billions of them). */
|
||||
/* Returns the ID of an nsock_iod . This ID is always unique amongst ids for a
|
||||
* given nspool (unless you blow through billions of them). */
|
||||
unsigned long nsi_id(nsock_iod nsockiod);
|
||||
|
||||
/*Returns Packets received in bytes */
|
||||
/* Returns Packets received in bytes */
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Returns the remote peer port (or -1 if unavailable). Note the
|
||||
return value is a whole int so that -1 can be distinguished from
|
||||
65535. Port is returned in host byte order. */
|
||||
/* Returns the remote peer port (or -1 if unavailable). Note the return value
|
||||
* is a whole int so that -1 can be distinguished from 65535. Port is returned
|
||||
* in host byte order. */
|
||||
int nsi_peerport(nsock_iod nsiod);
|
||||
|
||||
/* Sets the local address to bind to before connect() */
|
||||
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
|
||||
* options, so you can free() yours if necessary. This copy is freed
|
||||
* when the iod is destroyed
|
||||
*/
|
||||
/* Sets IPv4 options to apply before connect(). It makes a copy of the options,
|
||||
* so you can free() yours if necessary. This copy is freed when the iod is
|
||||
* destroyed */
|
||||
int nsi_set_ipoptions(nsock_iod nsi, void *ipopts, size_t ipoptslen);
|
||||
|
||||
/* Returns that host/port/protocol information for the last
|
||||
communication (or comm. attempt) this nsi has been involved with.
|
||||
By "involved" with I mean interactions like establishing (or trying
|
||||
to) a connection or sending a UDP datagram through an unconnected
|
||||
nsock_iod. AF is the address family (AF_INET or AF_INET6), Protocol
|
||||
is IPPROTO_TCP or IPPROTO_UDP. Pass NULL for information you do
|
||||
not need. If ANY of the information you requested is not
|
||||
available, 0 will be returned and the unavailable sockets are
|
||||
zeroed. If protocol or af is requested but not available, it will
|
||||
be set to -1 (and 0 returned). The pointers you pass in must be
|
||||
NULL or point to allocated address space. The sockaddr members
|
||||
should actually be sockaddr_storage, sockaddr_in6, or sockaddr_in
|
||||
with the socklen of them set appropriately (eg
|
||||
sizeof(sockaddr_storage) if that is what you are passing). */
|
||||
int nsi_getlastcommunicationinfo(nsock_iod ms_iod, int *protocol,
|
||||
int *af, struct sockaddr *local,
|
||||
struct sockaddr *remote, size_t socklen);
|
||||
/* Returns that host/port/protocol information for the last communication (or
|
||||
* comm. attempt) this nsi has been involved with. By "involved" with I mean
|
||||
* interactions like establishing (or trying to) a connection or sending a UDP
|
||||
* datagram through an unconnected nsock_iod. AF is the address family (AF_INET
|
||||
* or AF_INET6), Protocol is IPPROTO_TCP or IPPROTO_UDP. Pass NULL for
|
||||
* information you do not need. If ANY of the information you requested is not
|
||||
* available, 0 will be returned and the unavailable sockets are zeroed. If
|
||||
* protocol or af is requested but not available, it will be set to -1 (and 0
|
||||
* returned). The pointers you pass in must be NULL or point to allocated
|
||||
* address space. The sockaddr members should actually be sockaddr_storage,
|
||||
* sockaddr_in6, or sockaddr_in with the socklen of them set appropriately (eg
|
||||
* sizeof(sockaddr_storage) if that is what you are passing). */
|
||||
int 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
|
||||
currently only used for Server Name Indication in SSL connections. */
|
||||
/* Set the hostname of the remote host, for when that matters. This is currently
|
||||
* only used for Server Name Indication in SSL connections. */
|
||||
int nsi_set_hostname(nsock_iod nsi, const char *hostname);
|
||||
|
||||
/* EVENT CREATION FUNCTIONS -- These functions request asynchronous
|
||||
notification of completion of an event. The handler will never be
|
||||
synchronously called back during the event creation call (that
|
||||
causes too many hard to debug errors and plus we don't want people
|
||||
to have to deal with callbacks until they actually call nsock_loop */
|
||||
/* EVENT CREATION FUNCTIONS
|
||||
* ---
|
||||
* These functions request asynchronous
|
||||
* notification of completion of an event. The handler will never be
|
||||
* synchronously called back during the event creation call (that causes too
|
||||
* many hard to debug errors and plus we don't want people to have to deal with
|
||||
* callbacks until they actually call nsock_loop */
|
||||
|
||||
/* These functions generally take a common 5 initial parameters:
|
||||
|
||||
nsock_pool mst -- the is the nsock_pool describing the events you have
|
||||
scheduled, etc
|
||||
|
||||
nsock_iod nsiod -- The I/O Descriptor that should be used in the
|
||||
request. Note that timer events don't have this argument since
|
||||
they don't use an iod. You can obtain it in the callback from
|
||||
the nsock_event.
|
||||
|
||||
nsock_ev_handler handler -- This is the function you want the
|
||||
system to call when your event is triggered (or times out, or
|
||||
hits an error, etc.). The function should be of this form:
|
||||
void funcname(nsock_pool nsp, nsock_event nse, void *userdata)
|
||||
|
||||
int timeout_msecs -- The timeout for the request in milliseconds.
|
||||
If the request hasn't completed (or in a few cases started)
|
||||
within the timeout specified, the handler will be called with
|
||||
a TIMEOUT status and the request will be aborted.
|
||||
|
||||
void *userdata -- The nsock_event that comes back can
|
||||
optionally have a pointer associated with it. You can set
|
||||
that pointer here. If you don't want one, just pass NULL.
|
||||
|
||||
These functions return an nsock_event_id which can be used to cancel
|
||||
the event if neccessary.
|
||||
*/
|
||||
|
||||
*
|
||||
* nsock_pool mst:
|
||||
* The is the nsock_pool describing the events you have scheduled, etc
|
||||
*
|
||||
* nsock_iod nsiod:
|
||||
* The I/O Descriptor that should be used in the request. Note that timer
|
||||
* events don't have this argument since they don't use an iod. You can
|
||||
* obtain it in the callback from the nsock_event.
|
||||
*
|
||||
* nsock_ev_handler handler:
|
||||
* This is the function you want the system to call when your event is
|
||||
* triggered (or times out, or hits an error, etc.). The function should be
|
||||
* of this form: void funcname(nsock_pool nsp, nsock_event nse, void *userdata)
|
||||
*
|
||||
* int timeout_msecs:
|
||||
* The timeout for the request in milliseconds. If the request hasn't
|
||||
* completed (or in a few cases started) within the timeout specified, the
|
||||
* handler will be called with a TIMEOUT status and the request will be
|
||||
* aborted.
|
||||
*
|
||||
* void *userdata:
|
||||
* The nsock_event that comes back can optionally have a pointer associated
|
||||
* with it. You can set that pointer here. If you don't want one, just
|
||||
* pass NULL.
|
||||
*
|
||||
* These functions return an nsock_event_id which can be used to cancel the
|
||||
* event if neccessary.
|
||||
*/
|
||||
typedef void (*nsock_ev_handler)(nsock_pool, nsock_event, void *);
|
||||
|
||||
/* Initialize an unconnected UDP socket. */
|
||||
int nsock_setup_udp(nsock_pool nsp, nsock_iod ms_iod, int af);
|
||||
|
||||
/* Request a TCP connection to another system (by IP address). The
|
||||
in_addr is normal network byte order, but the port number should be
|
||||
given in HOST BYTE ORDER. ss should be a sockaddr_storage,
|
||||
sockaddr_in6, or sockaddr_in as appropriate (just like what you
|
||||
would pass to connect). sslen should be the sizeof the structure
|
||||
you are passing in. */
|
||||
nsock_event_id nsock_connect_tcp(nsock_pool nsp, nsock_iod nsiod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *ss,
|
||||
size_t sslen, unsigned short port);
|
||||
/* Request a TCP connection to another system (by IP address). The in_addr is
|
||||
* normal network byte order, but the port number should be given in HOST BYTE
|
||||
* ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as
|
||||
* appropriate (just like what you would pass to connect). sslen should be the
|
||||
* sizeof the structure you are passing in. */
|
||||
nsock_event_id nsock_connect_tcp(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *ss, size_t sslen, unsigned short port);
|
||||
|
||||
/* Request an SCTP association to another system (by IP address). The
|
||||
in_addr is normal network byte order, but the port number should be
|
||||
given in HOST BYTE ORDER. ss should be a sockaddr_storage,
|
||||
sockaddr_in6, or sockaddr_in as appropriate (just like what you
|
||||
would pass to connect). sslen should be the sizeof the structure
|
||||
you are passing in. */
|
||||
nsock_event_id nsock_connect_sctp(nsock_pool nsp, nsock_iod nsiod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *ss,
|
||||
size_t sslen, unsigned short port);
|
||||
/* Request an SCTP association to another system (by IP address). The in_addr is
|
||||
* normal network byte order, but the port number should be given in HOST BYTE
|
||||
* ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as
|
||||
* appropriate (just like what you would pass to connect). sslen should be the
|
||||
* sizeof the structure you are passing in. */
|
||||
nsock_event_id nsock_connect_sctp(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *ss, size_t sslen, unsigned short port);
|
||||
|
||||
/* Request a UDP "connection" to another system (by IP address). The
|
||||
in_addr is normal network byte order, but the port number should be
|
||||
given in HOST BYTE ORDER. Since this is UDP, no packets are
|
||||
actually sent. The destination IP and port are just associated
|
||||
with the nsiod (an actual OS connect() call is made). You can then
|
||||
use the normal nsock write calls on the socket. There is no
|
||||
timeout since this call always calls your callback at the next
|
||||
opportunity. The advantages to having a connected UDP socket (as
|
||||
opposed to just specifying an address with sendto() are that we can
|
||||
now use a consistent set of write/read calls for TCP/UDP, received
|
||||
packets from the non-partner are automatically dropped by the OS,
|
||||
and the OS can provide asynchronous errors (see Unix Network
|
||||
Programming pp224). ss should be a sockaddr_storage,
|
||||
sockaddr_in6, or sockaddr_in as appropriate (just like what you
|
||||
would pass to connect). sslen should be the sizeof the structure
|
||||
you are passing in. */
|
||||
nsock_event_id nsock_connect_udp(nsock_pool nsp, nsock_iod nsiod,
|
||||
nsock_ev_handler handler, void *userdata,
|
||||
struct sockaddr *ss, size_t sslen,
|
||||
unsigned short port);
|
||||
/* Request a UDP "connection" to another system (by IP address). The in_addr is
|
||||
* normal network byte order, but the port number should be given in HOST BYTE
|
||||
* ORDER. Since this is UDP, no packets are actually sent. The destination IP
|
||||
* and port are just associated with the nsiod (an actual OS connect() call is
|
||||
* made). You can then use the normal nsock write calls on the socket. There
|
||||
* is no timeout since this call always calls your callback at the next
|
||||
* opportunity. The advantages to having a connected UDP socket (as opposed to
|
||||
* just specifying an address with sendto() are that we can now use a consistent
|
||||
* set of write/read calls for TCP/UDP, received packets from the non-partner
|
||||
* are automatically dropped by the OS, and the OS can provide asynchronous
|
||||
* errors (see Unix Network Programming pp224). ss should be a
|
||||
* sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate (just like what
|
||||
* you would pass to connect). sslen should be the sizeof the structure you are
|
||||
* passing in. */
|
||||
nsock_event_id nsock_connect_udp(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, void *userdata,
|
||||
struct sockaddr *ss, size_t sslen, unsigned short port);
|
||||
|
||||
/* Request an SSL over TCP/SCTP connection to another system (by IP
|
||||
address). The in_addr is normal network byte order, but the port
|
||||
number should be given in HOST BYTE ORDER. This function will call
|
||||
back only after it has made the connection AND done the initial
|
||||
SSL negotiation. From that point on, you use the normal read/write
|
||||
calls and decryption will happen transparently. ss should be a
|
||||
sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate (just
|
||||
like what you would pass to connect). sslen should be the sizeof
|
||||
the structure you are passing in. */
|
||||
nsock_event_id nsock_connect_ssl(nsock_pool nsp, nsock_iod nsiod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *ss,
|
||||
size_t sslen, int proto, unsigned short port,
|
||||
nsock_ssl_session ssl_session);
|
||||
/* Request an SSL over TCP/SCTP connection to another system (by IP address).
|
||||
* The in_addr is normal network byte order, but the port number should be given
|
||||
* in HOST BYTE ORDER. This function will call back only after it has made the
|
||||
* connection AND done the initial SSL negotiation. From that point on, you use
|
||||
* the normal read/write calls and decryption will happen transparently. ss
|
||||
* should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate
|
||||
* (just like what you would pass to connect). sslen should be the sizeof the
|
||||
* structure you are passing in. */
|
||||
nsock_event_id nsock_connect_ssl(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *ss, size_t sslen, int proto, unsigned short port, nsock_ssl_session ssl_session);
|
||||
|
||||
/* Request ssl connection over already established TCP/SCTP connection.
|
||||
nsiod must be socket that is already connected to target
|
||||
using nsock_connect_tcp or nsock_connect_sctp.
|
||||
All parameters have the same meaning as in 'nsock_connect_ssl' */
|
||||
/* Request ssl connection over already established TCP/SCTP connection. nsiod
|
||||
* must be socket that is already connected to target using nsock_connect_tcp or
|
||||
* nsock_connect_sctp. All parameters have the same meaning as in
|
||||
* 'nsock_connect_ssl' */
|
||||
nsock_event_id nsock_reconnect_ssl(nsock_pool nsp, nsock_iod nsiod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, nsock_ssl_session ssl_session);
|
||||
nsock_ev_handler handler, int timeout_msecs, void *userdata, nsock_ssl_session ssl_session);
|
||||
|
||||
/* Read up to nlines lines (terminated with \n, which of course
|
||||
inclues \r\n), or until EOF, or until the timeout, whichever comes
|
||||
first. Note that NSE_STATUS_SUCCESS will be returned in the case
|
||||
of EOF or 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 */
|
||||
/* 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 nsiod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, int nlines);
|
||||
nsock_ev_handler handler, int timeout_msecs, void *userdata, int nlines);
|
||||
|
||||
/* Same as above, except it tries to read at least 'nbytes' instead of
|
||||
'nlines'. */
|
||||
/* Same as above, except it tries to read at least 'nbytes' instead of 'nlines'. */
|
||||
nsock_event_id nsock_readbytes(nsock_pool nsp, nsock_iod nsiod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, int nbytes);
|
||||
nsock_ev_handler handler, int timeout_msecs, void *userdata, int nbytes);
|
||||
|
||||
/* The simplest read function -- returns NSE_STATUS_SUCCESS when it
|
||||
reads anything, otherwise it returns timeout, eof, or error as
|
||||
appropriate */
|
||||
nsock_event_id nsock_read(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler,
|
||||
int timeout_msecs, void *userdata);
|
||||
/* The simplest read function -- returns NSE_STATUS_SUCCESS when it reads
|
||||
* anything, otherwise it returns timeout, eof, or error as appropriate */
|
||||
nsock_event_id nsock_read(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs, void *userdata);
|
||||
|
||||
/* Write some data to the socket. If the write is not COMPLETED within timeout_msecs , NSE_STATUS_TIMEOUT will be returned. If you are supplying NUL-terminated data, you can optionally pass -1 for datalen and nsock_write will figure out the length itself */
|
||||
/* Write some data to the socket. If the write is not COMPLETED within
|
||||
* timeout_msecs , NSE_STATUS_TIMEOUT will be returned. If you are supplying
|
||||
* NUL-terminated data, you can optionally pass -1 for datalen and nsock_write
|
||||
* will figure out the length itself */
|
||||
nsock_event_id nsock_write(nsock_pool nsp, nsock_iod nsiod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, const char *data, int datalen);
|
||||
nsock_ev_handler handler, int timeout_msecs, void *userdata, const char *data, int datalen);
|
||||
|
||||
nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *saddr, size_t sslen,
|
||||
unsigned short port, const char *data, int datalen);
|
||||
nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port, const char *data, int datalen);
|
||||
|
||||
/* Same as nsock_write except you can use a printf-style format and you can only use this for ASCII strings */
|
||||
/* Same as nsock_write except you can use a printf-style format and you can only
|
||||
* use this for ASCII strings */
|
||||
nsock_event_id nsock_printf(nsock_pool nsp, nsock_iod nsiod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, char *format, ... );
|
||||
nsock_ev_handler handler, int timeout_msecs, void *userdata, char *format, ... );
|
||||
|
||||
/* Send back an NSE_TYPE_TIMER after the number of milliseconds specified. Of course it can also return due to error, cancellation, etc. */
|
||||
nsock_event_id nsock_timer_create(nsock_pool nsp, nsock_ev_handler handler,
|
||||
int timeout_msecs, void *userdata);
|
||||
/* Send back an NSE_TYPE_TIMER after the number of milliseconds specified. Of
|
||||
* course it can also return due to error, cancellation, etc. */
|
||||
nsock_event_id nsock_timer_create(nsock_pool nsp, nsock_ev_handler handler, int timeout_msecs, void *userdata);
|
||||
|
||||
/* Cancel an event (such as a timer or read request). If notify is
|
||||
nonzero, the requester will be sent an event CANCELLED status back to
|
||||
the given handler. But in some cases there is no need to do this
|
||||
(like if the function deleting it is the one which created it), in
|
||||
which case 0 can be passed to skip the step. This function returns
|
||||
zero if the event is not found, nonzero otherwise */
|
||||
/* Cancel an event (such as a timer or read request). If notify is nonzero, the
|
||||
* requester will be sent an event CANCELLED status back to the given handler.
|
||||
* But in some cases there is no need to do this (like if the function deleting
|
||||
* it is the one which created it), in which case 0 can be passed to skip the
|
||||
* step. This function returns zero if the event is not found, nonzero
|
||||
* otherwise */
|
||||
int nsock_event_cancel(nsock_pool ms_pool, nsock_event_id id, int notify );
|
||||
|
||||
/* Grab the latest time as recorded by the nsock library, which does
|
||||
so at least once per event loop (in main_loop). Not only does this
|
||||
function (generally) avoid a system call, but in many circumstances
|
||||
it is better to use nsock's time rather than the system time. If
|
||||
nsock has never obtained the time when you call it, it will do so
|
||||
before returning */
|
||||
/* Grab the latest time as recorded by the nsock library, which does so at least
|
||||
* once per event loop (in main_loop). Not only does this function (generally)
|
||||
* avoid a system call, but in many circumstances it is better to use nsock's
|
||||
* time rather than the system time. If nsock has never obtained the time when
|
||||
* you call it, it will do so before returning */
|
||||
const struct timeval *nsock_gettimeofday();
|
||||
|
||||
|
||||
#ifdef HAVE_PCAP
|
||||
/*
|
||||
* Open pcap device and connect it to nsp. Other parameters have the
|
||||
/* Open pcap device and connect it to nsp. Other parameters have the
|
||||
* same meaning as for pcap_open_live in pcap(3).
|
||||
* device : pcap-style device name
|
||||
* snaplen : size of packet to be copied to handler
|
||||
* promisc : whether to open device in promiscous mode
|
||||
* bpf_fmt : berkeley filter
|
||||
*
|
||||
* device: pcap-style device name
|
||||
* snaplen: size of packet to be copied to handler
|
||||
* 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
|
||||
* [sorry Fyodor for breaking the API, but it's just simpler]
|
||||
* */
|
||||
char *nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod,
|
||||
const char *pcap_device, int snaplen, int promisc,
|
||||
const char *bpf_fmt, ...);
|
||||
char *nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod, 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.
|
||||
* */
|
||||
nsock_event_id nsock_pcap_read_packet(nsock_pool nsp, nsock_iod nsiod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata);
|
||||
/* Requests exacly one packet to be captured.from pcap.See nsock_read() for parameters description. */
|
||||
nsock_event_id nsock_pcap_read_packet(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs, void *userdata);
|
||||
|
||||
/*
|
||||
* Gets packet data. This should be called after 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
|
||||
* instead of valid pointer.
|
||||
* 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
|
||||
* think that host is a bit further.
|
||||
* */
|
||||
void nse_readpcap(nsock_event nsee,
|
||||
const unsigned char **l2_data, size_t *l2_len,
|
||||
const unsigned char **l3_data, size_t *l3_len,
|
||||
void nse_readpcap(nsock_event nsee, const unsigned char **l2_data, size_t *l2_len, const unsigned char **l3_data, size_t *l3_len,
|
||||
size_t *packet_len, struct timeval *ts);
|
||||
|
||||
/* Well. Just pcap-style datalink. Like DLT_EN10MB or DLT_SLIP. Check in pcap(3) manpage. */
|
||||
@@ -604,11 +553,3 @@ int nsi_is_pcap(nsock_iod nsiod);
|
||||
|
||||
#endif /* NSOCK_H */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -74,3 +74,6 @@
|
||||
#undef HAVE_SYS_IOCTL_H
|
||||
|
||||
#undef HAVE_SSL_SET_TLSEXT_HOST_NAME
|
||||
|
||||
#undef HAVE_EPOLL
|
||||
|
||||
|
||||
@@ -182,12 +182,15 @@
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\engine_epoll.c" />
|
||||
<ClCompile Include="src\engine_select.c" />
|
||||
<ClCompile Include="src\error.c" />
|
||||
<ClCompile Include="src\filespace.c" />
|
||||
<ClCompile Include="src\gh_list.c" />
|
||||
<ClCompile Include="src\netutils.c" />
|
||||
<ClCompile Include="src\nsock_connect.c" />
|
||||
<ClCompile Include="src\nsock_core.c" />
|
||||
<ClCompile Include="src\nsock_engines.c" />
|
||||
<ClCompile Include="src\nsock_event.c" />
|
||||
<ClCompile Include="src\nsock_iod.c" />
|
||||
<ClCompile Include="src\nsock_pcap.c" />
|
||||
|
||||
@@ -27,9 +27,9 @@ NBASEDIR=@NBASEDIR@
|
||||
|
||||
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
|
||||
|
||||
|
||||
648
nsock/src/configure
vendored
648
nsock/src/configure
vendored
@@ -1426,6 +1426,52 @@ fi
|
||||
|
||||
} # 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
|
||||
# ----------------------------------
|
||||
# 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
|
||||
|
||||
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_cpp='$CPP $CPPFLAGS'
|
||||
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
|
||||
@@ -3166,53 +3767,6 @@ if ${ac_cv_lib_nsl_gethostent+:} false; then :
|
||||
else
|
||||
ac_check_lib_save_LIBS=$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
|
||||
/* end confdefs.h. */
|
||||
|
||||
|
||||
@@ -107,6 +107,8 @@ if test "$pcap_enabled" != "no"; then
|
||||
AC_DEFINE(HAVE_PCAP)
|
||||
fi
|
||||
|
||||
AC_CHECK_FUNCS(epoll_create epoll_ctl epoll_wait, [AC_DEFINE(HAVE_EPOLL)], )
|
||||
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
if test -n "$GCC"; then
|
||||
|
||||
396
nsock/src/engine_epoll.c
Normal file
396
nsock/src/engine_epoll.c
Normal 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
409
nsock/src/engine_select.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* error.c -- a few simple routines for dealing with errors (quitting, *
|
||||
* printing error messages, etc. *
|
||||
@@ -59,28 +58,40 @@
|
||||
#include "error.h"
|
||||
|
||||
void fatal(char *fmt, ...) {
|
||||
va_list ap;va_start(ap, fmt);
|
||||
fflush(stdout);vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");va_end(ap);
|
||||
exit(1);}
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fflush(stdout);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void pfatal(char *fmt, ...) {
|
||||
va_list ap;va_start(ap, fmt);
|
||||
fflush(stdout);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, ": ");
|
||||
perror("");
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fflush(stdout);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, ": ");
|
||||
perror("");
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void gh_perror(char *err, ...) {
|
||||
va_list ap;va_start(ap, err);
|
||||
fflush(stdout);
|
||||
vfprintf(stderr, err, ap);
|
||||
va_end(ap);
|
||||
perror(" ");
|
||||
fflush(stderr);
|
||||
return;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, err);
|
||||
fflush(stdout);
|
||||
vfprintf(stderr, err, ap);
|
||||
va_end(ap);
|
||||
|
||||
perror(" ");
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* error.h -- a few simple routines for dealing with errors (quitting, *
|
||||
* printing error messages, etc. *
|
||||
@@ -76,10 +75,12 @@
|
||||
#endif
|
||||
|
||||
void fatal(char *fmt, ...) __attribute__((noreturn));
|
||||
|
||||
void myerror(char *fmt, ...);
|
||||
|
||||
void pfatal(char *fmt, ...) __attribute__((noreturn));
|
||||
|
||||
void gh_perror(char *err, ...);
|
||||
|
||||
#endif /* ERROR_H */
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* filespace.c -- a simple mechanism for storing dynamic amounts of data *
|
||||
* in a simple to use, and quick to append-to structure. *
|
||||
@@ -61,51 +60,44 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define FS_INITSIZE_DEFAULT 1024
|
||||
|
||||
|
||||
/* Assumes space for fs has already been allocated */
|
||||
int filespace_init(struct filespace *fs, int initial_size) {
|
||||
|
||||
memset(fs, 0, sizeof(struct filespace));
|
||||
if (initial_size == 0)
|
||||
initial_size = 1024;
|
||||
initial_size = FS_INITSIZE_DEFAULT;
|
||||
|
||||
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->pos = fs->str;
|
||||
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 */
|
||||
int fs_prepend(char *str, int len, struct filespace *fs) {
|
||||
char *tmpstr;
|
||||
int fs_prepend(char *str, int len, struct filespace *fs){
|
||||
char *tmpstr;
|
||||
|
||||
if (len < 0) return -1;
|
||||
if (len == 0) return 0;
|
||||
if (len < 0)
|
||||
return -1;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
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;
|
||||
tmpstr = (char *) safe_malloc(fs->current_alloc);
|
||||
|
||||
tmpstr = (char *)safe_malloc(fs->current_alloc);
|
||||
memcpy(tmpstr, fs->str, fs->current_size);
|
||||
|
||||
fs->pos = (fs->pos - fs->str) + tmpstr;
|
||||
if (fs->str) free(fs->str);
|
||||
if (fs->str)
|
||||
free(fs->str);
|
||||
|
||||
fs->str = tmpstr;
|
||||
}
|
||||
if (fs->current_size > 0)
|
||||
@@ -117,14 +109,21 @@ if (len == 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* filespace.h -- a simple mechanism for storing dynamic amounts of data *
|
||||
* in a simple to use, and quick to append-to structure. *
|
||||
@@ -83,19 +82,25 @@
|
||||
struct filespace {
|
||||
int current_size;
|
||||
int current_alloc;
|
||||
char *pos; /* Current position in the filespace */
|
||||
|
||||
/* Current position in the filespace */
|
||||
char *pos;
|
||||
char *str;
|
||||
};
|
||||
|
||||
/* If you want to express a length, use fscat() */
|
||||
static inline int fs_rputs(const char *str, struct filespace *fs) {
|
||||
char *new_str;
|
||||
int len = (int) strlen(str);
|
||||
int len;
|
||||
|
||||
len = (int)strlen(str);
|
||||
|
||||
if (len + fs->current_size + 1 > fs->current_alloc) {
|
||||
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);
|
||||
|
||||
fs->pos = (fs->pos - fs->str) + new_str;
|
||||
if (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);
|
||||
fs->current_size += len;
|
||||
fs->str[fs->current_size] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline int fs_rvputs(struct filespace *fs,...)
|
||||
{
|
||||
static inline int fs_rvputs(struct filespace *fs,...) {
|
||||
va_list args;
|
||||
const char *x;
|
||||
|
||||
@@ -118,30 +123,36 @@ static inline int fs_rvputs(struct filespace *fs,...)
|
||||
x = va_arg(args, const char *);
|
||||
if (x == NULL)
|
||||
break;
|
||||
|
||||
if (fs_rputs(x,fs) == -1) {
|
||||
va_end(args);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Concatenate a string to the end of a filespace */
|
||||
static inline int fscat(struct filespace *fs, const char *str, int len) {
|
||||
char *tmpstr;
|
||||
char *tmpstr;
|
||||
|
||||
if (len < 0) return -1;
|
||||
if (len == 0) return 0;
|
||||
if (len < 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) {
|
||||
fs->current_alloc = (int) (fs->current_alloc * 1.4 + 1 );
|
||||
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);
|
||||
|
||||
fs->pos = (fs->pos - fs->str) + tmpstr;
|
||||
if (fs->str) free(fs->str);
|
||||
fs->str = tmpstr;
|
||||
@@ -154,25 +165,30 @@ if (len == 0) return 0;
|
||||
}
|
||||
|
||||
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->current_size++;
|
||||
fs->str[fs->current_size] = '\0';
|
||||
} /* otherwise we use the ueber-technique of letting fscat handle it ...
|
||||
umm actually I don't know why we don't do this in all cases ... */
|
||||
else {
|
||||
} else {
|
||||
/* otherwise we use the ueber-technique of letting fscat handle it ... umm
|
||||
* actually I don't know why we don't do this in all cases ... */
|
||||
s[0] = ch;
|
||||
s[1] = '\0';
|
||||
fscat(fs, s, 1);
|
||||
}
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fs_free(struct filespace *fs);
|
||||
|
||||
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_clear(struct filespace *fs);
|
||||
|
||||
int fs_free(struct filespace *fs);
|
||||
|
||||
#endif /* FILESPACE_H */
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* gh_list.c -- a simple doubly-linked list implementation with a very *
|
||||
* heavy focus on efficiency. *
|
||||
@@ -69,6 +68,21 @@
|
||||
#include <strings.h>
|
||||
#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
|
||||
int main(int argc, char *argv[]) {
|
||||
gh_list lists[16];
|
||||
@@ -82,13 +96,13 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
for(num=25000; num < 50000; num++) {
|
||||
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(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(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(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");
|
||||
for(num=25000; num < 50000; num++) {
|
||||
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(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(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(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) {
|
||||
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));
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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 i;
|
||||
if (!newlist) return -1;
|
||||
int i;
|
||||
|
||||
newlist->count = 0;
|
||||
newlist->first = newlist->last = NULL;
|
||||
newlist->last_alloc = 32;
|
||||
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++) {
|
||||
if (!newlist)
|
||||
return -1;
|
||||
|
||||
newlist->count = 0;
|
||||
newlist->first = newlist->last = NULL;
|
||||
newlist->last_alloc = 16;
|
||||
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;
|
||||
}
|
||||
/* Not needed (newlist->free + newlist->last_alloc - 1)->next = NULL */
|
||||
#ifndef NDEBUG
|
||||
newlist->magic = GH_LIST_MAGIC;
|
||||
newlist->magic = GH_LIST_MAGIC;
|
||||
#endif
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
gh_list_elem *gh_list_append(gh_list *list, void *data) {
|
||||
gh_list_elem *newelem;
|
||||
gh_list_elem *oldlast;
|
||||
|
||||
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));
|
||||
SAFETY_CHECK_LIST(list);
|
||||
|
||||
newelem = get_free_buffer(list);
|
||||
oldlast = list->last;
|
||||
|
||||
if (oldlast) {
|
||||
oldlast->next = newelem;
|
||||
newelem->prev = oldlast;
|
||||
} else newelem->prev = NULL;
|
||||
} else {
|
||||
newelem->prev = NULL;
|
||||
}
|
||||
|
||||
newelem->next = NULL;
|
||||
newelem->data = data;
|
||||
|
||||
#ifndef NDEBUG
|
||||
newelem->magic = GH_LIST_MAGIC;
|
||||
#endif
|
||||
|
||||
list->count++;
|
||||
list->last = newelem;
|
||||
|
||||
if (list->count == 1)
|
||||
list->first = 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 *oldfirst;
|
||||
|
||||
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));
|
||||
SAFETY_CHECK_LIST(list);
|
||||
|
||||
newelem = get_free_buffer(list);
|
||||
oldfirst = list->first;
|
||||
if (oldfirst) {
|
||||
oldfirst->prev = newelem;
|
||||
newelem->next = oldfirst;
|
||||
} else newelem->next = NULL;
|
||||
} else {
|
||||
newelem->next = NULL;
|
||||
}
|
||||
|
||||
newelem->prev = NULL;
|
||||
newelem->data = data;
|
||||
|
||||
#ifndef NDEBUG
|
||||
newelem->magic = GH_LIST_MAGIC;
|
||||
#endif
|
||||
|
||||
list->count++;
|
||||
list->first = newelem;
|
||||
|
||||
if (list->count == 1)
|
||||
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;
|
||||
}
|
||||
|
||||
void *gh_list_pop(gh_list *list) {
|
||||
struct gh_list_elem *oldelem;
|
||||
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));
|
||||
|
||||
SAFETY_CHECK_LIST(list);
|
||||
|
||||
oldelem = list->first;
|
||||
if (!oldelem) return NULL;
|
||||
if (!oldelem)
|
||||
return NULL;
|
||||
|
||||
list->first = list->first->next;
|
||||
if (list->first)
|
||||
list->first->prev = NULL;
|
||||
|
||||
list->count--;
|
||||
|
||||
if (list->count < 2)
|
||||
list->last = list->first;
|
||||
|
||||
oldelem->next = list->free;
|
||||
list->free = oldelem;
|
||||
|
||||
@@ -308,44 +365,39 @@ int gh_list_free(gh_list *list) {
|
||||
struct gh_list_elem *current;
|
||||
char *free_list[32];
|
||||
int free_index = 0;
|
||||
int i=0;
|
||||
int i = 0;
|
||||
|
||||
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));
|
||||
SAFETY_CHECK_LIST(list);
|
||||
|
||||
#ifndef NDEBUG
|
||||
list->magic++;
|
||||
#endif
|
||||
for(current = list->first; current; current = current->next) {
|
||||
# ifndef NDEBUG
|
||||
|
||||
for (current = list->first; current; current = current->next) {
|
||||
#ifndef NDEBUG
|
||||
current->magic++;
|
||||
# endif
|
||||
#endif
|
||||
if (current->allocated) {
|
||||
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) {
|
||||
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]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gh_list_remove_elem(gh_list *list, gh_list_elem *elem) {
|
||||
assert(elem);
|
||||
assert(elem->magic == GH_LIST_MAGIC);
|
||||
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));
|
||||
SAFETY_CHECK_ELEM(elem);
|
||||
SAFETY_CHECK_LIST(list);
|
||||
|
||||
if (elem->prev) {
|
||||
elem->prev->next = elem->next;
|
||||
@@ -372,26 +424,41 @@ int gh_list_remove_elem(gh_list *list, gh_list_elem *elem) {
|
||||
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) {
|
||||
struct gh_list_elem *current;
|
||||
|
||||
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));
|
||||
SAFETY_CHECK_LIST(list);
|
||||
|
||||
for(current = list->first; current; current = current->next) {
|
||||
for (current = list->first; current; current = current->next) {
|
||||
if (current->data == data)
|
||||
return gh_list_remove_elem(list, current);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* gh_list.h -- a simple doubly-linked list implementation with a very *
|
||||
* heavy focus on efficiency. *
|
||||
@@ -75,37 +74,51 @@
|
||||
|
||||
/* Take a LIST ELEMENT (not just the data) and return the next one */
|
||||
#define GH_LIST_ELEM_NEXT(x) ((x)->next)
|
||||
|
||||
/* Same as above but return the previous element */
|
||||
#define GH_LIST_ELEM_PREV(x) ((x)->prev)
|
||||
|
||||
/* Take a LIST (not a list element) and return the first element */
|
||||
#define GH_LIST_FIRST_ELEM(x) ((x)->first)
|
||||
|
||||
/* Same as above but return the last element */
|
||||
#define GH_LIST_LAST_ELEM(x) ((x)->last)
|
||||
|
||||
/* Obtain the actual data stored in an element */
|
||||
#define GH_LIST_ELEM_DATA(x) ((x)->data)
|
||||
|
||||
/* Obtain the number of elements in a list */
|
||||
#define GH_LIST_COUNT(x) ((x)->count)
|
||||
|
||||
|
||||
typedef struct gh_list_elem {
|
||||
void *data;
|
||||
struct gh_list_elem *next;
|
||||
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
|
||||
long as we are OK with freeing others that were freed
|
||||
with it ... */
|
||||
|
||||
/* nonzero if this element was the first (or only) in a group that was
|
||||
* allocated. This means we can safely free() it as long as we are OK with
|
||||
* freeing others that were freed with it ... */
|
||||
int allocated;
|
||||
|
||||
#ifndef NDEBUG
|
||||
unsigned long magic;
|
||||
#endif
|
||||
} gh_list_elem;
|
||||
|
||||
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 *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. */
|
||||
int last_alloc; /* The number of list elements in the most recent malloc */
|
||||
|
||||
/* Instead of free()ing elements when something is removed from the list, we
|
||||
* 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
|
||||
unsigned long magic;
|
||||
#endif
|
||||
@@ -113,12 +126,22 @@ typedef struct gh_list {
|
||||
|
||||
|
||||
int gh_list_init(gh_list *newlist);
|
||||
|
||||
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_insert_before(gh_list *list, gh_list_elem *before, void *data);
|
||||
|
||||
void *gh_list_pop(gh_list *list);
|
||||
|
||||
int gh_list_remove(gh_list *list, void *data);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
#endif /* GH_LIST_H */
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* netutils.c -- This contains some useful little network/socket related *
|
||||
* utility functions. *
|
||||
@@ -87,17 +86,15 @@
|
||||
|
||||
static int netutils_debugging = 0;
|
||||
|
||||
/* maximize the number of file descriptors (including sockets) allowed
|
||||
for this process and return that maximum value (note -- you better
|
||||
not actually open this many -- stdin, stdout, other files opened by
|
||||
libraries you use, etc. all count toward this limit. Leave a
|
||||
little slack */
|
||||
/* maximize the number of file descriptors (including sockets) allowed for this
|
||||
* process and return that maximum value (note -- you better not actually open
|
||||
* this many -- stdin, stdout, other files opened by libraries you use, etc. all
|
||||
* count toward this limit. Leave a little slack */
|
||||
int maximize_fdlimit(void) {
|
||||
|
||||
int maximize_fdlimit() {
|
||||
#ifndef WIN32
|
||||
|
||||
struct rlimit r;
|
||||
static int maxfds = -1;
|
||||
struct rlimit r;
|
||||
static int maxfds = -1;
|
||||
|
||||
if (maxfds > 0)
|
||||
return maxfds;
|
||||
@@ -106,22 +103,31 @@ static int maxfds = -1;
|
||||
if (!getrlimit(RLIMIT_NOFILE, &r)) {
|
||||
r.rlim_cur = r.rlim_max;
|
||||
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)) {
|
||||
maxfds = r.rlim_cur;
|
||||
return maxfds;
|
||||
} else return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if(defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE))
|
||||
if (!getrlimit(RLIMIT_OFILE, &r)) {
|
||||
r.rlim_cur = r.rlim_max;
|
||||
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)) {
|
||||
maxfds = r.rlim_cur;
|
||||
return maxfds;
|
||||
} else return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* !WIN32 */
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* netutils.h -- This contains some useful little network/socket related *
|
||||
* utility functions. *
|
||||
@@ -70,12 +69,11 @@
|
||||
#include "nbase_winunix.h"
|
||||
#endif
|
||||
|
||||
/* maximize the number of file descriptors (including sockets) allowed
|
||||
for this process and return that maximum value (note -- you better
|
||||
not actually open this many -- stdin, stdout, other files opened by
|
||||
libraries you use, etc. all count toward this limit. Leave a
|
||||
little slack */
|
||||
int maximize_fdlimit();
|
||||
/* Maximize the number of file descriptors (including sockets) allowed for this
|
||||
* process and return that maximum value (note -- you better not actually open
|
||||
* this many -- stdin, stdout, other files opened by libraries you use, etc. all
|
||||
* count toward this limit. Leave a little slack */
|
||||
int maximize_fdlimit(void);
|
||||
|
||||
#endif /* NETUTILS_H */
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* nsock_connect.c -- This contains the functions for requesting TCP *
|
||||
* connections from the nsock parallel socket event library *
|
||||
@@ -65,15 +64,14 @@
|
||||
|
||||
extern struct timeval nsock_tod;
|
||||
|
||||
/* Create the actual socket (nse->iod->sd) underlying the iod. This
|
||||
unblocks the socket, binds to the localaddr address, sets IP options,
|
||||
and sets the broadcast flag. Trying to change these functions after
|
||||
making this call will not have an effect. This function needs to be
|
||||
called before you try to read or write on the iod. */
|
||||
/* Create the actual socket (nse->iod->sd) underlying the iod. This unblocks the
|
||||
* socket, binds to the localaddr address, sets IP options, and sets the
|
||||
* broadcast flag. Trying to change these functions after making this call will
|
||||
* not have an effect. This function needs to be called before you try to read
|
||||
* or write on the iod. */
|
||||
static int nsock_make_socket(mspool *ms, msiod *iod, int family, int proto) {
|
||||
/* inheritable_socket is from nbase */
|
||||
iod->sd = (int) inheritable_socket(family,
|
||||
(proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM, proto);
|
||||
iod->sd = (int)inheritable_socket(family, (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM, proto);
|
||||
if (iod->sd == -1) {
|
||||
perror("Socket troubles");
|
||||
return -1;
|
||||
@@ -85,34 +83,32 @@ static int nsock_make_socket(mspool *ms, msiod *iod, int family, int proto) {
|
||||
|
||||
if (iod->locallen) {
|
||||
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)
|
||||
nsock_trace(ms, "Bind to %s failed (IOD #%li)",
|
||||
inet_ntop_ez(&iod->local, iod->locallen), iod->id);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
nsock_trace(ms, "Setting of IP options failed (IOD #%li)", iod->id);
|
||||
}
|
||||
}
|
||||
|
||||
if (ms->broadcast) {
|
||||
if (setsockopt(iod->sd, SOL_SOCKET, SO_BROADCAST, (const char *)&(ms->broadcast), sizeof(int)) == -1) {
|
||||
if (ms->tracelevel > 0)
|
||||
nsock_trace(ms, "Setting of SO_BROADCAST failed (IOD #%li)", iod->id);
|
||||
}
|
||||
}
|
||||
|
||||
return iod->sd;
|
||||
}
|
||||
|
||||
int nsock_setup_udp(nsock_pool nsp, nsock_iod ms_iod, int af) {
|
||||
mspool *ms = (mspool *) nsp;
|
||||
msiod *nsi = (msiod *) ms_iod;
|
||||
mspool *ms = (mspool *)nsp;
|
||||
msiod *nsi = (msiod *)ms_iod;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* This does the actual logistics of requesting a TCP connection. It is
|
||||
* shared by nsock_connect_tcp and nsock_connect_ssl */
|
||||
void nsock_connect_internal(mspool *ms, msevent *nse, int proto,
|
||||
struct sockaddr_storage *ss, size_t sslen,
|
||||
unsigned short port)
|
||||
{
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *) ss;
|
||||
/* This does the actual logistics of requesting a TCP connection. It is shared
|
||||
* by nsock_connect_tcp and nsock_connect_ssl */
|
||||
void nsock_connect_internal(mspool *ms, msevent *nse, int proto, struct sockaddr_storage *ss, size_t sslen,
|
||||
unsigned short port) {
|
||||
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)ss;
|
||||
#if HAVE_IPV6
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ss;
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss;
|
||||
#endif
|
||||
msiod *iod = nse->iod;
|
||||
|
||||
/* Now it is time to actually attempt the connection */
|
||||
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 {
|
||||
if (sin->sin_family == AF_INET) {
|
||||
sin->sin_port = htons(port);
|
||||
@@ -155,10 +152,11 @@ void nsock_connect_internal(mspool *ms, msevent *nse, int proto,
|
||||
}
|
||||
|
||||
assert(sslen <= sizeof(iod->peer));
|
||||
if (&iod->peer != ss)
|
||||
memcpy(&iod->peer, ss, 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();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
/* The callback handle_connect_result handles the connection once it
|
||||
completes. */
|
||||
/* The callback handle_connect_result handles the connection once it completes. */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Request a TCP connection to another system (by IP address). The
|
||||
in_addr is normal network byte order, but the port number should be
|
||||
given in HOST BYTE ORDER. ss should be a sockaddr_storage,
|
||||
sockaddr_in6, or sockaddr_in as appropriate (just like what you
|
||||
would pass to connect). sslen should be the sizeof the structure
|
||||
you are passing in. */
|
||||
nsock_event_id nsock_connect_tcp(nsock_pool nsp, nsock_iod ms_iod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *saddr,
|
||||
size_t sslen, unsigned short port) {
|
||||
/* Request a TCP connection to another system (by IP address). The in_addr is
|
||||
* normal network byte order, but the port number should be given in HOST BYTE
|
||||
* ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as
|
||||
* appropriate (just like what you would pass to connect). sslen should be the
|
||||
* sizeof the structure you are passing in. */
|
||||
nsock_event_id nsock_connect_tcp(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port) {
|
||||
|
||||
msiod *nsi = (msiod *) ms_iod;
|
||||
mspool *ms = (mspool *) nsp;
|
||||
msiod *nsi = (msiod *)ms_iod;
|
||||
mspool *ms = (mspool *)nsp;
|
||||
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);
|
||||
|
||||
@@ -208,21 +202,18 @@ nsock_event_id nsock_connect_tcp(nsock_pool nsp, nsock_iod ms_iod,
|
||||
return nse->id;
|
||||
}
|
||||
|
||||
/* Request an SCTP association to another system (by IP address). The
|
||||
in_addr is normal network byte order, but the port number should be
|
||||
given in HOST BYTE ORDER. ss should be a sockaddr_storage,
|
||||
sockaddr_in6, or sockaddr_in as appropriate (just like what you
|
||||
would pass to connect). sslen should be the sizeof the structure
|
||||
you are passing in. */
|
||||
nsock_event_id nsock_connect_sctp(nsock_pool nsp, nsock_iod ms_iod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *saddr,
|
||||
size_t sslen, unsigned short port) {
|
||||
/* Request an SCTP association to another system (by IP address). The in_addr
|
||||
* is normal network byte order, but the port number should be given in HOST
|
||||
* BYTE ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as
|
||||
* appropriate (just like what you would pass to connect). sslen should be the
|
||||
* sizeof the structure you are passing in. */
|
||||
nsock_event_id nsock_connect_sctp(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port) {
|
||||
|
||||
msiod *nsi = (msiod *) ms_iod;
|
||||
mspool *ms = (mspool *) nsp;
|
||||
msiod *nsi = (msiod *)ms_iod;
|
||||
mspool *ms = (mspool *)nsp;
|
||||
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);
|
||||
|
||||
@@ -243,28 +234,24 @@ nsock_event_id nsock_connect_sctp(nsock_pool nsp, nsock_iod ms_iod,
|
||||
return nse->id;
|
||||
}
|
||||
|
||||
/* Request an SSL over TCP/SCTP connection to another system (by IP
|
||||
address). The in_addr is normal network byte order, but the port
|
||||
number should be given in HOST BYTE ORDER. This function will call
|
||||
back only after it has made the connection AND done the initial
|
||||
SSL negotiation. From that point on, you use the normal read/write
|
||||
calls and decryption will happen transparently. ss should be a
|
||||
sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate (just
|
||||
like what you would pass to connect). sslen should be the sizeof
|
||||
the structure you are passing in. */
|
||||
nsock_event_id nsock_connect_ssl(nsock_pool nsp, nsock_iod nsiod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *saddr,
|
||||
size_t sslen, int proto, unsigned short port,
|
||||
nsock_ssl_session ssl_session) {
|
||||
/* Request an SSL over TCP/SCTP connection to another system (by IP address).
|
||||
* The in_addr is normal network byte order, but the port number should be given
|
||||
* in HOST BYTE ORDER. This function will call back only after it has made the
|
||||
* connection AND done the initial SSL negotiation. From that point on, you use
|
||||
* the normal read/write calls and decryption will happen transparently. ss
|
||||
* should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate
|
||||
* (just like what you would pass to connect). sslen should be the sizeof the
|
||||
* structure you are passing in. */
|
||||
nsock_event_id nsock_connect_ssl(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *saddr, size_t sslen, int proto, unsigned short port, nsock_ssl_session ssl_session) {
|
||||
|
||||
#ifndef HAVE_OPENSSL
|
||||
fatal("nsock_connect_ssl called - but nsock was built w/o SSL support. QUITTING");
|
||||
return (nsock_event_id) 0; /* UNREACHED */
|
||||
return (nsock_event_id)0; /* UNREACHED */
|
||||
#else
|
||||
struct sockaddr_storage *ss = (struct sockaddr_storage *) saddr;
|
||||
msiod *nsi = (msiod *) nsiod;
|
||||
mspool *ms = (mspool *) nsp;
|
||||
struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;
|
||||
msiod *nsi = (msiod *)nsiod;
|
||||
mspool *ms = (mspool *)nsp;
|
||||
msevent *nse;
|
||||
|
||||
/* 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);
|
||||
|
||||
nse = msevent_new(ms, NSE_TYPE_CONNECT_SSL, nsi, timeout_msecs, handler,
|
||||
userdata);
|
||||
nse = msevent_new(ms, NSE_TYPE_CONNECT_SSL, nsi, timeout_msecs, handler, userdata);
|
||||
assert(nse);
|
||||
|
||||
/* Set our SSL_SESSION so we can benefit from session-id reuse. */
|
||||
nsi_set_ssl_session(nsi, (SSL_SESSION *) ssl_session);
|
||||
nsi_set_ssl_session(nsi, (SSL_SESSION *)ssl_session);
|
||||
|
||||
if (ms->tracelevel > 0)
|
||||
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"),
|
||||
nsi->id, nse->id);
|
||||
inet_ntop_ez(ss, sslen), port, (proto == IPPROTO_TCP ? "tcp" : "sctp"), nsi->id, nse->id);
|
||||
|
||||
/* Do the actual connect() */
|
||||
nsock_connect_internal(ms, nse, proto, ss, sslen, port);
|
||||
@@ -295,21 +280,19 @@ nsock_event_id nsock_connect_ssl(nsock_pool nsp, nsock_iod nsiod,
|
||||
#endif /* HAVE_OPENSSL */
|
||||
}
|
||||
|
||||
/* Request ssl connection over already established connection.
|
||||
nsiod must be socket that is already connected to target
|
||||
using nsock_connect_tcp or nsock_connect_sctp.
|
||||
All parameters have the same meaning as in 'nsock_connect_ssl' */
|
||||
nsock_event_id nsock_reconnect_ssl(nsock_pool nsp, nsock_iod nsiod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, nsock_ssl_session ssl_session)
|
||||
{
|
||||
/* Request ssl connection over already established connection. nsiod must be
|
||||
* socket that is already connected to target using nsock_connect_tcp or
|
||||
* nsock_connect_sctp. All parameters have the same meaning as in
|
||||
* 'nsock_connect_ssl' */
|
||||
nsock_event_id nsock_reconnect_ssl(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, nsock_ssl_session ssl_session) {
|
||||
|
||||
#ifndef HAVE_OPENSSL
|
||||
fatal("nsock_reconnect_ssl called - but nsock was built w/o SSL support. QUITTING");
|
||||
return (nsock_event_id) 0; /* UNREACHED */
|
||||
#else
|
||||
msiod *nsi = (msiod *) nsiod;
|
||||
mspool *ms = (mspool *) nsp;
|
||||
msiod *nsi = (msiod *)nsiod;
|
||||
mspool *ms = (mspool *)nsp;
|
||||
msevent *nse;
|
||||
|
||||
if (!ms->sslctx)
|
||||
@@ -319,7 +302,7 @@ nsock_event_id nsock_reconnect_ssl(nsock_pool nsp, nsock_iod nsiod,
|
||||
assert(nse);
|
||||
|
||||
/* 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)
|
||||
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->status = NSE_STATUS_SUCCESS;
|
||||
nsp_add_event(ms, nse);
|
||||
|
||||
return nse->id;
|
||||
#endif /* HAVE_OPENSSL */
|
||||
}
|
||||
|
||||
/* Request a UDP "connection" to another system (by IP address). The in_addr is
|
||||
* normal network byte order, but the port number should be given in HOST BYTE
|
||||
* ORDER. Since this is UDP, no packets are actually sent. The destination IP
|
||||
* and port are just associated with the nsiod (an actual OS connect() call is
|
||||
* made). You can then use the normal nsock write calls on the socket. There
|
||||
* is no timeout since this call always calls your callback at the next
|
||||
* opportunity. The advantages to having a connected UDP socket (as opposed to
|
||||
* just specifying an address with sendto() are that we can now use a consistent
|
||||
* set of write/read calls for TCP/UDP, received packets from the non-partner
|
||||
* are automatically dropped by the OS, and the OS can provide asynchronous
|
||||
* errors (see Unix Network Programming pp224). ss should be a
|
||||
* sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate (just like what
|
||||
* you would pass to connect). sslen should be the sizeof the structure you are
|
||||
* passing in. */
|
||||
nsock_event_id nsock_connect_udp(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, void *userdata,
|
||||
struct sockaddr *saddr, size_t sslen, unsigned short port) {
|
||||
|
||||
/* 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) {
|
||||
msiod *nsi = (msiod *)nsiod;
|
||||
mspool *ms = (mspool *)nsp;
|
||||
msevent *nse;
|
||||
struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;
|
||||
|
||||
msiod *nsi = (msiod *) nsiod;
|
||||
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);
|
||||
|
||||
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 */
|
||||
gettimeofday(&nsock_tod, NULL);
|
||||
nse = msevent_new(ms, NSE_TYPE_CONNECT, nsi, -1, handler, userdata);
|
||||
assert(nse);
|
||||
|
||||
nse = msevent_new(ms, NSE_TYPE_CONNECT, nsi, -1, handler, userdata);
|
||||
assert(nse);
|
||||
|
||||
if (ms->tracelevel > 0)
|
||||
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_connect_internal(ms, nse, IPPROTO_UDP, ss, sslen, port);
|
||||
|
||||
nsp_add_event(ms, nse);
|
||||
|
||||
return nse->id;
|
||||
}
|
||||
|
||||
/* Returns that host/port/protocol information for the last
|
||||
communication (or comm. attempt) this nsi has been involved with.
|
||||
By "involved" with I mean interactions like establishing (or trying
|
||||
to) a connection or sending a UDP datagram through an unconnected
|
||||
nsock_iod. AF is the address family (AF_INET or AF_INET6), Protocl
|
||||
is IPPROTO_TCP or IPPROTO_UDP. Pass NULL for information you do
|
||||
not need. If ANY of the information you requested is not
|
||||
available, 0 will be returned and the unavailable sockets are
|
||||
zeroed. If protocol or af is requested but not available, it will
|
||||
be set to -1 (and 0 returned). The pointers you pass in must be
|
||||
NULL or point to allocated address space. The sockaddr members
|
||||
should actually be sockaddr_storage, sockaddr_in6, or sockaddr_in
|
||||
with the socklen of them set appropriately (eg
|
||||
sizeof(sockaddr_storage) if that is what you are passing). */
|
||||
int nsi_getlastcommunicationinfo(nsock_iod ms_iod, int *protocol,
|
||||
int *af, struct sockaddr *local,
|
||||
/* Returns that host/port/protocol information for the last communication (or
|
||||
* comm. attempt) this nsi has been involved with. By "involved" with I mean
|
||||
* interactions like establishing (or trying to) a connection or sending a UDP
|
||||
* datagram through an unconnected nsock_iod. AF is the address family (AF_INET
|
||||
* or AF_INET6), Protocl is IPPROTO_TCP or IPPROTO_UDP. Pass NULL for
|
||||
* information you do not need. If ANY of the information you requested is not
|
||||
* available, 0 will be returned and the unavailable sockets are zeroed. If
|
||||
* protocol or af is requested but not available, it will be set to -1 (and 0
|
||||
* returned). The pointers you pass in must be NULL or point to allocated
|
||||
* address space. The sockaddr members should actually be sockaddr_storage,
|
||||
* sockaddr_in6, or sockaddr_in with the socklen of them set appropriately (eg
|
||||
* sizeof(sockaddr_storage) if that is what you are passing). */
|
||||
int nsi_getlastcommunicationinfo(nsock_iod ms_iod, int *protocol, int *af, struct sockaddr *local,
|
||||
struct sockaddr *remote, size_t socklen) {
|
||||
msiod *nsi = (msiod *) ms_iod;
|
||||
msiod *nsi = (msiod *)ms_iod;
|
||||
int ret = 1;
|
||||
struct sockaddr_storage sock;
|
||||
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 (af) {
|
||||
*af = ((struct sockaddr_in *) &nsi->peer)->sin_family;
|
||||
*af = ((struct sockaddr_in *)&nsi->peer)->sin_family;
|
||||
}
|
||||
if (local) {
|
||||
if (nsi->sd >= 0) {
|
||||
res = getsockname(nsi->sd, (struct sockaddr *) &sock, &slen);
|
||||
res = getsockname(nsi->sd, (struct sockaddr *)&sock, &slen);
|
||||
if (res == -1) {
|
||||
memset(local, 0, socklen);
|
||||
ret = 0;
|
||||
@@ -430,10 +405,19 @@ int nsi_getlastcommunicationinfo(nsock_iod ms_iod, int *protocol,
|
||||
} else {
|
||||
if (local || remote || protocol || af)
|
||||
ret = 0;
|
||||
if (remote) memset(remote, 0, socklen);
|
||||
if (local) memset(local, 0, socklen);
|
||||
if (protocol) *protocol = -1;
|
||||
if (af) *af = -1;
|
||||
|
||||
if (remote)
|
||||
memset(remote, 0, socklen);
|
||||
|
||||
if (local)
|
||||
memset(local, 0, socklen);
|
||||
|
||||
if (protocol)
|
||||
*protocol = -1;
|
||||
|
||||
if (af)
|
||||
*af = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
107
nsock/src/nsock_engines.c
Normal file
107
nsock/src/nsock_engines.c
Normal 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;
|
||||
}
|
||||
|
||||
@@ -86,55 +86,106 @@ int nse_eof(nsock_event nse) {
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
msevent *nse = (msevent *) ms_event;
|
||||
msevent *nse = (msevent *)ms_event;
|
||||
return (nsock_iod) nse->iod;
|
||||
}
|
||||
|
||||
/* This next function returns the errno style error code -- which is only
|
||||
valid if the status is NSE_STATUS_ERROR */
|
||||
/* This next function returns the errno style error code -- which is only valid
|
||||
* if the status is NSE_STATUS_ERROR */
|
||||
int nse_errorcode(nsock_event nse) {
|
||||
msevent *me = (msevent *)nse;
|
||||
return me->errnum;
|
||||
}
|
||||
|
||||
/* Every event has an ID which will be unique throughout the program's execution unless you use (literally) billions of them */
|
||||
/* 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) {
|
||||
msevent *me = (msevent *)nse;
|
||||
return me->id;
|
||||
}
|
||||
|
||||
/* If you did a read request, and the result was STATUS_SUCCESS, this
|
||||
function provides the buffer that was read in as well as the number
|
||||
of chars read. The buffer should not be modified or free'd */
|
||||
/* If you did a read request, and the result was STATUS_SUCCESS, this function
|
||||
* provides the buffer that was read in as well as the number of chars read.
|
||||
* The buffer should not be modified or free'd */
|
||||
char *nse_readbuf(nsock_event nse, int *nbytes) {
|
||||
msevent *me = (msevent *)nse;
|
||||
|
||||
if (nbytes) {
|
||||
if (nbytes)
|
||||
*nbytes = FILESPACE_LENGTH(&(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
|
||||
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 */
|
||||
if ((msevent *)GH_LIST_ELEM_DATA(*first) == nse) {
|
||||
gh_list_elem *next;
|
||||
|
||||
next = GH_LIST_ELEM_NEXT(*first);
|
||||
if (next) {
|
||||
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 ) {
|
||||
mspool *nsp = (mspool *) ms_pool;
|
||||
enum nse_type type = get_event_id_type(id);
|
||||
gh_list *event_list = NULL;
|
||||
gh_list *event_list2 = NULL;
|
||||
mspool *nsp = (mspool *)ms_pool;
|
||||
enum nse_type type;
|
||||
gh_list *event_list = NULL, *event_list2 = NULL;
|
||||
gh_list_elem *current, *next;
|
||||
msevent *nse = NULL;
|
||||
|
||||
assert(nsp);
|
||||
|
||||
type = get_event_id_type(id);
|
||||
if (nsp->tracelevel > 0) {
|
||||
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 */
|
||||
switch(type) {
|
||||
case NSE_TYPE_CONNECT:
|
||||
event_list = &nsp->evl.connect_events;
|
||||
event_list = &nsp->connect_events;
|
||||
break;
|
||||
|
||||
case NSE_TYPE_READ:
|
||||
event_list = &nsp->evl.read_events;
|
||||
event_list = &nsp->read_events;
|
||||
break;
|
||||
|
||||
case NSE_TYPE_WRITE:
|
||||
event_list = &nsp->evl.write_events;
|
||||
event_list = &nsp->write_events;
|
||||
break;
|
||||
|
||||
case NSE_TYPE_TIMER:
|
||||
event_list = &nsp->evl.timer_events;
|
||||
event_list = &nsp->timer_events;
|
||||
break;
|
||||
|
||||
#if HAVE_PCAP
|
||||
case NSE_TYPE_PCAP_READ:
|
||||
event_list = &nsp->evl.read_events;
|
||||
event_list2 = &nsp->evl.pcap_read_events;
|
||||
event_list = &nsp->read_events;
|
||||
event_list2 = &nsp->pcap_read_events;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
fatal("Bogus event type in nsock_event_cancel"); break;
|
||||
}
|
||||
|
||||
/* Now we try to find the event in the list */
|
||||
for(current = GH_LIST_FIRST_ELEM(event_list); current != NULL;
|
||||
current = next) {
|
||||
for (current = GH_LIST_FIRST_ELEM(event_list); current != NULL; current = next) {
|
||||
next = GH_LIST_ELEM_NEXT(current);
|
||||
nse = (msevent *) GH_LIST_ELEM_DATA(current);
|
||||
nse = (msevent *)GH_LIST_ELEM_DATA(current);
|
||||
if (nse->id == id)
|
||||
break;
|
||||
}
|
||||
|
||||
if (current == NULL && event_list2){
|
||||
event_list = event_list2;
|
||||
for(current = GH_LIST_FIRST_ELEM(event_list); current != NULL;
|
||||
current = next) {
|
||||
for (current = GH_LIST_FIRST_ELEM(event_list); current != NULL; current = next) {
|
||||
next = GH_LIST_ELEM_NEXT(current);
|
||||
nse = (msevent *) GH_LIST_ELEM_DATA(current);
|
||||
nse = (msevent *)GH_LIST_ELEM_DATA(current);
|
||||
if (nse->id == id)
|
||||
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);
|
||||
}
|
||||
|
||||
/* An inernal function for cancelling an event when you already have a
|
||||
pointer to the msevent (use nsock_event_cancel if you just have an
|
||||
ID). The event_list passed in should correspond to the type of the
|
||||
event. For example, with NSE_TYPE_READ, you would pass in
|
||||
&nsp->evl.read_events;. elem is the list element in event_list which
|
||||
holds the event. Pass a nonzero for notify if you want the
|
||||
program owning the event to be notified that it has been cancelled */
|
||||
int msevent_cancel(mspool *nsp, msevent *nse, gh_list *event_list, gh_list_elem *elem,
|
||||
int notify) {
|
||||
|
||||
|
||||
/* An inernal function for cancelling an event when you already have a pointer
|
||||
* to the msevent (use nsock_event_cancel if you just have an ID). The
|
||||
* event_list passed in should correspond to the type of the event. For example,
|
||||
* with NSE_TYPE_READ, you would pass in &nsp->read_events;. elem is the list
|
||||
* element in event_list which holds the event. Pass a nonzero for notify if
|
||||
* you want the program owning the event to be notified that it has been
|
||||
* cancelled */
|
||||
int msevent_cancel(mspool *nsp, msevent *nse, gh_list *event_list, gh_list_elem *elem, int notify) {
|
||||
if (nse->event_done) {
|
||||
/* This event has already been marked for death somewhere else -- it
|
||||
will be gone soon (and if we try to kill it now all hell will break
|
||||
loose due to reentrancy */
|
||||
/* This event has already been marked for death somewhere else -- it will be
|
||||
* gone soon (and if we try to kill it now all hell will break loose due to
|
||||
* reentrancy. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Now that we found the event ... we go through the motions of cleanly
|
||||
cancelling it */
|
||||
if (nsp->tracelevel > 0)
|
||||
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) {
|
||||
case NSE_TYPE_CONNECT:
|
||||
case NSE_TYPE_CONNECT_SSL:
|
||||
handle_connect_result(nsp, nse, NSE_STATUS_CANCELLED);
|
||||
break;
|
||||
|
||||
case NSE_TYPE_READ:
|
||||
handle_read_result(nsp, nse, NSE_STATUS_CANCELLED);
|
||||
break;
|
||||
|
||||
case NSE_TYPE_WRITE:
|
||||
handle_write_result(nsp, nse, NSE_STATUS_CANCELLED);
|
||||
break;
|
||||
|
||||
case NSE_TYPE_TIMER:
|
||||
handle_timer_result(nsp, nse, NSE_STATUS_CANCELLED);
|
||||
break;
|
||||
|
||||
#if HAVE_PCAP
|
||||
case NSE_TYPE_PCAP_READ:
|
||||
handle_pcap_read_result(nsp, nse, NSE_STATUS_CANCELLED);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
assert(nse->event_done);
|
||||
update_first_events(nse);
|
||||
gh_list_remove_elem(event_list, elem);
|
||||
|
||||
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 PCAP_BSD_SELECT_HACK
|
||||
if(nse->type==NSE_TYPE_PCAP_READ){
|
||||
if (nse->type == NSE_TYPE_PCAP_READ) {
|
||||
if (nsp->tracelevel > 8)
|
||||
nsock_trace(nsp, "PCAP NSE #%lu: CANCELL TEST el.pcap=%p el.read=%p el.curr=%p sd=%i",
|
||||
nse->id, &nsp->evl.pcap_read_events, &nsp->evl.read_events, event_list,((mspcap *) nse->iod->pcap)->pcap_desc );
|
||||
/* If event occured, and we're in BSD_HACK mode, than this event was added
|
||||
* 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 */
|
||||
nsock_trace(nsp, "PCAP NSE #%lu: CANCEL TEST pcap=%p read=%p curr=%p sd=%i",
|
||||
nse->id, &nsp->pcap_read_events, &nsp->read_events,
|
||||
event_list,((mspcap *)nse->iod->pcap)->pcap_desc);
|
||||
|
||||
if(((mspcap *) nse->iod->pcap)->pcap_desc >= 0 &&
|
||||
event_list == &nsp->evl.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->evl.pcap_read_events, nse);
|
||||
/* If event occured, and we're in BSD_HACK mode, than this event was added to
|
||||
* two queues. read_event and pcap_read_event Of course we should
|
||||
* destroy it only once. I assume we're now in read_event, so just unlink
|
||||
* this event from pcap_read_event */
|
||||
if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0 && event_list == &nsp->read_events) {
|
||||
/* event is done, list is read_events and we're in BSD_HACK mode. So unlink
|
||||
* event from pcap_read_events */
|
||||
gh_list_remove(&nsp->pcap_read_events, nse);
|
||||
if (nsp->tracelevel > 8)
|
||||
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.
|
||||
* So unlink event from pcap_read_events */
|
||||
gh_list_remove(&nsp->evl.read_events, nse);
|
||||
* So unlink event from read_events */
|
||||
gh_list_remove(&nsp->read_events, nse);
|
||||
|
||||
if (nsp->tracelevel > 8)
|
||||
nsock_trace(nsp, "PCAP NSE #%lu: Removing event from READ_EVENTS", nse->id);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
msevent_dispatch_and_delete(nsp, nse, notify);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Adjust various statistics, dispatches the event handler (if notify is
|
||||
nonzero) and then deletes the event. This function does NOT delete
|
||||
the event from any lists it might be on (eg nsp->evl.read_list etc.)
|
||||
nse->event_done MUST be true when you call this */
|
||||
* nonzero) and then deletes the event. This function does NOT delete the event
|
||||
* from any lists it might be on (eg nsp->read_list etc.) nse->event_done
|
||||
* MUST be true when you call this */
|
||||
void msevent_dispatch_and_delete(mspool *nsp, msevent *nse, int notify) {
|
||||
assert(nsp);
|
||||
assert(nse);
|
||||
|
||||
assert(nse->event_done);
|
||||
|
||||
nsp->evl.events_pending--;
|
||||
assert(nsp->evl.events_pending >= 0);
|
||||
|
||||
nsp->events_pending--;
|
||||
assert(nsp->events_pending >= 0);
|
||||
|
||||
if (nse->iod) {
|
||||
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);
|
||||
}
|
||||
|
||||
/* FIXME: We should be updating stats here ... */
|
||||
/* FIXME: We should be updating stats here ... */
|
||||
|
||||
/* Now we clobber the event ... */
|
||||
msevent_delete(nsp, nse);
|
||||
}
|
||||
|
||||
/* OK -- the idea is that we want the type included in the rightmost
|
||||
two bits and the serial number in the leftmost 30 or 62. But we
|
||||
also want to insure a correct wrap-around in the case of an obscene
|
||||
number of event. One definition of a "correct" wraparound is that
|
||||
it goes from the highest number back to one (not zero) because we
|
||||
don't want event numbers to ever be zero. */
|
||||
/* OK -- the idea is that we want the type included in the rightmost two bits
|
||||
* and the serial number in the leftmost 30 or 62. But we also want to insure a
|
||||
* correct wrap-around in the case of an obscene number of event. One
|
||||
* definition of a "correct" wraparound is that it goes from the highest number
|
||||
* back to one (not zero) because we don't want event numbers to ever be zero.
|
||||
* */
|
||||
nsock_event_id get_new_event_id(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 max_serial_allowed;
|
||||
int shiftbits;
|
||||
|
||||
assert(type < NSE_TYPE_MAX);
|
||||
|
||||
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 */
|
||||
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,
|
||||
unless it returns NULL (failure). NULL can be passed in for the
|
||||
msiod and the userdata if not available */
|
||||
msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod,
|
||||
int timeout_msecs, nsock_ev_handler handler,
|
||||
void *userdata) {
|
||||
|
||||
* unless it returns NULL (failure). NULL can be passed in for the msiod and
|
||||
* the userdata if not available */
|
||||
msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod, int timeout_msecs,
|
||||
nsock_ev_handler handler, void *userdata) {
|
||||
msevent *nse;
|
||||
|
||||
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 ... */
|
||||
nse = (msevent *) gh_list_pop(&nsp->evl.free_events);
|
||||
if (!nse) nse = (msevent *) safe_malloc(sizeof(msevent));
|
||||
memset(nse, 0, sizeof(*nse));
|
||||
nse = (msevent *)gh_list_pop(&nsp->free_events);
|
||||
if (!nse)
|
||||
nse = (msevent *)safe_malloc(sizeof(msevent));
|
||||
memset(nse, 0, sizeof(msevent));
|
||||
|
||||
nse->id = get_new_event_id(nsp, type);
|
||||
nse->type = type;
|
||||
nse->status = NSE_STATUS_NONE;
|
||||
#if HAVE_OPENSSL
|
||||
nse->sslinfo.ssl_desire = SSL_ERROR_NONE;
|
||||
#endif
|
||||
if (type == NSE_TYPE_READ || type == NSE_TYPE_WRITE) {
|
||||
if (type == NSE_TYPE_READ || type == NSE_TYPE_WRITE)
|
||||
filespace_init(&(nse->iobuf), 1024);
|
||||
}
|
||||
#if HAVE_PCAP
|
||||
|
||||
if (type == NSE_TYPE_PCAP_READ) {
|
||||
mspcap *mp;
|
||||
int sz;
|
||||
|
||||
assert(msiod != NULL);
|
||||
mspcap *mp = (mspcap *) msiod->pcap;
|
||||
mp = (mspcap *)msiod->pcap;
|
||||
assert(mp);
|
||||
int sz = mp->snaplen+1 + sizeof(nsock_pcap);
|
||||
|
||||
sz = mp->snaplen+1 + sizeof(nsock_pcap);
|
||||
filespace_init(&(nse->iobuf), sz);
|
||||
}
|
||||
#endif
|
||||
@@ -375,41 +436,32 @@ msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod,
|
||||
assert(timeout_msecs >= 0);
|
||||
TIMEVAL_MSEC_ADD(nse->timeout, nsock_tod, timeout_msecs);
|
||||
}
|
||||
|
||||
nse->iod = msiod;
|
||||
nse->handler = handler;
|
||||
nse->userdata = userdata;
|
||||
nse->time_created = nsock_tod;
|
||||
|
||||
if (nsp->tracelevel > 3) {
|
||||
if(nse->iod == NULL) {
|
||||
nsock_trace(nsp, "msevent_new (IOD #NULL) (EID #%li)",
|
||||
nse->id);
|
||||
} else {
|
||||
nsock_trace(nsp, "msevent_new (IOD #%li) (EID #%li)",
|
||||
nse->iod->id,
|
||||
nse->id);
|
||||
if (nse->iod == NULL)
|
||||
nsock_trace(nsp, "msevent_new (IOD #NULL) (EID #%li)", nse->id);
|
||||
else
|
||||
nsock_trace(nsp, "msevent_new (IOD #%li) (EID #%li)", nse->iod->id, nse->id);
|
||||
}
|
||||
}
|
||||
|
||||
return nse;
|
||||
}
|
||||
|
||||
/* Free an msevent which was allocated with msevent_new, including all
|
||||
internal resources. Note -- we assume that
|
||||
nse->iod->events_pending (if it exists) has ALREADY been
|
||||
decremented (done during msevent_dispatch_and_delete) -- so
|
||||
remember to do this if you call msevent_delete() directly */
|
||||
/* Free an msevent which was allocated with msevent_new, including all internal
|
||||
* resources. Note -- we assume that nse->iod->events_pending (if it exists)
|
||||
* has ALREADY been decremented (done during msevent_dispatch_and_delete) -- so
|
||||
* remember to do this if you call msevent_delete() directly */
|
||||
void msevent_delete(mspool *nsp, msevent *nse) {
|
||||
|
||||
if (nsp->tracelevel > 3) {
|
||||
if(nse->iod == NULL) {
|
||||
nsock_trace(nsp, "msevent_delete (IOD #NULL) (EID #%li)",
|
||||
nse->id);
|
||||
} else {
|
||||
nsock_trace(nsp, "msevent_delete (IOD #%li) (EID #%li)",
|
||||
nse->iod->id,
|
||||
nse->id);
|
||||
}
|
||||
if (nse->iod == NULL)
|
||||
nsock_trace(nsp, "msevent_delete (IOD #NULL) (EID #%li)", nse->id);
|
||||
else
|
||||
nsock_trace(nsp, "msevent_delete (IOD #%li) (EID #%li)", nse->iod->id, nse->id);
|
||||
}
|
||||
|
||||
/* First free the IOBuf inside it if neccessary */
|
||||
@@ -425,13 +477,12 @@ void msevent_delete(mspool *nsp, msevent *nse) {
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
string name that you can use for printing, etc. */
|
||||
/* Takes an nse_type (as returned by nse_type() and returns a static string name
|
||||
* that you can use for printing, etc. */
|
||||
const char *nse_type2str(enum nse_type type) {
|
||||
switch(type) {
|
||||
case NSE_TYPE_CONNECT: return "CONNECT";
|
||||
@@ -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
|
||||
string name that you can use for printing, etc. */
|
||||
/* Takes an nse_status (as returned by nse_status() and returns a static string
|
||||
* name that you can use for printing, etc. */
|
||||
const char *nse_status2str(enum nse_status status) {
|
||||
switch(status) {
|
||||
case NSE_STATUS_NONE: return "NONE";
|
||||
@@ -461,9 +512,3 @@ const char *nse_status2str(enum nse_status status) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* nsock_internal.h -- PRIVATE interface definitions for the guts of the *
|
||||
* nsock paralle socket event library. Applications calling this library *
|
||||
@@ -103,290 +102,353 @@
|
||||
#define IPPROTO_SCTP 132
|
||||
#endif
|
||||
|
||||
/********* STRUCTURES **************/
|
||||
|
||||
/* This is geared to handling state for select calls, perhaps at
|
||||
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 */
|
||||
/* ------------------- CONSTANTS ------------------- */
|
||||
|
||||
/* 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 results_left; /* The number of descriptors contained in the sets that
|
||||
we have not yet dealt with. */
|
||||
enum nsock_read_types {
|
||||
NSOCK_READLINES,
|
||||
NSOCK_READBYTES,
|
||||
NSOCK_READ
|
||||
};
|
||||
|
||||
struct event_lists {
|
||||
/* We keep the events seperate because we want to handle them in the
|
||||
order: connect => read => write => timer for several reasons:
|
||||
1) Makes sure we have gone through all the net i/o events before
|
||||
a timer expires (would be a shame to timeout after the data was
|
||||
available but before we delivered the events
|
||||
2) The connect() results often lead to a read or write that can be
|
||||
processed in the same cycle. In the same way, read() often
|
||||
leads to write().
|
||||
*/
|
||||
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 */
|
||||
enum msiod_state {
|
||||
NSIOD_STATE_DELETED,
|
||||
NSIOD_STATE_INITIAL,
|
||||
|
||||
/* 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 {
|
||||
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 sockaddr_storage dest;
|
||||
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
|
||||
fields directly */
|
||||
/* Remember that callers of this library should NOT be accessing these
|
||||
* fields directly */
|
||||
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 */
|
||||
struct event_lists evl; /* Lists of pending events we are waiting on */
|
||||
/* Every msp has a unique (accross the program execution) id */
|
||||
unsigned long id;
|
||||
|
||||
void *userdata; /* User Data, if it has been set. Otherwise NULL */
|
||||
gh_list free_iods; /* msiod structures that have been freed for reuse */
|
||||
gh_list active_iods; /* msiod structures that have been allocated */
|
||||
unsigned long next_event_serial; /* serial # of next event (used to create
|
||||
next nsock_event_id */
|
||||
unsigned long next_iod_serial; /* Serial # of next iod to be created */
|
||||
int errnum; /* If nsock_loop() returns NSOCK_LOOP_ERROR, this is where we
|
||||
describe the error (errnum fashion) */
|
||||
int tracelevel; /* Trace/debug level - set by nsp_settrace. If positive,
|
||||
trace logs are printted to tracefile. */
|
||||
/* User data, NULL if unset */
|
||||
void *userdata;
|
||||
|
||||
/* IO Engine vtable */
|
||||
struct io_engine *engine;
|
||||
/* IO Engine internal data */
|
||||
void *engine_data;
|
||||
|
||||
/* Active network events */
|
||||
gh_list 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;
|
||||
int broadcast; /* If true, new sockets will have SO_BROADCAST set */
|
||||
/* This time is subtracted from the current time for trace reports */
|
||||
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
|
||||
NSOCK_LOOP_QUIT. */
|
||||
* NSOCK_LOOP_QUIT. */
|
||||
int quit;
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
SSL_CTX *sslctx; /* The SSL Context (options and such) */
|
||||
/* The SSL Context (options and such) */
|
||||
SSL_CTX *sslctx;
|
||||
#endif
|
||||
} 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,
|
||||
NSIOD_STATE_UNKNOWN /* sd was provided to us in nsi_new2 */,
|
||||
NSIOD_STATE_CONNECTED_TCP, NSIOD_STATE_CONNECTED_UDP };
|
||||
/* Pending events */
|
||||
gh_list_elem *first_connect;
|
||||
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 writesd_count;
|
||||
#if HAVE_PCAP
|
||||
int readpcapsd_count;
|
||||
mspool *nsp; /* The mspool used to create the iod (used for deletion) */
|
||||
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 */
|
||||
#endif
|
||||
|
||||
/* 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, peerlen;
|
||||
int lastproto; /* -1 if none yet, otherwise IPPROTO_TCP, etc. */
|
||||
gh_list_elem *entry_in_nsp_active_iods; /* 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 */
|
||||
int watched_events;
|
||||
|
||||
/* The mspool used to create the iod (used for deletion) */
|
||||
mspool *nsp;
|
||||
|
||||
enum msiod_state state;
|
||||
|
||||
/* The host and port we are connected to using sd (saves a call to getpeername) */
|
||||
struct sockaddr_storage peer;
|
||||
/* The host and port to bind to with sd */
|
||||
struct sockaddr_storage local;
|
||||
|
||||
/* The length of peer/local actually used (sizeof(sockaddr_in) or
|
||||
* sizeof(sockaddr_in6), 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. */
|
||||
char *hostname;
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
SSL *ssl; /* An SSL connection (or NULL if none) */
|
||||
SSL_SESSION *ssl_session; /* SSL SESSION ID (or NULL if none) */
|
||||
/* An SSL connection (or NULL if none) */
|
||||
SSL *ssl;
|
||||
/* SSL SESSION ID (or NULL if none) */
|
||||
SSL_SESSION *ssl_session;
|
||||
#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
|
||||
unsigned long id; /* Every iod has an id which is always unique for the
|
||||
same nspool (unless you create billions of them) */
|
||||
/* Every iod has an id which is always unique for the same nspool (unless you
|
||||
* create billions of them) */
|
||||
unsigned long id;
|
||||
|
||||
/* No. of bytes read from the sd*/
|
||||
unsigned long read_count;
|
||||
/* No. of bytes written to the sd */
|
||||
unsigned long write_count;
|
||||
|
||||
unsigned long read_count; /* No. of bytes read from the sd*/
|
||||
unsigned long write_count; /* No. of bytes written to the sd */
|
||||
void *userdata;
|
||||
|
||||
/* IP options to set on socket before connect() */
|
||||
void *ipopts;
|
||||
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_status status;
|
||||
|
||||
struct filespace iobuf; /* for write events, this is the data to be written,
|
||||
for read events, this is what we will read into */
|
||||
/* For write events, this is the data to be written, for read events, this is
|
||||
* what we will read into */
|
||||
struct filespace iobuf;
|
||||
|
||||
/* The timeout of the event -- absolute time
|
||||
* except that tv_sec == 0 means no timeout */
|
||||
struct timeval timeout;
|
||||
|
||||
/* Info pertaining to READ requests */
|
||||
struct readinfo readinfo;
|
||||
/* Info pertaining to WRITE requests */
|
||||
struct writeinfo writeinfo;
|
||||
|
||||
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
|
||||
struct sslinfo sslinfo;
|
||||
#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;
|
||||
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;
|
||||
int event_done; /* If this event is all filled out and ready for
|
||||
immediate delivery, event_done is nonzero. Used
|
||||
when event is finished at unexpected time and we
|
||||
want to dispatch it later to avoid duplicating
|
||||
stat update code and all that other crap */
|
||||
|
||||
/* If this event is all filled out and ready for immediate delivery,
|
||||
* event_done is nonzero. Used when event is finished at unexpected time and
|
||||
* we want to dispatch it later to avoid duplicating stat update code and all
|
||||
* that other crap */
|
||||
int event_done;
|
||||
|
||||
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 */
|
||||
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 */
|
||||
enum nse_type get_event_id_type(nsock_event_id event_id);
|
||||
|
||||
/* Create a new event structure -- must be deleted later with msevent_delete,
|
||||
unless it returns NULL (failure). NULL can be passed in for the
|
||||
msiod and the userdata if not available. */
|
||||
msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod,
|
||||
int timeout_msecs, nsock_ev_handler handler,
|
||||
void *userdata);
|
||||
* unless it returns NULL (failure). NULL can be passed in for the msiod and
|
||||
* the userdata if not available. */
|
||||
msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod, int timeout_msecs, nsock_ev_handler handler, void *userdata);
|
||||
|
||||
/* An inernal function for cancelling an event when you already have a
|
||||
pointer to the msevent (use nsock_event_cancel if you just have an
|
||||
ID). The event_list passed in should correspond to the type of the
|
||||
event. For example, with NSE_TYPE_READ, you would pass in
|
||||
&nsp->evl.read_events;. elem is the list element in event_list
|
||||
which holds the event. Pass a nonzero for notify if you want the
|
||||
program owning the event to be notified that it has been cancelled */
|
||||
int msevent_cancel(mspool *nsp, msevent *nse, gh_list *event_list,
|
||||
gh_list_elem *elem, int notify);
|
||||
/* An internal function for cancelling an event when you already have a pointer
|
||||
* to the msevent (use nsock_event_cancel if you just have an ID). The
|
||||
* event_list passed in should correspond to the type of the event. For
|
||||
* example, with NSE_TYPE_READ, you would pass in &iod->read_events;. elem
|
||||
* is the list element in event_list which holds the event. Pass a nonzero for
|
||||
* notify if you want the program owning the event to be notified that it has
|
||||
* been cancelled */
|
||||
int msevent_cancel(mspool *nsp, msevent *nse, gh_list *event_list, gh_list_elem *elem, int notify);
|
||||
|
||||
/* Adjust various statistics, dispatches the event handler (if notify is
|
||||
nonzero) and then deletes the event. This function does NOT delete
|
||||
the event from any lists it might be on (eg nsp->evl.read_list etc.)
|
||||
nse->event_done MUST be true when you call this */
|
||||
* nonzero) and then deletes the event. This function does NOT delete the event
|
||||
* from any lists it might be on (eg nsp->read_list etc.) nse->event_done
|
||||
* MUST be true when you call this */
|
||||
void msevent_dispatch_and_delete(mspool *nsp, msevent *nse, int notify);
|
||||
|
||||
/* Free an msevent which was allocated with msevent_new, including all
|
||||
internal resources. Note -- we assume that
|
||||
nse->iod->events_pending (if it exists) has ALREADY been
|
||||
decremented (done during msevent_dispatch_and_delete) -- so
|
||||
remember to do this if you call msevent_delete() directly */
|
||||
/* Free an msevent which was allocated with msevent_new, including all internal
|
||||
* resources. Note -- we assume that nse->iod->events_pending (if it exists)
|
||||
* has ALREADY been decremented (done during msevent_dispatch_and_delete) -- so
|
||||
* remember to do this if you call msevent_delete() directly */
|
||||
void msevent_delete(mspool *nsp, msevent *nse);
|
||||
|
||||
/* Adds an event to the appropriate nsp event list, handles housekeeping
|
||||
such as adjusting the descriptor select/poll lists, registering the
|
||||
timeout value, etc. */
|
||||
/* Add an event to the appropriate nsp event list, handles housekeeping such as
|
||||
* adjusting the descriptor select/poll lists, registering the timeout value,
|
||||
* etc. */
|
||||
void nsp_add_event(mspool *nsp, msevent *nse);
|
||||
|
||||
void nsock_connect_internal(mspool *ms, msevent *nse, int proto,
|
||||
struct sockaddr_storage *ss, size_t sslen,
|
||||
unsigned short port);
|
||||
void nsock_connect_internal(mspool *ms, msevent *nse, int proto, struct sockaddr_storage *ss, size_t sslen, unsigned short port);
|
||||
|
||||
/* Comments on using the following handle_*_result functions are available
|
||||
in nsock_core.c */
|
||||
/* handle_connect_results assumes that select or poll have already
|
||||
shown the descriptor to be active */
|
||||
void handle_connect_result(mspool *ms, msevent *nse,
|
||||
enum nse_status status);
|
||||
/* Comments on using the following handle_*_result functions are available in nsock_core.c */
|
||||
|
||||
void handle_read_result(mspool *ms, msevent *nse,
|
||||
enum nse_status status);
|
||||
/* 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_write_result(mspool *ms, msevent *nse,
|
||||
enum nse_status status);
|
||||
void handle_read_result(mspool *ms, msevent *nse, enum nse_status status);
|
||||
|
||||
void handle_timer_result(mspool *ms, msevent *nse,
|
||||
enum nse_status status);
|
||||
void handle_write_result(mspool *ms, msevent *nse, enum nse_status status);
|
||||
|
||||
void handle_timer_result(mspool *ms, msevent *nse, enum nse_status status);
|
||||
|
||||
#if HAVE_PCAP
|
||||
void handle_pcap_read_result(mspool *ms, msevent *nse,
|
||||
enum nse_status status);
|
||||
void handle_pcap_read_result(mspool *ms, msevent *nse, enum nse_status status);
|
||||
#endif
|
||||
|
||||
void nsock_trace(mspool *ms, char *fmt, ...)
|
||||
__attribute__ ((format (printf, 2, 3)));
|
||||
void nsock_trace(mspool *ms, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
/* An event has been completed and the handler is about to be called. This function
|
||||
writes out tracing data about the event if neccessary */
|
||||
/* An event has been completed and the handler is about to be called. This
|
||||
* function writes out tracing data about the event if necessary */
|
||||
void nsock_trace_handler_callback(mspool *ms, msevent *nse);
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
/* sets the ssl session of an nsock_iod, increments usage count. The
|
||||
session should not have been set yet (as no freeing is done) */
|
||||
/* Sets the ssl session of an nsock_iod, increments usage count. The session
|
||||
* should not have been set yet (as no freeing is done) */
|
||||
void nsi_set_ssl_session(msiod *iod, SSL_SESSION *sessid);
|
||||
#endif
|
||||
|
||||
#endif /* NSOCK_INTERNAL_H */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* nsock_iod.c -- This contains the functions relating to nsock_iod (and *
|
||||
* its nsock internal manifistation -- nsockiod. This is is similar to a *
|
||||
@@ -69,30 +68,29 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* nsock_iod is like a "file descriptor" for the nsock library. You
|
||||
use it to request events. And here is how you create an nsock_iod.
|
||||
nsi_new returns NULL if the iod cannot be allocated. Pass NULL as
|
||||
userdata if you don't want to immediately associate any user data
|
||||
with the iod. */
|
||||
/* nsock_iod is like a "file descriptor" for the nsock library. You use it to
|
||||
* request events. And here is how you create an nsock_iod. nsi_new returns
|
||||
* NULL if the iod cannot be allocated. Pass NULL as userdata if you don't want
|
||||
* to immediately associate any user data with the iod. */
|
||||
nsock_iod nsi_new(nsock_pool nsockp, void *userdata) {
|
||||
return nsi_new2(nsockp, -1, userdata);
|
||||
}
|
||||
|
||||
/* This version allows you to associate an existing sd with the msi
|
||||
so that you can read/write it using the nsock infrastructure. For example,
|
||||
you may want to watch for data from STDIN_FILENO at the same time as you
|
||||
read/write various sockets. STDIN_FILENO is a special case, however. Any
|
||||
other sd is dup()ed, so you may close or otherwise manipulate your copy.
|
||||
The duped copy will be destroyed when the nsi is destroyed
|
||||
*/
|
||||
/* This version allows you to associate an existing sd with the msi so that you
|
||||
* can read/write it using the nsock infrastructure. For example, you may want
|
||||
* to watch for data from STDIN_FILENO at the same time as you read/write
|
||||
* various sockets. STDIN_FILENO is a special case, however. Any other sd is
|
||||
* dup()ed, so you may close or otherwise manipulate your copy. The duped copy
|
||||
* will be destroyed when the nsi is destroyed. */
|
||||
nsock_iod nsi_new2(nsock_pool nsockp, int sd, void *userdata) {
|
||||
mspool *nsp = (mspool *) nsockp;
|
||||
mspool *nsp = (mspool *)nsockp;
|
||||
msiod *nsi;
|
||||
|
||||
nsi = (msiod *) gh_list_pop(&nsp->free_iods);
|
||||
if (!nsi) nsi = (msiod * ) safe_malloc(sizeof(msiod));
|
||||
|
||||
nsi = (msiod *)gh_list_pop(&nsp->free_iods);
|
||||
if (!nsi) {
|
||||
nsi = (msiod *)safe_malloc(sizeof(msiod));
|
||||
memset(nsi, 0, sizeof(*nsi));
|
||||
}
|
||||
|
||||
if (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->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->nsp = (mspool *) nsockp;
|
||||
nsi->events_pending = 0;
|
||||
nsi->readsd_count = 0;
|
||||
nsi->writesd_count = 0;
|
||||
nsi->readpcapsd_count = 0;
|
||||
nsi->read_count=0;
|
||||
nsi->write_count=0;
|
||||
nsi->nsp = (mspool *)nsockp;
|
||||
|
||||
nsi->read_count = 0;
|
||||
nsi->write_count = 0;
|
||||
|
||||
nsi->hostname = NULL;
|
||||
|
||||
@@ -131,66 +135,73 @@ nsock_iod nsi_new2(nsock_pool nsockp, int sd, void *userdata) {
|
||||
#endif
|
||||
|
||||
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
|
||||
if it is deleted */
|
||||
nsi->entry_in_nsp_active_iods = gh_list_append(&nsi->nsp->active_iods, nsi);
|
||||
|
||||
return (nsock_iod) nsi;
|
||||
/* The nsp keeps track of active msiods so it can delete them if it is deleted */
|
||||
nsi->entry_in_nsp_active_iods = gh_list_append(&nsp->active_iods, nsi);
|
||||
return (nsock_iod)nsi;
|
||||
}
|
||||
|
||||
|
||||
/* Defined in nsock_core.c. */
|
||||
int socket_count_zero(msiod *iod, mspool *ms);
|
||||
|
||||
/* If msiod_new returned success, you must free the iod when you are
|
||||
done with it to conserve memory (and in some cases, sockets).
|
||||
After this call, nsockiod may no longer be used -- you need to
|
||||
create a new one with nsi_new(). pending_response tells what to do
|
||||
with any events that are pending on this nsock_iod. This can be
|
||||
NSOCK_PENDING_NOTIFY (send a KILL notification to each event),
|
||||
NSOCK_PENDING_SILENT (do not send notification to the killed
|
||||
events), or NSOCK_PENDING_ERROR (print an error message and quiit
|
||||
the program) */
|
||||
/* If msiod_new returned success, you must free the iod when you are done with
|
||||
* it to conserve memory (and in some cases, sockets). After this call,
|
||||
* nsockiod may no longer be used -- you need to create a new one with
|
||||
* nsi_new(). pending_response tells what to do with any events that are
|
||||
* pending on this nsock_iod. This can be NSOCK_PENDING_NOTIFY (send a KILL
|
||||
* notification to each event), NSOCK_PENDING_SILENT (do not send notification
|
||||
* to the killed events), or NSOCK_PENDING_ERROR (print an error message and
|
||||
* quiit the program) */
|
||||
void nsi_delete(nsock_iod nsockiod, int pending_response) {
|
||||
msiod *nsi = (msiod *) nsockiod;
|
||||
gh_list *elist_ar[3];
|
||||
int elist;
|
||||
gh_list_elem *currev_elem, *next_elem;
|
||||
msevent *currev;
|
||||
msiod *nsi = (msiod *)nsockiod;
|
||||
gh_list_elem *evlist_ar[3];
|
||||
gh_list *corresp_list[3];
|
||||
int i;
|
||||
gh_list_elem *current, *next;
|
||||
|
||||
assert(nsi);
|
||||
|
||||
|
||||
if (nsi->nsp->tracelevel > 1)
|
||||
nsock_trace(nsi->nsp, "nsi_delete() (IOD #%lu)", nsi->id);
|
||||
|
||||
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) {
|
||||
/* shit -- they killed the msiod while an event was still pending
|
||||
on it. Maybe I should store the pending events in the msiod.
|
||||
On the other hand, this should be a pretty rare occurance and
|
||||
so I'll save space and hassle by just locating the events here
|
||||
by searching through the active events list */
|
||||
/* shit -- they killed the msiod while an event was still pending on it.
|
||||
* Maybe I should store the pending events in the msiod. On the other hand,
|
||||
* this should be a pretty rare occurance and so I'll save space and hassle
|
||||
* by just locating the events here by searching through the active events
|
||||
* list */
|
||||
if (pending_response == NSOCK_PENDING_ERROR)
|
||||
fatal("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);
|
||||
elist_ar[0] = &(nsi->nsp->evl.read_events);
|
||||
elist_ar[1] = &(nsi->nsp->evl.write_events);
|
||||
elist_ar[2] = &(nsi->nsp->evl.connect_events);
|
||||
for(elist = 0; elist < 3 && nsi->events_pending > 0; elist++) {
|
||||
currev_elem = GH_LIST_FIRST_ELEM(elist_ar[elist]);
|
||||
while(currev_elem) {
|
||||
currev = (msevent *) GH_LIST_ELEM_DATA(currev_elem);
|
||||
next_elem = GH_LIST_ELEM_NEXT(currev_elem);
|
||||
if (currev->iod == nsi) {
|
||||
/* OK - we found an event pending on this IOD. Kill it. */
|
||||
/* printf("Found an outstanding event (out of %d), removing\n", nsi->events_pending); */
|
||||
msevent_cancel(nsi->nsp, currev, elist_ar[elist], currev_elem, pending_response == NSOCK_PENDING_NOTIFY);
|
||||
}
|
||||
if (nsi->events_pending == 0)
|
||||
|
||||
assert(pending_response == NSOCK_PENDING_NOTIFY || pending_response == NSOCK_PENDING_SILENT);
|
||||
|
||||
evlist_ar[0] = nsi->first_connect;
|
||||
evlist_ar[1] = nsi->first_read;
|
||||
evlist_ar[2] = nsi->first_write;
|
||||
|
||||
corresp_list[0] = &nsi->nsp->connect_events;
|
||||
corresp_list[1] = &nsi->nsp->read_events;
|
||||
corresp_list[2] = &nsi->nsp->write_events;
|
||||
|
||||
for (i = 0; i < 3 && nsi->events_pending > 0; i++) {
|
||||
for (current = evlist_ar[i]; current != NULL; current = next) {
|
||||
next = GH_LIST_ELEM_NEXT(current);
|
||||
msevent *nse = (msevent *)GH_LIST_ELEM_DATA(current);
|
||||
|
||||
/* we're done with this list of events for the current IOD */
|
||||
if (nse->iod != nsi)
|
||||
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);
|
||||
|
||||
/* 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)
|
||||
socket_count_zero(nsi, nsi->nsp);
|
||||
|
||||
@@ -209,22 +220,24 @@ void nsi_delete(nsock_iod nsockiod, int pending_response) {
|
||||
/* Close any SSL resources */
|
||||
if (nsi->ssl) {
|
||||
/* 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);
|
||||
nsi->ssl_session = NULL; */
|
||||
nsi->ssl_session = NULL;
|
||||
#endif
|
||||
|
||||
if (SSL_shutdown(nsi->ssl) == -1) {
|
||||
|
||||
if (nsi->nsp->tracelevel > 1)
|
||||
nsock_trace(nsi->nsp,
|
||||
"nsi_delete(): SSL shutdown failed (%s) on NSI %li",
|
||||
ERR_reason_error_string(SSL_get_error(nsi->ssl, -1)),
|
||||
nsi->id);
|
||||
nsock_trace(nsi->nsp, "nsi_delete(): SSL shutdown failed (%s) on NSI %li",
|
||||
ERR_reason_error_string(SSL_get_error(nsi->ssl, -1)), nsi->id);
|
||||
}
|
||||
|
||||
/* I don't really care if the SSL_shutdown() succeeded politely. I could
|
||||
make the SD blocking temporarily for this, but I'm hoping it will
|
||||
succeed 95% of the time because we can usually write to a socket. */
|
||||
* make the SD blocking temporarily for this, but I'm hoping it will succeed
|
||||
* 95% of the time because we can usually write to a socket. */
|
||||
SSL_free(nsi->ssl);
|
||||
nsi->ssl = NULL;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -240,17 +253,18 @@ void nsi_delete(nsock_iod nsockiod, int pending_response) {
|
||||
free(nsi->ipopts);
|
||||
|
||||
#if HAVE_PCAP
|
||||
if(nsi->pcap){
|
||||
mspcap *mp = (mspcap *) nsi->pcap;
|
||||
if(mp->pt){
|
||||
if (nsi->pcap){
|
||||
mspcap *mp = (mspcap *)nsi->pcap;
|
||||
|
||||
if (mp->pt){
|
||||
pcap_close(mp->pt);
|
||||
mp->pt=NULL;
|
||||
mp->pt = NULL;
|
||||
}
|
||||
if(mp->pcap_desc){
|
||||
// Should I close pcap_desc or pcap_close does this for me?
|
||||
if (mp->pcap_desc) {
|
||||
/* pcap_close() will close the associated pcap descriptor */
|
||||
mp->pcap_desc = -1;
|
||||
}
|
||||
if(mp->pcap_device){
|
||||
if (mp->pcap_device) {
|
||||
free(mp->pcap_device);
|
||||
mp->pcap_device = NULL;
|
||||
}
|
||||
@@ -258,14 +272,10 @@ void nsi_delete(nsock_iod nsockiod, int pending_response) {
|
||||
nsi->pcap = NULL;
|
||||
}
|
||||
#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
|
||||
ids for a given nspool (unless you blow through billions of them). */
|
||||
/* Returns the ID of an nsock_iod . This ID is always unique amongst ids for a
|
||||
* given nspool (unless you blow through billions of them). */
|
||||
unsigned long nsi_id(nsock_iod nsockiod) {
|
||||
assert(nsockiod);
|
||||
return ((msiod *)nsockiod)->id;
|
||||
@@ -280,7 +290,7 @@ nsock_ssl nsi_getssl(nsock_iod nsockiod) {
|
||||
#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) {
|
||||
#if HAVE_OPENSSL
|
||||
return SSL_get1_session(((msiod *)nsockiod)->ssl);
|
||||
@@ -289,7 +299,7 @@ nsock_ssl_session nsi_get1_ssl_session(nsock_iod nsockiod) {
|
||||
#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) {
|
||||
#if HAVE_OPENSSL
|
||||
return SSL_get0_session(((msiod *)nsockiod)->ssl);
|
||||
@@ -298,62 +308,61 @@ nsock_ssl_session nsi_get0_ssl_session(nsock_iod nsockiod) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/* sets the ssl session of an nsock_iod, increments usage count. The
|
||||
session should not have been set yet (as no freeing is done) */
|
||||
/* sets the ssl session of an nsock_iod, increments usage count. The session
|
||||
* should not have been set yet (as no freeing is done) */
|
||||
#if HAVE_OPENSSL
|
||||
void nsi_set_ssl_session(msiod *iod, SSL_SESSION *sessid) {
|
||||
if (sessid) {
|
||||
iod->ssl_session = sessid;
|
||||
|
||||
/* No reference counting for the copy stored briefly in nsiod */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Sometimes it is useful to store a pointer to information inside
|
||||
the msiod so you can retrieve it during a callback. */
|
||||
/* Sometimes it is useful to store a pointer to information inside the msiod so
|
||||
* you can retrieve it during a callback. */
|
||||
void nsi_setud(nsock_iod nsockiod, void *data) {
|
||||
assert(nsockiod);
|
||||
((msiod *)nsockiod)->userdata = data;
|
||||
}
|
||||
|
||||
/* And the function above wouldn't make much sense if we didn't have a way
|
||||
to retrieve that data ... */
|
||||
/* And the function above wouldn't make much sense if we didn't have a way to
|
||||
* retrieve that data... */
|
||||
void *nsi_getud(nsock_iod nsockiod) {
|
||||
assert(nsockiod);
|
||||
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) {
|
||||
return ((msiod *)nsockiod)->ssl? 1 : 0;
|
||||
return (((msiod *)nsockiod)->ssl) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Returns the remote peer port (or -1 if unavailable). Note the
|
||||
return value is a whole int so that -1 can be distinguished from
|
||||
65535. Port is returned in host byte order. */
|
||||
/* Returns the remote peer port (or -1 if unavailable). Note the return value
|
||||
* is a whole int so that -1 can be distinguished from 65535. Port is returned
|
||||
* in host byte order. */
|
||||
int nsi_peerport(nsock_iod nsockiod) {
|
||||
msiod *nsi = (msiod *) nsockiod;
|
||||
msiod *nsi = (msiod *)nsockiod;
|
||||
int fam;
|
||||
|
||||
if (nsi->peerlen <= 0)
|
||||
return -1;
|
||||
|
||||
fam = ((struct sockaddr_in *) &nsi->peer)->sin_family;
|
||||
fam = ((struct sockaddr_in *)&nsi->peer)->sin_family;
|
||||
|
||||
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
|
||||
else if (fam == AF_INET6)
|
||||
return ntohs(((struct sockaddr_in6 *) &nsi->peer)->sin6_port);
|
||||
return ntohs(((struct sockaddr_in6 *)&nsi->peer)->sin6_port);
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Sets the local address to bind to before connect() */
|
||||
int nsi_set_localaddr(nsock_iod nsi, struct sockaddr_storage *ss, size_t sslen)
|
||||
{
|
||||
msiod *iod = (msiod *) nsi;
|
||||
int nsi_set_localaddr(nsock_iod nsi, struct sockaddr_storage *ss, size_t sslen) {
|
||||
msiod *iod = (msiod *)nsi;
|
||||
|
||||
assert(iod);
|
||||
|
||||
@@ -365,13 +374,11 @@ int nsi_set_localaddr(nsock_iod nsi, struct sockaddr_storage *ss, size_t sslen)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sets IPv4 options to apply before connect(). It makes a copy of the
|
||||
* options, so you can free() yours if necessary. This copy is freed
|
||||
* when the iod is destroyed
|
||||
*/
|
||||
int nsi_set_ipoptions(nsock_iod nsi, void *opts, size_t optslen)
|
||||
{
|
||||
msiod *iod = (msiod *) nsi;
|
||||
/* Sets IPv4 options to apply before connect(). It makes a copy of the options,
|
||||
* so you can free() yours if necessary. This copy is freed when the iod is
|
||||
* destroyed. */
|
||||
int nsi_set_ipoptions(nsock_iod nsi, void *opts, size_t optslen) {
|
||||
msiod *iod = (msiod *)nsi;
|
||||
|
||||
assert(iod);
|
||||
|
||||
@@ -384,17 +391,24 @@ int nsi_set_ipoptions(nsock_iod nsi, void *opts, size_t optslen)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* I didn't want to do this. Its an ugly hack, but I suspect it will
|
||||
be neccessary. I certainly can't reproduce in nsock EVERYTHING you
|
||||
might want to do with a socket. So I'm offering you this function
|
||||
to obtain the socket descriptor which is (usually) wrapped in a
|
||||
nsock_iod). You can do "reasonable" things with it, like setting
|
||||
socket receive buffers. But don't create havok by closing the
|
||||
descriptor! If the descriptor you get back is -1, the iod does not
|
||||
currently possess a valid descriptor */
|
||||
/* I didn't want to do this. Its an ugly hack, but I suspect it will be
|
||||
* neccessary. I certainly can't reproduce in nsock EVERYTHING you might want
|
||||
* to do with a socket. So I'm offering you this function to obtain the socket
|
||||
* descriptor which is (usually) wrapped in a nsock_iod). You can do
|
||||
* "reasonable" things with it, like setting socket receive buffers. But don't
|
||||
* create havok by closing the descriptor! If the descriptor you get back is
|
||||
* -1, the iod does not currently possess a valid descriptor */
|
||||
int nsi_getsd(nsock_iod nsockiod) {
|
||||
msiod *iod = (msiod *)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){
|
||||
@@ -405,17 +419,18 @@ unsigned long nsi_get_read_count(nsock_iod nsockiod){
|
||||
unsigned long nsi_get_write_count(nsock_iod nsockiod){
|
||||
assert(nsockiod);
|
||||
return ((msiod *)nsockiod)->write_count;
|
||||
|
||||
}
|
||||
|
||||
int nsi_set_hostname(nsock_iod nsi, const char *hostname) {
|
||||
msiod *iod = (msiod *) nsi;
|
||||
msiod *iod = (msiod *)nsi;
|
||||
|
||||
if (iod->hostname != NULL)
|
||||
free(iod->hostname);
|
||||
|
||||
iod->hostname = strdup(hostname);
|
||||
if (iod->hostname == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -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_internal.h"
|
||||
|
||||
@@ -8,7 +65,7 @@
|
||||
#if HAVE_NET_BPF_H
|
||||
#ifdef _AIX
|
||||
/* Prevent bpf.h from redefining the DLT_ values to their IFT_ values. (See
|
||||
similar comment in libpcap/pcap-bpf.c.) */
|
||||
* similar comment in libpcap/pcap-bpf.c.) */
|
||||
#undef _AIX
|
||||
#include <net/bpf.h>
|
||||
#define _AIX
|
||||
@@ -23,25 +80,20 @@ extern struct timeval nsock_tod;
|
||||
|
||||
#if HAVE_PCAP
|
||||
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 as for pcap_open_live in pcap(3).
|
||||
/* Convert new nsiod to pcap descriptor. Other parameters have the same meaning
|
||||
* as for pcap_open_live in pcap(3).
|
||||
* device : pcap-style device name
|
||||
* snaplen : size of packet to be copied to hanler
|
||||
* 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
|
||||
* */
|
||||
char* nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod,
|
||||
const char *pcap_device, int snaplen, int promisc,
|
||||
const char *bpf_fmt, ...)
|
||||
|
||||
{
|
||||
msiod *nsi = (msiod *) nsiod;
|
||||
mspool *ms = (mspool *) nsp;
|
||||
mspcap *mp = (mspcap *) nsi->pcap;
|
||||
* 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,
|
||||
int promisc, const char *bpf_fmt, ...) {
|
||||
msiod *nsi = (msiod *)nsiod;
|
||||
mspool *ms = (mspool *)nsp;
|
||||
mspcap *mp = (mspcap *)nsi->pcap;
|
||||
static char errorbuf[128];
|
||||
char err0r[PCAP_ERRBUF_SIZE];
|
||||
/* packet filter string */
|
||||
@@ -52,38 +104,45 @@ char* nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod,
|
||||
|
||||
gettimeofday(&nsock_tod, NULL);
|
||||
|
||||
#ifdef PCAP_CAN_DO_SELECT
|
||||
#if PCAP_BSD_SELECT_HACK
|
||||
#ifdef PCAP_CAN_DO_SELECT
|
||||
|
||||
#if PCAP_BSD_SELECT_HACK
|
||||
/* MacOsX reports error if to_ms is too big (like INT_MAX) with error
|
||||
* FAILED. Reported error: BIOCSRTIMEOUT: Invalid argument
|
||||
* INT_MAX/6 (=357913941) seems to be working...*/
|
||||
* INT_MAX/6 (=357913941) seems to be working... */
|
||||
int to_ms = 357913941;
|
||||
#else
|
||||
#else
|
||||
int to_ms = 200;
|
||||
#endif
|
||||
#else
|
||||
#endif /* PCAP_BSD_SELECT_HACK */
|
||||
|
||||
#else
|
||||
int to_ms = 1;
|
||||
#endif
|
||||
if(mp) return "nsock-pcap: this nsi already has pcap device opened";
|
||||
#endif
|
||||
|
||||
if (mp)
|
||||
return "nsock-pcap: this nsi already has pcap device opened";
|
||||
|
||||
mp = (mspcap *)safe_zalloc(sizeof(mspcap));
|
||||
nsi->pcap = (void*)mp;
|
||||
nsi->pcap = (void *)mp;
|
||||
|
||||
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);
|
||||
return "nsock-pcap: nsock_pcap_open called with too-large bpf filter arg";
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
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);
|
||||
|
||||
failed = 0;
|
||||
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!*/
|
||||
break;
|
||||
|
||||
/* sorry, something failed*/
|
||||
if (++failed >= 3) {
|
||||
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?";
|
||||
}
|
||||
|
||||
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);
|
||||
sleep(4* failed);
|
||||
}while(1);
|
||||
} while (1);
|
||||
|
||||
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 */
|
||||
pcap_setmintocopy(mp->pt, 1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
mp->l3_offset = nsock_pcap_get_l3_offset(mp->pt, &datalink);
|
||||
mp->snaplen = snaplen;
|
||||
mp->datalink = datalink;
|
||||
mp->pcap_device = strdup(pcap_device);
|
||||
#ifdef PCAP_CAN_DO_SELECT
|
||||
#ifdef PCAP_CAN_DO_SELECT
|
||||
mp->pcap_desc = pcap_get_selectable_fd(mp->pt);
|
||||
#else
|
||||
#else
|
||||
mp->pcap_desc = -1;
|
||||
#endif
|
||||
#endif
|
||||
mp->readsd_count = 0;
|
||||
|
||||
/* Without setting this ioctl, some systems (BSDs, though it depends on
|
||||
the release) will buffer packets in non-blocking mode and only
|
||||
return them in a bunch when the buffer is full. Setting the ioctl
|
||||
makes each one be delivered immediately. This is how Linux works by
|
||||
default. See the comments surrounding the ssetting of BIOCIMMEDIATE
|
||||
in libpcap/pcap-bpf.c. */
|
||||
/* Without setting this ioctl, some systems (BSDs, though it depends on the
|
||||
* release) will buffer packets in non-blocking mode and only return them in a
|
||||
* bunch when the buffer is full. Setting the ioctl makes each one be
|
||||
* delivered immediately. This is how Linux works by default. See the comments
|
||||
* surrounding the ssetting of BIOCIMMEDIATE in libpcap/pcap-bpf.c. */
|
||||
#ifdef BIOCIMMEDIATE
|
||||
if (mp->pcap_desc != -1) {
|
||||
int immediate = 1;
|
||||
|
||||
if (ioctl(mp->pcap_desc, BIOCIMMEDIATE, &immediate) < 0)
|
||||
fatal("Cannot set BIOCIMMEDIATE on pcap descriptor");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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 */
|
||||
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;
|
||||
}
|
||||
|
||||
/* When we use bsd hack we also need to set non-blocking */
|
||||
#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);
|
||||
#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);
|
||||
return errorbuf;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* 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)
|
||||
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,
|
||||
mp->pcap_desc,
|
||||
#if PCAP_BSD_SELECT_HACK
|
||||
#if PCAP_BSD_SELECT_HACK
|
||||
1,
|
||||
#else
|
||||
#else
|
||||
0,
|
||||
#endif
|
||||
#if PCAP_RECV_TIMEVAL_VALID
|
||||
#endif
|
||||
#if PCAP_RECV_TIMEVAL_VALID
|
||||
1,
|
||||
#else
|
||||
#else
|
||||
0,
|
||||
#endif
|
||||
#endif
|
||||
mp->l3_offset,
|
||||
nsi->id);
|
||||
|
||||
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;
|
||||
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));
|
||||
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));
|
||||
return errorbuf;
|
||||
}
|
||||
@@ -195,16 +260,16 @@ char *nsock_pcap_set_filter(pcap_t *pt, const char *device, const char *bpf)
|
||||
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;
|
||||
unsigned int offset = 0;
|
||||
|
||||
/* 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));
|
||||
|
||||
/* NOTE: IF A NEW OFFSET EVER EXCEEDS THE CURRENT MAX (24), ADJUST
|
||||
MAX_LINK_HEADERSZ in tcpip.h */
|
||||
/* XXX NOTE:
|
||||
* if a new offset ever exceeds the current max (24), adjust max_link_headersz in tcpip.h */
|
||||
switch(datalink) {
|
||||
case DLT_EN10MB: offset = 14; 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. */
|
||||
fatal("Unknown datalink type %d.\n", datalink);
|
||||
}
|
||||
if(dl)
|
||||
if (dl)
|
||||
*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_ev_handler handler, int timeout_msecs,
|
||||
void *userdata)
|
||||
{
|
||||
msiod *nsi = (msiod *) nsiod;
|
||||
mspool *ms = (mspool *) nsp;
|
||||
nsock_ev_handler handler, int timeout_msecs, void *userdata) {
|
||||
msiod *nsi = (msiod *)nsiod;
|
||||
mspool *ms = (mspool *)nsp;
|
||||
msevent *nse;
|
||||
|
||||
nse = msevent_new(ms, NSE_TYPE_PCAP_READ, nsi, timeout_msecs, handler, userdata);
|
||||
assert(nse);
|
||||
|
||||
if (ms->tracelevel > 0) {
|
||||
if (ms->tracelevel > 0)
|
||||
nsock_trace(ms, "Pcap read request from IOD #%li EID %li",
|
||||
nsi->id, nse->id);
|
||||
}
|
||||
|
||||
nsp_add_event(ms, nse);
|
||||
|
||||
return nse->id;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remember that pcap descriptor is in nonblocking state. */
|
||||
int do_actual_pcap_read(msevent *nse)
|
||||
{
|
||||
msiod *iod = nse->iod;
|
||||
mspcap *mp = (mspcap *) iod->pcap;
|
||||
|
||||
/* Remember that pcap descriptor is in nonblocking state. */
|
||||
int do_actual_pcap_read(msevent *nse) {
|
||||
mspcap *mp = (mspcap *)nse->iod->pcap;
|
||||
nsock_pcap npp;
|
||||
nsock_pcap *n;
|
||||
struct pcap_pkthdr *pkt_header;
|
||||
const unsigned char *pkt_data = NULL;
|
||||
int rc;
|
||||
|
||||
memset(&npp, 0, sizeof(nsock_pcap));
|
||||
|
||||
if (nse->iod->nsp->tracelevel > 2)
|
||||
@@ -313,7 +369,7 @@ int do_actual_pcap_read(msevent *nse)
|
||||
assert( FILESPACE_LENGTH(&(nse->iobuf)) == 0 );
|
||||
|
||||
rc = pcap_next_ex(mp->pt, &pkt_header, &pkt_data);
|
||||
switch(rc){
|
||||
switch(rc) {
|
||||
case 1: /* read good packet */
|
||||
#ifdef PCAP_RECV_TIMEVAL_VALID
|
||||
npp.ts = pkt_header->ts;
|
||||
@@ -324,19 +380,24 @@ int do_actual_pcap_read(msevent *nse)
|
||||
npp.len = pkt_header->len;
|
||||
npp.caplen = pkt_header->caplen;
|
||||
npp.packet = pkt_data;
|
||||
fscat(&(nse->iobuf), (char*)&npp, sizeof(npp));
|
||||
fscat(&(nse->iobuf), (char*)pkt_data, npp.caplen);
|
||||
n = (nsock_pcap *) FILESPACE_STR(&(nse->iobuf));
|
||||
n->packet = (unsigned char*)FILESPACE_STR(&(nse->iobuf))+sizeof(npp);
|
||||
|
||||
fscat(&(nse->iobuf), (char *)&npp, sizeof(npp));
|
||||
fscat(&(nse->iobuf), (char *)pkt_data, npp.caplen);
|
||||
n = (nsock_pcap *)FILESPACE_STR(&(nse->iobuf));
|
||||
n->packet = (unsigned char *)FILESPACE_STR(&(nse->iobuf)) + sizeof(npp);
|
||||
|
||||
if (nse->iod->nsp->tracelevel > 2)
|
||||
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);
|
||||
return(1);
|
||||
|
||||
case 0: /* timeout */
|
||||
return(0);
|
||||
|
||||
case -1: /* error */
|
||||
fatal("pcap_next_ex() fatal error while reading from pcap: %s\n", pcap_geterr(mp->pt));
|
||||
break;
|
||||
|
||||
case -2: /* no more packets in savefile (if reading from one) */
|
||||
default:
|
||||
assert(0);
|
||||
@@ -344,53 +405,59 @@ int do_actual_pcap_read(msevent *nse)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nse_readpcap(nsock_event nsee,
|
||||
const unsigned char **l2_data, size_t *l2_len,
|
||||
const unsigned char **l3_data, size_t *l3_len,
|
||||
size_t *packet_len, struct timeval *ts)
|
||||
{
|
||||
void nse_readpcap(nsock_event nsee, const unsigned char **l2_data, size_t *l2_len,
|
||||
const unsigned char **l3_data, size_t *l3_len, size_t *packet_len, struct timeval *ts) {
|
||||
msevent *nse = (msevent *)nsee;
|
||||
msiod *iod = nse->iod;
|
||||
mspcap *mp = (mspcap *) iod->pcap;
|
||||
|
||||
mspcap *mp = (mspcap *)iod->pcap;
|
||||
size_t l2l;
|
||||
size_t l3l;
|
||||
|
||||
nsock_pcap *n = (nsock_pcap *) FILESPACE_STR(&(nse->iobuf));
|
||||
if(FILESPACE_LENGTH(&(nse->iobuf)) < sizeof(nsock_pcap)){
|
||||
if(l2_data) *l2_data = NULL;
|
||||
if(l2_len ) *l2_len = 0;
|
||||
if(l3_data) *l3_data = NULL;
|
||||
if(l3_len ) *l3_len = 0;
|
||||
if(packet_len) *packet_len = 0;
|
||||
nsock_pcap *n = (nsock_pcap *)FILESPACE_STR(&(nse->iobuf));
|
||||
if (FILESPACE_LENGTH(&(nse->iobuf)) < sizeof(nsock_pcap)) {
|
||||
if (l2_data)
|
||||
*l2_data = NULL;
|
||||
if (l2_len)
|
||||
*l2_len = 0;
|
||||
if (l3_data)
|
||||
*l3_data = NULL;
|
||||
if (l3_len)
|
||||
*l3_len = 0;
|
||||
if (packet_len)
|
||||
*packet_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
l2l = MIN(mp->l3_offset, n->caplen);
|
||||
l3l = MAX(0, n->caplen-mp->l3_offset);
|
||||
|
||||
if(l2_data) *l2_data = n->packet;
|
||||
if(l2_len ) *l2_len = l2l;
|
||||
if(l3_data) *l3_data = l3l>0? n->packet+l2l : NULL;
|
||||
if(l3_len ) *l3_len = l3l;
|
||||
if(packet_len) *packet_len = n->len;
|
||||
if(ts) *ts = n->ts;
|
||||
if (l2_data)
|
||||
*l2_data = n->packet;
|
||||
if (l2_len)
|
||||
*l2_len = l2l;
|
||||
if (l3_data)
|
||||
*l3_data = (l3l > 0) ? n->packet+l2l : NULL;
|
||||
if (l3_len)
|
||||
*l3_len = l3l;
|
||||
if (packet_len)
|
||||
*packet_len = n->len;
|
||||
if (ts)
|
||||
*ts = n->ts;
|
||||
return;
|
||||
}
|
||||
|
||||
int nsi_pcap_linktype(nsock_iod nsiod){
|
||||
msiod *nsi = (msiod *) nsiod;
|
||||
mspcap *mp = (mspcap *) nsi->pcap;
|
||||
int nsi_pcap_linktype(nsock_iod nsiod) {
|
||||
msiod *nsi = (msiod *)nsiod;
|
||||
mspcap *mp = (mspcap *)nsi->pcap;
|
||||
assert(mp);
|
||||
return(mp->datalink);
|
||||
return (mp->datalink);
|
||||
}
|
||||
|
||||
int nsi_is_pcap(nsock_iod nsiod){
|
||||
msiod *nsi = (msiod *) nsiod;
|
||||
mspcap *mp = (mspcap *) nsi->pcap;
|
||||
return(mp!=NULL);
|
||||
int nsi_is_pcap(nsock_iod nsiod) {
|
||||
msiod *nsi = (msiod *)nsiod;
|
||||
mspcap *mp = (mspcap *)nsi->pcap;
|
||||
return (mp != NULL);
|
||||
}
|
||||
|
||||
|
||||
#endif // HAVE_PCAP
|
||||
#endif /* HAVE_PCAP */
|
||||
|
||||
|
||||
@@ -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
|
||||
#define NSOCK_PCAP_H
|
||||
|
||||
@@ -23,9 +80,9 @@
|
||||
* 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.
|
||||
* */
|
||||
*/
|
||||
|
||||
// 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)
|
||||
#define PCAP_CAN_DO_SELECT 1
|
||||
#endif
|
||||
@@ -54,14 +111,14 @@
|
||||
* on BPF devices, so the workaround isn't necessary, although it does no harm.)
|
||||
*/
|
||||
#if defined(MACOSX) || defined(FREEBSD) || defined(OPENBSD)
|
||||
// Well, now select() is not receiving any pcap events on MACOSX, but maybe it will someday :)
|
||||
// in both cases. It never hurts to enable this feature. It just has performance penalty.
|
||||
/* Well, now select() is not receiving any pcap events on MACOSX, but maybe it will someday :)
|
||||
* in both cases. It never hurts to enable this feature. It just has performance penalty. */
|
||||
#define PCAP_BSD_SELECT_HACK 1
|
||||
#endif
|
||||
|
||||
// Returns whether the packet receive time value obtained from libpcap
|
||||
// (and thus by readip_pcap()) should be considered valid. When
|
||||
// invalid (Windows and Amiga), readip_pcap returns the time you called it.
|
||||
/* Returns whether the packet receive time value obtained from libpcap
|
||||
* (and thus by readip_pcap()) should be considered valid. When
|
||||
* invalid (Windows and Amiga), readip_pcap returns the time you called it. */
|
||||
#if !defined(WIN32) && !defined(__amigaos__)
|
||||
#define PCAP_RECV_TIMEVAL_VALID 1
|
||||
#endif
|
||||
@@ -71,7 +128,7 @@ typedef struct{
|
||||
pcap_t *pt;
|
||||
int pcap_desc;
|
||||
/* 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 datalink;
|
||||
int l3_offset;
|
||||
@@ -79,15 +136,15 @@ typedef struct{
|
||||
char *pcap_device;
|
||||
} mspcap;
|
||||
|
||||
|
||||
typedef struct{
|
||||
struct timeval ts;
|
||||
int caplen;
|
||||
int len;
|
||||
const unsigned char *packet; // caplen bytes
|
||||
const unsigned char *packet; /* caplen bytes */
|
||||
} nsock_pcap;
|
||||
|
||||
int do_actual_pcap_read(msevent *nse);
|
||||
|
||||
#endif /* HAVE_PCAP */
|
||||
#endif /* NSOCK_PCAP_H */
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* nsock_pool.c -- This contains the functions that deal with creating, *
|
||||
* destroying, and otherwise manipulating nsock_pools (and their internal *
|
||||
@@ -71,15 +70,210 @@
|
||||
#endif
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
extern struct timeval nsock_tod;
|
||||
|
||||
unsigned long nsp_next_id = 2;
|
||||
|
||||
static int nsocklib_initialized = 0; /* To use this library, the first thing
|
||||
they must do is create a pool -- so
|
||||
we do the initialization during the
|
||||
first pool creation */
|
||||
/* To use this library, the first thing they must do is create a pool
|
||||
* so we do the initialization during the first pool creation */
|
||||
static int nsocklib_initialized = 0;
|
||||
|
||||
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;
|
||||
|
||||
/* We want to make darn sure the evil SIGPIPE is ignored */
|
||||
@@ -94,183 +288,3 @@ static void nsock_library_initialize(void) {
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* nsock_read.c -- This contains the functions for requesting various read *
|
||||
* events from the nsock parallel socket event library *
|
||||
@@ -58,30 +57,27 @@
|
||||
|
||||
#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);
|
||||
assert(nse);
|
||||
|
||||
if (ms->tracelevel > 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);
|
||||
else
|
||||
nsock_trace(ms, "Read request for %d lines from IOD #%li (peer unspecified) EID %li", nlines,
|
||||
nsi->id, nse->id);
|
||||
nsock_trace(ms, "Read request for %d lines from IOD #%li (peer unspecified) EID %li", nlines, nsi->id, nse->id);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Same as above, except it tries to read at least 'nbytes' instead of
|
||||
'nlines'. */
|
||||
nsock_event_id nsock_readbytes(nsock_pool nsp, nsock_iod ms_iod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
/* Same as above, except it tries to read at least 'nbytes' instead of 'nlines'. */
|
||||
nsock_event_id nsock_readbytes(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, int nbytes) {
|
||||
|
||||
msiod *nsi = (msiod *) ms_iod;
|
||||
mspool *ms = (mspool *) nsp;
|
||||
msiod *nsi = (msiod *)ms_iod;
|
||||
mspool *ms = (mspool *)nsp;
|
||||
msevent *nse;
|
||||
|
||||
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 (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);
|
||||
else
|
||||
nsock_trace(ms, "Read request for %d bytes from IOD #%li (peer unspecified) EID %li", nbytes,
|
||||
nsi->id, nse->id);
|
||||
nsock_trace(ms, "Read request for %d bytes from IOD #%li (peer unspecified) EID %li", nbytes, nsi->id, nse->id);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return nse->id;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* The simplest read function -- returns NSE_STATUS_SUCCESS when it
|
||||
reads anything, otherwise it returns timeout, eof, or error as
|
||||
appropriate */
|
||||
nsock_event_id nsock_read(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler,
|
||||
int timeout_msecs, void *userdata) {
|
||||
|
||||
msiod *nsi = (msiod *) ms_iod;
|
||||
mspool *ms = (mspool *) nsp;
|
||||
* reads anything, otherwise it returns timeout, eof, or error as appropriate */
|
||||
nsock_event_id nsock_read(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs, void *userdata) {
|
||||
msiod *nsi = (msiod *)ms_iod;
|
||||
mspool *ms = (mspool *)nsp;
|
||||
msevent *nse;
|
||||
|
||||
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 (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
|
||||
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;
|
||||
@@ -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);
|
||||
|
||||
return nse->id;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* nsock_ssl.c -- This contains functions that relate somewhat exclusively *
|
||||
* to SSL (over TCP) support in nsock. Where SSL support is incidental, *
|
||||
@@ -67,88 +66,87 @@
|
||||
#if HAVE_OPENSSL
|
||||
|
||||
/* Disallow anonymous ciphers (Diffie-Hellman key agreement), low bit-strength
|
||||
ciphers, export-crippled ciphers, and MD5. Prefer ciphers in decreasing order
|
||||
of key size. The cipher list is taken from the book Network Security with
|
||||
OpenSSL. To see exactly what ciphers are enabled, use the command
|
||||
openssl ciphers -v '...'
|
||||
where ... is the string below. */
|
||||
* ciphers, export-crippled ciphers, and MD5. Prefer ciphers in decreasing order
|
||||
* of key size. The cipher list is taken from the book Network Security with
|
||||
* OpenSSL. To see exactly what ciphers are enabled, use the command
|
||||
* openssl ciphers -v '...'
|
||||
* where ... is the string below. */
|
||||
#define CIPHERS_SECURE "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
|
||||
|
||||
/* This list of ciphers is for speed and compatibility, not security. Any cipher
|
||||
is accepted, and the list is sorted by speed based on Brian Hatch's
|
||||
(bri@ifokr.org) tests on an Pentium 686 against the ciphers listed. */
|
||||
* is accepted, and the list is sorted by speed based on Brian Hatch's
|
||||
* (bri@ifokr.org) tests on an Pentium 686 against the ciphers listed. */
|
||||
#define CIPHERS_FAST "RC4-SHA:RC4-MD5:NULL-SHA:EXP-DES-CBC-SHA:EXP-EDH-RSA-DES-CBC-SHA:EXP-RC4-MD5:NULL-MD5:EDH-RSA-DES-CBC-SHA:EXP-RC2-CBC-MD5:EDH-RSA-DES-CBC3-SHA:EXP-ADH-RC4-MD5:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:EXP-ADH-DES-CBC-SHA:ADH-AES256-SHA:ADH-DES-CBC-SHA:ADH-RC4-MD5:AES256-SHA:DES-CBC-SHA:DES-CBC3-SHA:ADH-DES-CBC3-SHA:AES128-SHA:ADH-AES128-SHA:eNULL:ALL"
|
||||
|
||||
extern struct timeval nsock_tod;
|
||||
|
||||
/* 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() {
|
||||
SSL_CTX *ctx;
|
||||
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
|
||||
ctx = SSL_CTX_new( SSLv23_client_method() );
|
||||
if ( ! ctx ) {
|
||||
ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
if (!ctx) {
|
||||
fatal("OpenSSL failed to create a new SSL_CTX: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
|
||||
/* Our SSL* will always have the SSL_SESSION* inside it, so we neither
|
||||
need to use nor waste memory for the session cache.
|
||||
(Use '1' because '0' means 'infinite'.) */
|
||||
SSL_CTX_set_session_cache_mode(
|
||||
ctx, SSL_SESS_CACHE_OFF | SSL_SESS_CACHE_NO_AUTO_CLEAR );
|
||||
SSL_CTX_sess_set_cache_size( ctx, 1 );
|
||||
SSL_CTX_set_timeout( ctx, 3600); /* pretty unnecessary */
|
||||
/* Our SSL* will always have the SSL_SESSION* inside it, so we neither need to
|
||||
* use nor waste memory for the session cache. (Use '1' because '0' means
|
||||
* 'infinite'.) */
|
||||
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF|SSL_SESS_CACHE_NO_AUTO_CLEAR);
|
||||
SSL_CTX_sess_set_cache_size(ctx, 1);
|
||||
SSL_CTX_set_timeout(ctx, 3600); /* pretty unnecessary */
|
||||
|
||||
return ctx;
|
||||
}
|
||||
#endif /* HAVE_OPENSSL */
|
||||
|
||||
/* Initializes an Nsock pool to create SSL connections. This sets an internal
|
||||
SSL_CTX, which is like a template that sets options for all connections that
|
||||
are made from it. The connections made from this context will use only secure
|
||||
ciphers but no server certificate verification is done. Returns the SSL_CTX
|
||||
so you can set your own options. */
|
||||
* SSL_CTX, which is like a template that sets options for all connections that
|
||||
* are made from it. The connections made from this context will use only secure
|
||||
* ciphers but no server certificate verification is done. Returns the SSL_CTX
|
||||
* so you can set your own options. */
|
||||
nsock_ssl_ctx nsp_ssl_init(nsock_pool ms_pool) {
|
||||
#if HAVE_OPENSSL
|
||||
mspool *ms = (mspool *) ms_pool;
|
||||
mspool *ms = (mspool *)ms_pool;
|
||||
char rndbuf[128];
|
||||
|
||||
if (ms->sslctx == NULL)
|
||||
ms->sslctx = ssl_init_common();
|
||||
|
||||
/* get_random_bytes may or may not provide high-quality randomness. Add it to
|
||||
the entropy pool without increasing the entropy estimate (third argument of
|
||||
RAND_add is 0). We rely on OpenSSL's entropy gathering, called implicitly
|
||||
by RAND_status, to give us what we need, or else bail out if it fails. */
|
||||
* the entropy pool without increasing the entropy estimate (third argument of
|
||||
* RAND_add is 0). We rely on OpenSSL's entropy gathering, called implicitly
|
||||
* by RAND_status, to give us what we need, or else bail out if it fails. */
|
||||
get_random_bytes(rndbuf, sizeof(rndbuf));
|
||||
RAND_add(rndbuf, sizeof(rndbuf), 0);
|
||||
if (!RAND_status())
|
||||
fatal("nsp_ssl_init: Failed to seed OpenSSL PRNG (RAND_status returned false).");
|
||||
|
||||
/* By default, do no server certificate verification. To enable it, do
|
||||
something like
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
|
||||
on the SSL_CTX returned. If you do, it is then up to the application to
|
||||
load trusted certificates with SSL_CTX_load_verify_locations or
|
||||
SSL_CTX_set_default_verify_paths, or else every connection will fail. It is
|
||||
also up to the application to do any further checks such as domain name
|
||||
validation. */
|
||||
* something like:
|
||||
* SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
|
||||
*
|
||||
* on the SSL_CTX returned. If you do, it is then up to the application to
|
||||
* load trusted certificates with SSL_CTX_load_verify_locations or
|
||||
* SSL_CTX_set_default_verify_paths, or else every connection will fail. It
|
||||
* is also up to the application to do any further checks such as domain name
|
||||
* validation. */
|
||||
SSL_CTX_set_verify(ms->sslctx, SSL_VERIFY_NONE, NULL);
|
||||
|
||||
/* SSL_OP_ALL sets bug-compatibility for pretty much everything.
|
||||
SSL_OP_NO_SSLv2 disables the less-secure SSLv2 while allowing us to use the
|
||||
SSLv2-compatible SSLv23_client_method. */
|
||||
SSL_CTX_set_options(ms->sslctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
|
||||
* SSL_OP_NO_SSLv2 disables the less-secure SSLv2 while allowing us to use the
|
||||
* SSLv2-compatible SSLv23_client_method. */
|
||||
SSL_CTX_set_options(ms->sslctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
|
||||
|
||||
if (!SSL_CTX_set_cipher_list(ms->sslctx, CIPHERS_SECURE)) {
|
||||
fatal("Unable to set OpenSSL cipher list: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
|
||||
return ms->sslctx;
|
||||
#else
|
||||
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
|
||||
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. */
|
||||
* 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. */
|
||||
nsock_ssl_ctx nsp_ssl_init_max_speed(nsock_pool ms_pool) {
|
||||
#if HAVE_OPENSSL
|
||||
mspool *ms = (mspool *) ms_pool;
|
||||
mspool *ms = (mspool *)ms_pool;
|
||||
char rndbuf[128];
|
||||
|
||||
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",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
|
||||
return ms->sslctx;
|
||||
#else
|
||||
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 first that a certificate was even offered, then call
|
||||
SSL_get_verify_result to get the overall status of verification. (Just
|
||||
calling SSL_get_verify_result is not enough because that function returns
|
||||
X509_V_OK when 0 certificates are presented.) If the verification mode of the
|
||||
SSL object is SSL_VERIFY_NONE, or if OpenSSL is disabled, this function
|
||||
always returns true. */
|
||||
* check first that a certificate was even offered, then call
|
||||
* SSL_get_verify_result to get the overall status of verification. (Just
|
||||
* calling SSL_get_verify_result is not enough because that function returns
|
||||
* X509_V_OK when 0 certificates are presented.) If the verification mode of the
|
||||
* SSL object is SSL_VERIFY_NONE, or if OpenSSL is disabled, this function
|
||||
* always returns true. */
|
||||
int nsi_ssl_post_connect_verify(const nsock_iod nsockiod) {
|
||||
#if HAVE_OPENSSL
|
||||
msiod *iod = (msiod *) nsockiod;
|
||||
msiod *iod = (msiod *)nsockiod;
|
||||
|
||||
assert(iod->ssl != NULL);
|
||||
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)
|
||||
/* No certificate presented. */
|
||||
return 0;
|
||||
|
||||
X509_free(cert);
|
||||
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* nsock_ssl.c -- This contains functions that relate somewhat exclusively *
|
||||
* to SSL (over TCP) support in nsock. Where SSL support is incidental, *
|
||||
@@ -73,7 +72,7 @@
|
||||
|
||||
struct sslinfo {
|
||||
/* SSL_ERROR_NONE, SSL_ERROR_WANT_CONNECT, SSL_ERROR_WAINT_READ, or
|
||||
SSL_ERROR_WANT_WRITE */
|
||||
* SSL_ERROR_WANT_WRITE */
|
||||
int ssl_desire;
|
||||
};
|
||||
|
||||
@@ -81,3 +80,4 @@ int nsi_ssl_post_connect_verify(const nsock_iod nsockiod);
|
||||
|
||||
#endif /* HAVE_OPENSSL */
|
||||
#endif /* NSOCK_SSL_H */
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* nsock_read.c -- This contains the functions for requesting timers *
|
||||
* from the nsock parallel socket event library *
|
||||
@@ -58,19 +57,18 @@
|
||||
|
||||
#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,
|
||||
int timeout_msecs, void *userdata) {
|
||||
mspool *nsp = (mspool *) ms_pool;
|
||||
mspool *nsp = (mspool *)ms_pool;
|
||||
msevent *nse;
|
||||
|
||||
nse = msevent_new(nsp, NSE_TYPE_TIMER, NULL, timeout_msecs, handler,
|
||||
userdata);
|
||||
nse = msevent_new(nsp, NSE_TYPE_TIMER, NULL, timeout_msecs, handler, userdata);
|
||||
assert(nse);
|
||||
|
||||
if (nsp->tracelevel > 0) {
|
||||
if (nsp->tracelevel > 0)
|
||||
nsock_trace(nsp, "Timer created - %dms from now. EID %li", timeout_msecs, nse->id);
|
||||
}
|
||||
|
||||
nsp_add_event(nsp, nse);
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* nsock_write.c -- This contains the functions relating to writing to *
|
||||
* sockets using the nsock parallel socket event library *
|
||||
@@ -63,21 +62,18 @@
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *saddr, size_t sslen,
|
||||
unsigned short port, const char *data, int datalen) {
|
||||
mspool *nsp = (mspool *) ms_pool;
|
||||
msiod *nsi = (msiod *) ms_iod;
|
||||
nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port, const char *data, int datalen) {
|
||||
mspool *nsp = (mspool *)ms_pool;
|
||||
msiod *nsi = (msiod *)ms_iod;
|
||||
msevent *nse;
|
||||
char displaystr[256];
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *) saddr;
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
|
||||
#if HAVE_IPV6
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) saddr;
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)saddr;
|
||||
#endif
|
||||
|
||||
nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler,
|
||||
userdata);
|
||||
nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata);
|
||||
assert(nse);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, const char *data, int datalen) {
|
||||
mspool *nsp = (mspool *) ms_pool;
|
||||
msiod *nsi = (msiod *) ms_iod;
|
||||
nsock_ev_handler handler, int timeout_msecs, void *userdata, const char *data, int datalen) {
|
||||
mspool *nsp = (mspool *)ms_pool;
|
||||
msiod *nsi = (msiod *)ms_iod;
|
||||
msevent *nse;
|
||||
char displaystr[256];
|
||||
|
||||
nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler,
|
||||
userdata);
|
||||
nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata);
|
||||
assert(nse);
|
||||
|
||||
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, '.');
|
||||
} else displaystr[0] = '\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);
|
||||
else
|
||||
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 */
|
||||
nsock_event_id nsock_printf(nsock_pool ms_pool, nsock_iod ms_iod,
|
||||
nsock_ev_handler handler, int timeout_msecs,
|
||||
void *userdata, char *format, ... ) {
|
||||
|
||||
mspool *nsp = (mspool *) ms_pool;
|
||||
msiod *nsi = (msiod *) ms_iod;
|
||||
nsock_ev_handler handler, int timeout_msecs, void *userdata, char *format, ... ) {
|
||||
mspool *nsp = (mspool *)ms_pool;
|
||||
msiod *nsi = (msiod *)ms_iod;
|
||||
msevent *nse;
|
||||
char buf[4096];
|
||||
char *buf2 = NULL;
|
||||
@@ -181,8 +176,7 @@ nsock_event_id nsock_printf(nsock_pool ms_pool, nsock_iod ms_iod,
|
||||
va_list ap;
|
||||
va_start(ap,format);
|
||||
|
||||
nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler,
|
||||
userdata);
|
||||
nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata);
|
||||
assert(nse);
|
||||
|
||||
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 > sizeof(buf)) {
|
||||
buf2 = (char * ) safe_malloc(res + 16);
|
||||
buf2 = (char * )safe_malloc(res + 16);
|
||||
res2 = Vsnprintf(buf2, sizeof(buf), format, ap);
|
||||
if (res2 == -1 || res2 > res) {
|
||||
free(buf2);
|
||||
buf2 = NULL;
|
||||
} else strlength = res2;
|
||||
} else
|
||||
strlength = res2;
|
||||
} else {
|
||||
buf2 = buf;
|
||||
strlength = res;
|
||||
@@ -221,18 +216,19 @@ nsock_event_id nsock_printf(nsock_pool ms_pool, nsock_iod ms_iod,
|
||||
memcpy(displaystr + 2, buf2, strlength);
|
||||
displaystr[2 + strlength] = '\0';
|
||||
replacenonprintable(displaystr + 2, strlength, '.');
|
||||
} else displaystr[0] = '\0';
|
||||
} else {
|
||||
displaystr[0] = '\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);
|
||||
else
|
||||
nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li (peer unspecified)%s", strlength,
|
||||
nsi->id, nse->id, displaystr);
|
||||
}
|
||||
|
||||
if (buf2 != buf) {
|
||||
if (buf2 != buf)
|
||||
free(buf2);
|
||||
}
|
||||
|
||||
nsp_add_event(nsp, nse);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user