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

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

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

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

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

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

View File

@@ -1,5 +1,11 @@
# Nmap Changelog ($Id$); -*-text-*-
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

View File

@@ -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 */

View File

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

View File

@@ -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" />

View File

@@ -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
View File

@@ -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. */

View File

@@ -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
View File

@@ -0,0 +1,396 @@
/***************************************************************************
* engine_epoll.c -- epoll(7) based IO engine. *
* *
***********************IMPORTANT NSOCK LICENSE TERMS***********************
* *
* The nsock parallel socket event library is (C) 1999-2011 Insecure.Com *
* LLC This library is free software; you may redistribute and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; Version 2. This guarantees *
* your right to use, modify, and redistribute this software under certain *
* conditions. If this license is unacceptable to you, Insecure.Com LLC *
* may be willing to sell alternative licenses (contact *
* sales@insecure.com ). *
* *
* As a special exception to the GPL terms, Insecure.Com LLC grants *
* permission to link the code of this program with any version of the *
* OpenSSL library which is distributed under a license identical to that *
* listed in the included docs/licenses/OpenSSL.txt file, and distribute *
* linked combinations including the two. You must obey the GNU GPL in all *
* respects for all of the code used other than OpenSSL. If you modify *
* this file, you may extend this exception to your version of the file, *
* but you are not obligated to do so. *
* *
* If you received these files with a written license agreement stating *
* terms other than the (GPL) terms above, then that alternative license *
* agreement takes precedence over this comment. *
* *
* Source is provided to this software because we believe users have a *
* right to know exactly what a program is going to do before they run it. *
* This also allows you to audit the software for security holes (none *
* have been found so far). *
* *
* Source code also allows you to port Nmap to new platforms, fix bugs, *
* and add new features. You are highly encouraged to send your changes *
* to nmap-dev@insecure.org for possible incorporation into the main *
* distribution. By sending these changes to Fyodor or one of the *
* Insecure.Org development mailing lists, it is assumed that you are *
* offering the Nmap Project (Insecure.Com LLC) the unlimited, *
* non-exclusive right to reuse, modify, and relicense the code. Nmap *
* will always be available Open Source, but this is important because the *
* inability to relicense code has caused devastating problems for other *
* Free Software projects (such as KDE and NASM). We also occasionally *
* relicense the code to third parties as discussed above. If you wish to *
* specify special license conditions of your contributions, just say so *
* when you send them. *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License v2.0 for more details *
* (http://www.gnu.org/licenses/gpl-2.0.html). *
* *
***************************************************************************/
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "nsock_config.h"
#endif
#if HAVE_EPOLL
#include <sys/epoll.h>
#include <errno.h>
#include "nsock_internal.h"
#if HAVE_PCAP
#include "nsock_pcap.h"
#endif
#define INITIAL_EV_COUNT 128
#define EPOLL_R_FLAGS (EPOLLIN | EPOLLPRI)
#define EPOLL_W_FLAGS EPOLLOUT
#define EPOLL_X_FLAGS (EPOLLERR | EPOLLRDHUP | EPOLLHUP)
/* --- ENGINE INTERFACE PROTOTYPES --- */
static int epoll_init(mspool *nsp);
static void epoll_destroy(mspool *nsp);
static int epoll_iod_register(mspool *nsp, msiod *iod, int ev);
static int epoll_iod_unregister(mspool *nsp, msiod *iod);
static int epoll_iod_modify(mspool *nsp, msiod *iod, int ev_set, int ev_clr);
static int epoll_loop(mspool *nsp, int msec_timeout);
/* ---- ENGINE DEFINITION ---- */
struct io_engine engine_epoll = {
"epoll",
epoll_init,
epoll_destroy,
epoll_iod_register,
epoll_iod_unregister,
epoll_iod_modify,
epoll_loop
};
/* --- INTERNAL PROTOTYPES --- */
static void iterate_through_event_lists(mspool *nsp, int evcount);
/* defined in nsock_core.c */
void process_iod_events(mspool *nsp, msiod *nsi, int ev);
void process_event(mspool *nsp, gh_list *evlist, msevent *nse, int ev);
#if HAVE_PCAP
int pcap_read_on_nonselect(mspool *nsp);
#endif
/* defined in nsock_event.c */
void update_first_events(msevent *nse);
extern struct timeval nsock_tod;
/*
* Engine specific data structure
*/
struct epoll_engine_info {
/* file descriptor corresponding to our epoll instance */
int epfd;
/* number of epoll_events we can deal with */
int evlen;
/* list of epoll events, resized if necessary (when polling over large numbers of IODs) */
struct epoll_event *events;
};
int epoll_init(mspool *nsp) {
struct epoll_engine_info *einfo;
einfo = (struct epoll_engine_info *)safe_malloc(sizeof(struct epoll_engine_info));
einfo->epfd = epoll_create(10); /* argument is ignored */
einfo->evlen = INITIAL_EV_COUNT;
einfo->events = (struct epoll_event *)safe_malloc(einfo->evlen * sizeof(struct epoll_event));
nsp->engine_data = (void *)einfo;
return 1;
}
void epoll_destroy(mspool *nsp) {
struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data;
assert(einfo != NULL);
close(einfo->epfd);
free(einfo->events);
free(einfo);
}
int epoll_iod_register(mspool *nsp, msiod *iod, int ev) {
int sd;
struct epoll_event epev;
struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data;
assert(!IOD_PROPGET(iod, IOD_REGISTERED));
iod->watched_events = ev;
epev.events = EPOLLET;
epev.data.ptr = (void *)iod;
if (ev & EV_READ)
epev.events |= EPOLL_R_FLAGS;
if (ev & EV_WRITE)
epev.events |= EPOLL_W_FLAGS;
if (ev & EV_EXCEPT)
epev.events |= EPOLL_X_FLAGS;
sd = nsi_getsd(iod);
if (epoll_ctl(einfo->epfd, EPOLL_CTL_ADD, sd, &epev) < 0)
fatal("Unable to register IOD #%lu: %s", iod->id, strerror(errno));
IOD_PROPSET(iod, IOD_REGISTERED);
return 1;
}
int epoll_iod_unregister(mspool *nsp, msiod *iod) {
iod->watched_events = EV_NONE;
/* some IODs can be unregistered here if they're associated to an event that was
* immediately completed */
if (IOD_PROPGET(iod, IOD_REGISTERED)) {
struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data;
int sd;
sd = nsi_getsd(iod);
epoll_ctl(einfo->epfd, EPOLL_CTL_DEL, sd, NULL);
IOD_PROPCLR(iod, IOD_REGISTERED);
}
return 1;
}
int epoll_iod_modify(mspool *nsp, msiod *iod, int ev_set, int ev_clr) {
int sd;
struct epoll_event epev;
int new_events;
struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data;
assert((ev_set & ev_clr) == 0);
epev.events = EPOLLET;
epev.data.ptr = (void *)iod;
new_events = iod->watched_events;
new_events |= ev_set;
new_events &= ~ev_clr;
if (new_events == iod->watched_events)
return 1; /* nothing to do */
iod->watched_events = new_events;
/* regenerate the current set of events for this IOD */
if (iod->watched_events & EV_READ)
epev.events |= EPOLL_R_FLAGS;
if (iod->watched_events & EV_WRITE)
epev.events |= EPOLL_W_FLAGS;
if (iod->watched_events & EV_EXCEPT)
epev.events |= EPOLL_X_FLAGS;
sd = nsi_getsd(iod);
epoll_ctl(einfo->epfd, EPOLL_CTL_MOD, sd, &epev);
return 1;
}
int epoll_loop(mspool *nsp, int msec_timeout) {
int results_left;
int event_msecs; /* msecs before an event goes off */
int combined_msecs;
int sock_err = 0;
struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data;
assert(msec_timeout >= -1);
if (nsp->events_pending == 0)
return 0; /* No need to wait on 0 events ... */
if (GH_LIST_COUNT(&nsp->active_iods) > einfo->evlen) {
einfo->evlen = GH_LIST_COUNT(&nsp->active_iods) * 2;
einfo->events = (struct epoll_event *)safe_realloc(einfo->events, einfo->evlen * sizeof(struct epoll_event));
}
do {
if (nsp->tracelevel > 6)
nsock_trace(nsp, "wait_for_events");
if (nsp->next_ev.tv_sec == 0)
event_msecs = -1; /* None of the events specified a timeout */
else
event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nsp->next_ev, nsock_tod));
#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
/* Force a low timeout when capturing packets on systems where
* the pcap descriptor is not select()able. */
if (GH_LIST_COUNT(&nsp->pcap_read_events) > 0)
if (event_msecs > PCAP_POLL_INTERVAL)
event_msecs = PCAP_POLL_INTERVAL;
#endif
#endif
/* We cast to unsigned because we want -1 to be very high (since it means no
* timeout) */
combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout);
#if HAVE_PCAP
/* do non-blocking read on pcap devices that doesn't support select()
* If there is anything read, don't do usleep() or select(), just leave this loop */
if (pcap_read_on_nonselect(nsp)) {
/* okay, something was read. */
} else
#endif
{
if (einfo->evlen)
results_left = epoll_wait(einfo->epfd, einfo->events, einfo->evlen, combined_msecs);
else
results_left = 0;
if (results_left == -1)
sock_err = socket_errno();
}
gettimeofday(&nsock_tod, NULL); /* Due to usleep or epoll delay */
} while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occured */
if (results_left == -1 && sock_err != EINTR) {
nsock_trace(nsp, "nsock_loop error %d: %s", sock_err, socket_strerror(sock_err));
nsp->errnum = sock_err;
return -1;
}
iterate_through_event_lists(nsp, results_left);
return 1;
}
/* ---- INTERNAL FUNCTIONS ---- */
/* Iterate through all the event lists (such as connect_events, read_events,
* timer_events, etc) and take action for those that have completed (due to
* timeout, i/o, etc) */
void iterate_through_event_lists(mspool *nsp, int evcount) {
int n, initial_iod_count;
struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data;
gh_list_elem *current, *next, *last, *timer_last, *last_active = NULL;
msevent *nse;
msiod *nsi;
/* Clear it -- We will find the next event as we go through the list */
nsp->next_ev.tv_sec = 0;
last = GH_LIST_LAST_ELEM(&nsp->active_iods);
timer_last = GH_LIST_LAST_ELEM(&nsp->timer_events);
initial_iod_count = GH_LIST_COUNT(&nsp->active_iods);
for (n = 0; n < evcount; n++) {
int evmask = EV_NONE;
nsi = (msiod *)einfo->events[n].data.ptr;
assert(nsi);
if (nsi->entry_in_nsp_active_iods == last)
last = GH_LIST_ELEM_PREV(nsi->entry_in_nsp_active_iods);
/* generate the corresponding event mask with nsock event flags */
if (einfo->events[n].events & EPOLL_R_FLAGS)
evmask |= EV_READ;
if (einfo->events[n].events & EPOLL_W_FLAGS)
evmask |= EV_WRITE;
if (einfo->events[n].events & EPOLL_X_FLAGS)
evmask |= (EV_READ | EV_WRITE | EV_EXCEPT);
/* process all the pending events for this IOD */
process_iod_events(nsp, nsi, evmask);
if (nsi->state != NSIOD_STATE_DELETED) {
gh_list_move_front(&nsp->active_iods, nsi->entry_in_nsp_active_iods);
if (last_active == NULL)
last_active = nsi->entry_in_nsp_active_iods;
} else {
gh_list_remove_elem(&nsp->active_iods, nsi->entry_in_nsp_active_iods);
gh_list_prepend(&nsp->free_iods, nsi);
}
}
if (evcount < initial_iod_count) {
/* some IODs had no active events and need to be processed */
if (!last_active)
/* either no IOD had events or all IODs were deleted after event processing */
current = GH_LIST_FIRST_ELEM(&nsp->active_iods);
else
/* IODs that had active events were pushed to the beginning of the list, start after them */
current = GH_LIST_ELEM_NEXT(last_active);
} else {
/* all the IODs had events and were therefore processed */
current = NULL;
}
/* cull timeouts amongst the non active IODs */
while (current != NULL && GH_LIST_ELEM_PREV(current) != last) {
msiod *nsi = (msiod *)GH_LIST_ELEM_DATA(current);
if (nsi->state != NSIOD_STATE_DELETED && nsi->events_pending)
process_iod_events(nsp, nsi, EV_NONE);
next = GH_LIST_ELEM_NEXT(current);
if (nsi->state == NSIOD_STATE_DELETED) {
gh_list_remove_elem(&nsp->active_iods, current);
gh_list_prepend(&nsp->free_iods, nsi);
}
current = next;
}
/* iterate through timers */
for (current = GH_LIST_FIRST_ELEM(&nsp->timer_events);
current != NULL && GH_LIST_ELEM_PREV(current) != timer_last; current = next) {
nse = (msevent *)GH_LIST_ELEM_DATA(current);
process_event(nsp, &nsp->timer_events, nse, EV_NONE);
next = GH_LIST_ELEM_NEXT(current);
if (nse->event_done)
gh_list_remove_elem(&nsp->timer_events, current);
}
}
#endif /* HAVE_EPOLL */

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

@@ -0,0 +1,409 @@
/***************************************************************************
* engine_select.c -- select(2) based IO engine. *
* *
***********************IMPORTANT NSOCK LICENSE TERMS***********************
* *
* The nsock parallel socket event library is (C) 1999-2011 Insecure.Com *
* LLC This library is free software; you may redistribute and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; Version 2. This guarantees *
* your right to use, modify, and redistribute this software under certain *
* conditions. If this license is unacceptable to you, Insecure.Com LLC *
* may be willing to sell alternative licenses (contact *
* sales@insecure.com ). *
* *
* As a special exception to the GPL terms, Insecure.Com LLC grants *
* permission to link the code of this program with any version of the *
* OpenSSL library which is distributed under a license identical to that *
* listed in the included docs/licenses/OpenSSL.txt file, and distribute *
* linked combinations including the two. You must obey the GNU GPL in all *
* respects for all of the code used other than OpenSSL. If you modify *
* this file, you may extend this exception to your version of the file, *
* but you are not obligated to do so. *
* *
* If you received these files with a written license agreement stating *
* terms other than the (GPL) terms above, then that alternative license *
* agreement takes precedence over this comment. *
* *
* Source is provided to this software because we believe users have a *
* right to know exactly what a program is going to do before they run it. *
* This also allows you to audit the software for security holes (none *
* have been found so far). *
* *
* Source code also allows you to port Nmap to new platforms, fix bugs, *
* and add new features. You are highly encouraged to send your changes *
* to nmap-dev@insecure.org for possible incorporation into the main *
* distribution. By sending these changes to Fyodor or one of the *
* Insecure.Org development mailing lists, it is assumed that you are *
* offering the Nmap Project (Insecure.Com LLC) the unlimited, *
* non-exclusive right to reuse, modify, and relicense the code. Nmap *
* will always be available Open Source, but this is important because the *
* inability to relicense code has caused devastating problems for other *
* Free Software projects (such as KDE and NASM). We also occasionally *
* relicense the code to third parties as discussed above. If you wish to *
* specify special license conditions of your contributions, just say so *
* when you send them. *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License v2.0 for more details *
* (http://www.gnu.org/licenses/gpl-2.0.html). *
* *
***************************************************************************/
/* $Id$ */
#ifndef WIN32
#include <sys/select.h>
#endif
#include <errno.h>
#include "nsock_internal.h"
#if HAVE_PCAP
#include "nsock_pcap.h"
#endif
#ifdef WIN32
#define CHECKED_FD_SET FD_SET
#else
#define CHECKED_FD_SET(fd, set) \
do { \
if ((fd) < FD_SETSIZE) { \
FD_SET((fd), (set)); \
} else { \
fatal("%s:%ld: Attempt to FD_SET fd %d, which is not less than" \
" FD_SETSIZE (%d). Try using a lower parallelism.", \
__FILE__, __LINE__, (fd), FD_SETSIZE); \
} \
} while (0)
#endif
#ifdef WIN32
#define CHECKED_FD_CLR FD_CLR
#else
#define CHECKED_FD_CLR(fd, set) \
do { \
if ((fd) < FD_SETSIZE) { \
FD_CLR((fd), (set)); \
} else { \
fatal("%s:%ld: Attempt to FD_CLR fd %d, which is not less than" \
" FD_SETSIZE (%d). Try using a lower parallelism.", \
__FILE__, __LINE__, (fd), FD_SETSIZE); \
} \
} while (0)
#endif
/* --- ENGINE INTERFACE PROTOTYPES --- */
static int select_init(mspool *nsp);
static void select_destroy(mspool *nsp);
static int select_iod_register(mspool *nsp, msiod *iod, int ev);
static int select_iod_unregister(mspool *nsp, msiod *iod);
static int select_iod_modify(mspool *nsp, msiod *iod, int ev_set, int ev_clr);
static int select_loop(mspool *nsp, int msec_timeout);
/* ---- ENGINE DEFINITION ---- */
struct io_engine engine_select = {
"select",
select_init,
select_destroy,
select_iod_register,
select_iod_unregister,
select_iod_modify,
select_loop
};
/* --- INTERNAL PROTOTYPES --- */
static void iterate_through_event_lists(mspool *nsp);
/* defined in nsock_core.c */
void process_event(mspool *nsp, gh_list *evlist, msevent *nse, int ev);
void process_iod_events(mspool *nsp, msiod *nsi, int ev);
#if HAVE_PCAP
int pcap_read_on_nonselect(mspool *nsp);
#endif
/* defined in nsock_event.c */
void update_first_events(msevent *nse);
extern struct timeval nsock_tod;
/*
* Engine specific data structure
*/
struct select_engine_info {
/* Descriptors from which have pending READ events */
fd_set fds_master_r;
/* Descriptors which we are tryint to WRITE to */
fd_set fds_master_w;
/* looking for exceptional events -- used with connect */
fd_set fds_master_x;
/* For keeping track of the select results */
fd_set fds_results_r, fds_results_w, fds_results_x;
/* The highest sd we have set in any of our fd_set's (max_sd + 1 is used in
* select() calls). Note that it can be -1, when there are no valid sockets */
int max_sd;
};
int select_init(mspool *nsp) {
struct select_engine_info *sinfo;
sinfo = (struct select_engine_info *)safe_malloc(sizeof(struct select_engine_info));
FD_ZERO(&sinfo->fds_master_r);
FD_ZERO(&sinfo->fds_master_w);
FD_ZERO(&sinfo->fds_master_x);
sinfo->max_sd = -1;
nsp->engine_data = (void *)sinfo;
return 1;
}
void select_destroy(mspool *nsp) {
assert(nsp->engine_data != NULL);
free(nsp->engine_data);
}
int select_iod_register(mspool *nsp, msiod *iod, int ev) {
assert(!IOD_PROPGET(iod, IOD_REGISTERED));
iod->watched_events = ev;
select_iod_modify(nsp, iod, ev, EV_NONE);
IOD_PROPSET(iod, IOD_REGISTERED);
return 1;
}
int select_iod_unregister(mspool *nsp, msiod *iod) {
struct select_engine_info *sinfo = (struct select_engine_info *)nsp->engine_data;
iod->watched_events = EV_NONE;
/* some IODs can be unregistered here if they're associated to an event that was
* immediately completed */
if (IOD_PROPGET(iod, IOD_REGISTERED)) {
#if HAVE_PCAP
if (iod->pcap) {
int sd = ((mspcap *)iod->pcap)->pcap_desc;
if (sd >= 0) {
CHECKED_FD_CLR(sd, &sinfo->fds_master_r);
CHECKED_FD_CLR(sd, &sinfo->fds_results_r);
}
} else
#endif
{
CHECKED_FD_CLR(iod->sd, &sinfo->fds_master_r);
CHECKED_FD_CLR(iod->sd, &sinfo->fds_master_w);
CHECKED_FD_CLR(iod->sd, &sinfo->fds_results_r);
CHECKED_FD_CLR(iod->sd, &sinfo->fds_results_w);
}
if (sinfo->max_sd == iod->sd)
sinfo->max_sd--;
IOD_PROPCLR(iod, IOD_REGISTERED);
}
return 1;
}
int select_iod_modify(mspool *nsp, msiod *iod, int ev_set, int ev_clr) {
int sd;
struct select_engine_info *sinfo = (struct select_engine_info *)nsp->engine_data;
assert((ev_set & ev_clr) == 0);
iod->watched_events |= ev_set;
iod->watched_events &= ~ev_clr;
sd = nsi_getsd(iod);
/* -- set events -- */
if (ev_set & EV_READ)
CHECKED_FD_SET(sd, &sinfo->fds_master_r);
if (ev_set & EV_WRITE)
CHECKED_FD_SET(sd, &sinfo->fds_master_w);
if (ev_set & EV_EXCEPT)
CHECKED_FD_SET(sd, &sinfo->fds_master_x);
/* -- clear events -- */
if (ev_clr & EV_READ)
CHECKED_FD_CLR(sd, &sinfo->fds_master_r);
if (ev_clr & EV_WRITE)
CHECKED_FD_CLR(sd, &sinfo->fds_master_w);
if (ev_clr & EV_EXCEPT)
CHECKED_FD_CLR(sd, &sinfo->fds_master_x);
/* -- update max_sd -- */
if (ev_set != EV_NONE)
sinfo->max_sd = MAX(sinfo->max_sd,sd);
else if (ev_clr != EV_NONE && iod->events_pending == 1 && (sinfo->max_sd == sd))
sinfo->max_sd--;
return 1;
}
int select_loop(mspool *nsp, int msec_timeout) {
int results_left = 0;
int event_msecs; /* msecs before an event goes off */
int combined_msecs;
int sock_err = 0;
struct timeval select_tv;
struct timeval *select_tv_p;
struct select_engine_info *sinfo = (struct select_engine_info *)nsp->engine_data;
assert(msec_timeout >= -1);
if (nsp->events_pending == 0)
return 0; /* No need to wait on 0 events ... */
do {
if (nsp->tracelevel > 6)
nsock_trace(nsp, "wait_for_events");
if (nsp->next_ev.tv_sec == 0)
event_msecs = -1; /* None of the events specified a timeout */
else
event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nsp->next_ev, nsock_tod));
#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
/* Force a low timeout when capturing packets on systems where
* the pcap descriptor is not select()able. */
if (GH_LIST_COUNT(&nsp->pcap_read_events))
if (event_msecs > PCAP_POLL_INTERVAL)
event_msecs = PCAP_POLL_INTERVAL;
#endif
#endif
/* We cast to unsigned because we want -1 to be very high (since it means no
* timeout) */
combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout);
/* Set up the timeval pointer we will give to select() */
memset(&select_tv, 0, sizeof(select_tv));
if (combined_msecs > 0) {
select_tv.tv_sec = combined_msecs / 1000;
select_tv.tv_usec = (combined_msecs % 1000) * 1000;
select_tv_p = &select_tv;
} else if (combined_msecs == 0) {
/* we want the tv_sec and tv_usec to be zero but they already are from bzero */
select_tv_p = &select_tv;
} else {
assert(combined_msecs == -1);
select_tv_p = NULL;
}
#if HAVE_PCAP
/* do non-blocking read on pcap devices that doesn't support select()
* If there is anything read, don't do usleep() or select(), just leave this loop */
if (pcap_read_on_nonselect(nsp)) {
/* okay, something was read. */
} else
#endif
{
/* Set up the descriptors for select */
sinfo->fds_results_r = sinfo->fds_master_r;
sinfo->fds_results_w = sinfo->fds_master_w;
sinfo->fds_results_x = sinfo->fds_master_x;
results_left = fselect(sinfo->max_sd + 1, &sinfo->fds_results_r,
&sinfo->fds_results_w, &sinfo->fds_results_x, select_tv_p);
if (results_left == -1)
sock_err = socket_errno();
}
gettimeofday(&nsock_tod, NULL); /* Due to usleep or select delay */
} while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occured */
if (results_left == -1 && sock_err != EINTR) {
nsock_trace(nsp, "nsock_loop error %d: %s", sock_err, socket_strerror(sock_err));
nsp->errnum = sock_err;
return -1;
}
iterate_through_event_lists(nsp);
return 1;
}
/* ---- INTERNAL FUNCTIONS ---- */
/* Iterate through all the event lists (such as connect_events, read_events,
* timer_events, etc) and take action for those that have completed (due to
* timeout, i/o, etc) */
void iterate_through_event_lists(mspool *nsp) {
gh_list_elem *current, *next, *last, *timer_last;
struct select_engine_info *sinfo = (struct select_engine_info *)nsp->engine_data;
/* Clear it -- We will find the next event as we go through the list */
nsp->next_ev.tv_sec = 0;
last = GH_LIST_LAST_ELEM(&nsp->active_iods);
timer_last = GH_LIST_LAST_ELEM(&nsp->timer_events);
for (current = GH_LIST_FIRST_ELEM(&nsp->active_iods);
current != NULL && GH_LIST_ELEM_PREV(current) != last; current = next) {
msiod *nsi = (msiod *)GH_LIST_ELEM_DATA(current);
if (nsi->state != NSIOD_STATE_DELETED && nsi->events_pending) {
int sd, evmask = EV_NONE;
#if HAVE_PCAP
if (nsi->pcap)
sd = ((mspcap *)nsi->pcap)->pcap_desc;
else
#endif
sd = nsi->sd;
if (FD_ISSET(sd, &sinfo->fds_results_r))
evmask |= EV_READ;
if (FD_ISSET(sd, &sinfo->fds_results_w))
evmask |= EV_WRITE;
if (FD_ISSET(sd, &sinfo->fds_results_x))
evmask |= EV_EXCEPT;
process_iod_events(nsp, nsi, evmask);
}
next = GH_LIST_ELEM_NEXT(current);
if (nsi->state == NSIOD_STATE_DELETED) {
gh_list_remove_elem(&nsp->active_iods, current);
gh_list_prepend(&nsp->free_iods, nsi);
}
}
/* iterate through timers */
for (current = GH_LIST_FIRST_ELEM(&nsp->timer_events);
current != NULL && GH_LIST_ELEM_PREV(current) != timer_last; current = next) {
msevent *nse = (msevent *)GH_LIST_ELEM_DATA(current);
process_event(nsp, &nsp->timer_events, nse, EV_NONE);
next = GH_LIST_ELEM_NEXT(current);
if (nse->event_done)
gh_list_remove_elem(&nsp->timer_events, current);
}
}

View File

@@ -1,4 +1,3 @@
/***************************************************************************
* error.c -- a few simple routines for dealing with errors (quitting, *
* 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);
}

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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
View File

@@ -0,0 +1,107 @@
/***************************************************************************
* nsock_engines.c -- This contains the functions and definitions to *
* manage the list of available IO engines. Each IO engine leverages a *
* specific IO notification function to wait for events. Nsock will try *
* to use the most efficient engine for your system. *
* *
***********************IMPORTANT NSOCK LICENSE TERMS***********************
* *
* The nsock parallel socket event library is (C) 1999-2011 Insecure.Com *
* LLC This library is free software; you may redistribute and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; Version 2. This guarantees *
* your right to use, modify, and redistribute this software under certain *
* conditions. If this license is unacceptable to you, Insecure.Com LLC *
* may be willing to sell alternative licenses (contact *
* sales@insecure.com ). *
* *
* As a special exception to the GPL terms, Insecure.Com LLC grants *
* permission to link the code of this program with any version of the *
* OpenSSL library which is distributed under a license identical to that *
* listed in the included docs/licenses/OpenSSL.txt file, and distribute *
* linked combinations including the two. You must obey the GNU GPL in all *
* respects for all of the code used other than OpenSSL. If you modify *
* this file, you may extend this exception to your version of the file, *
* but you are not obligated to do so. *
* *
* If you received these files with a written license agreement stating *
* terms other than the (GPL) terms above, then that alternative license *
* agreement takes precedence over this comment. *
* *
* Source is provided to this software because we believe users have a *
* right to know exactly what a program is going to do before they run it. *
* This also allows you to audit the software for security holes (none *
* have been found so far). *
* *
* Source code also allows you to port Nmap to new platforms, fix bugs, *
* and add new features. You are highly encouraged to send your changes *
* to nmap-dev@insecure.org for possible incorporation into the main *
* distribution. By sending these changes to Fyodor or one of the *
* Insecure.Org development mailing lists, it is assumed that you are *
* offering the Nmap Project (Insecure.Com LLC) the unlimited, *
* non-exclusive right to reuse, modify, and relicense the code. Nmap *
* will always be available Open Source, but this is important because the *
* inability to relicense code has caused devastating problems for other *
* Free Software projects (such as KDE and NASM). We also occasionally *
* relicense the code to third parties as discussed above. If you wish to *
* specify special license conditions of your contributions, just say so *
* when you send them. *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License v2.0 for more details *
* (http://www.gnu.org/licenses/gpl-2.0.html). *
* *
***************************************************************************/
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "nsock_config.h"
#endif
#include "nsock_internal.h"
#if HAVE_EPOLL
extern struct io_engine engine_epoll;
#define ENGINE_EPOLL &engine_epoll,
#else
#define ENGINE_EPOLL
#endif /* HAVE_EPOLL */
/* select() based engine is the fallback engine, we assume it's always available */
extern struct io_engine engine_select;
#define ENGINE_SELECT &engine_select,
/* Available IO engines. This depends on which IO management interfaces are
* available on your system. Engines must be sorted by order of preference */
static struct io_engine *available_engines[] = {
ENGINE_EPOLL
ENGINE_SELECT
NULL
};
struct io_engine *get_io_engine(const char *engine_hint) {
struct io_engine *engine = NULL;
int i;
if (!engine_hint) {
engine = available_engines[0];
} else {
for (i = 0; available_engines[i] != NULL; i++)
if (strcmp(engine_hint, available_engines[i]->name) == 0) {
engine = available_engines[i];
break;
}
}
if (!engine)
fatal("No suitable IO engine found! (%s)\n",
engine_hint ? engine_hint : "no hint");
return engine;
}

View File

@@ -86,55 +86,106 @@ int nse_eof(nsock_event nse) {
}
/* Obtains the nsock_iod (see below) associated with the event. Note that
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) {
}
}

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -1,3 +1,60 @@
/***************************************************************************
* nsock_pcap.c -- This contains pcap operations functions from *
* the nsock parallel socket event library *
* *
***********************IMPORTANT NSOCK LICENSE TERMS***********************
* *
* The nsock parallel socket event library is (C) 1999-2011 Insecure.Com *
* LLC This library is free software; you may redistribute and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; Version 2. This guarantees *
* your right to use, modify, and redistribute this software under certain *
* conditions. If this license is unacceptable to you, Insecure.Com LLC *
* may be willing to sell alternative licenses (contact *
* sales@insecure.com ). *
* *
* As a special exception to the GPL terms, Insecure.Com LLC grants *
* permission to link the code of this program with any version of the *
* OpenSSL library which is distributed under a license identical to that *
* listed in the included docs/licenses/OpenSSL.txt file, and distribute *
* linked combinations including the two. You must obey the GNU GPL in all *
* respects for all of the code used other than OpenSSL. If you modify *
* this file, you may extend this exception to your version of the file, *
* but you are not obligated to do so. *
* *
* If you received these files with a written license agreement stating *
* terms other than the (GPL) terms above, then that alternative license *
* agreement takes precedence over this comment. *
* *
* Source is provided to this software because we believe users have a *
* right to know exactly what a program is going to do before they run it. *
* This also allows you to audit the software for security holes (none *
* have been found so far). *
* *
* Source code also allows you to port Nmap to new platforms, fix bugs, *
* and add new features. You are highly encouraged to send your changes *
* to nmap-dev@insecure.org for possible incorporation into the main *
* distribution. By sending these changes to Fyodor or one of the *
* Insecure.Org development mailing lists, it is assumed that you are *
* offering the Nmap Project (Insecure.Com LLC) the unlimited, *
* non-exclusive right to reuse, modify, and relicense the code. Nmap *
* will always be available Open Source, but this is important because the *
* inability to relicense code has caused devastating problems for other *
* Free Software projects (such as KDE and NASM). We also occasionally *
* relicense the code to third parties as discussed above. If you wish to *
* specify special license conditions of your contributions, just say so *
* when you send them. *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License v2.0 for more details *
* (http://www.gnu.org/licenses/gpl-2.0.html). *
* *
***************************************************************************/
/* $Id: $ */
#include "nsock.h"
#include "nsock_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 */

View File

@@ -1,3 +1,60 @@
/***************************************************************************
* nsock_pcap.h -- Header for pcap operations functions from *
* the nsock parallel socket event library *
* *
***********************IMPORTANT NSOCK LICENSE TERMS***********************
* *
* The nsock parallel socket event library is (C) 1999-2011 Insecure.Com *
* LLC This library is free software; you may redistribute and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; Version 2. This guarantees *
* your right to use, modify, and redistribute this software under certain *
* conditions. If this license is unacceptable to you, Insecure.Com LLC *
* may be willing to sell alternative licenses (contact *
* sales@insecure.com ). *
* *
* As a special exception to the GPL terms, Insecure.Com LLC grants *
* permission to link the code of this program with any version of the *
* OpenSSL library which is distributed under a license identical to that *
* listed in the included docs/licenses/OpenSSL.txt file, and distribute *
* linked combinations including the two. You must obey the GNU GPL in all *
* respects for all of the code used other than OpenSSL. If you modify *
* this file, you may extend this exception to your version of the file, *
* but you are not obligated to do so. *
* *
* If you received these files with a written license agreement stating *
* terms other than the (GPL) terms above, then that alternative license *
* agreement takes precedence over this comment. *
* *
* Source is provided to this software because we believe users have a *
* right to know exactly what a program is going to do before they run it. *
* This also allows you to audit the software for security holes (none *
* have been found so far). *
* *
* Source code also allows you to port Nmap to new platforms, fix bugs, *
* and add new features. You are highly encouraged to send your changes *
* to nmap-dev@insecure.org for possible incorporation into the main *
* distribution. By sending these changes to Fyodor or one of the *
* Insecure.Org development mailing lists, it is assumed that you are *
* offering the Nmap Project (Insecure.Com LLC) the unlimited, *
* non-exclusive right to reuse, modify, and relicense the code. Nmap *
* will always be available Open Source, but this is important because the *
* inability to relicense code has caused devastating problems for other *
* Free Software projects (such as KDE and NASM). We also occasionally *
* relicense the code to third parties as discussed above. If you wish to *
* specify special license conditions of your contributions, just say so *
* when you send them. *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License v2.0 for more details *
* (http://www.gnu.org/licenses/gpl-2.0.html). *
* *
***************************************************************************/
/* $Id: $ */
#ifndef NSOCK_PCAP_H
#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 */

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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);