nanomsg-0.8-beta/0000775000175000017500000000000012623652617014652 5ustar00travistravis00000000000000nanomsg-0.8-beta/doc/0000775000175000017500000000000012623652617015417 5ustar00travistravis00000000000000nanomsg-0.8-beta/doc/asciidoc.conf0000664000175000017500000000231112623652600020031 0ustar00travistravis00000000000000[paradef-default]
literal-style=template="literalparagraph"
[macros]
(?su)[\\]?(?Plinknanomsg):(?P\S*?)\[(?P.*?)\]=
ifdef::backend-docbook[]
[linknanomsg-inlinemacro]
{0%{target}}
{0#}
{0#{target}{0}}
{0#}
endif::backend-docbook[]
ifdef::backend-xhtml11[]
[linknanomsg-inlinemacro]
{target}{0?({0})}
endif::backend-xhtml11[]
ifdef::doctype-manpage[]
ifdef::backend-docbook[]
[header]
template::[header-declarations]
{mantitle}
{manvolnum}
nanomsg
{version}
nanomsg manual
{manname}
{manpurpose}
endif::backend-docbook[]
endif::doctype-manpage[]
ifdef::backend-xhtml11[]
[footer]
{disable-javascript%}
endif::backend-xhtml11[]
nanomsg-0.8-beta/doc/htmldoc.css0000664000175000017500000000035612623652600017557 0ustar00travistravis00000000000000p {font-family:sans-serif;}
h1,h2,h3,h4,h5,h6 {color:#808080;}
a {color:#000000;}
a:visited {color:#000000;}
dt {color:#000000; font-style: italic;}
tt {color: #000000;}
em {color: #000000;}
strong {color: #000000; font-weight: bold;}
nanomsg-0.8-beta/doc/nanocat.txt0000664000175000017500000001222612623652600017576 0ustar00travistravis00000000000000nanocat(1)
==========
NAME
----
nanocat - a command-line interface to nanomsg
SYNOPSIS
--------
nanocat --req {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ]
nanocat --rep {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-AQ]
nanocat --push {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC]
nanocat --pull {--connect ADDR|--bind ADDR} [-AQ]
nanocat --pub {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC]
nanocat --sub {--connect ADDR|--bind ADDR} [--subscribe PREFIX ...] [-AQ]
nanocat --surveyor {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ]
nanocat --respondent {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-AQ]
nanocat --bus {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ]
nanocat --pair {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ]
In the case symlinks are installed:
nn_req {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ]
nn_rep {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-AQ]
nn_push {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC]
nn_pull {--connect ADDR|--bind ADDR} [-AQ]
nn_pub {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC]
nn_sub {--connect ADDR|--bind ADDR} [--subscribe PREFIX ...] [-AQ]
nn_surveyor {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ]
nn_respondent {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-AQ]
nn_bus {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ]
nn_pair {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ]
DESCRIPTION
-----------
The nanocat is a command-line tool to send and receive data via nanomsg
sockets. It can be used for debugging purposes, sending files through the
network, health checking the system or whatever else you can think of.
OPTIONS
-------
Generic:
*--verbose,-v*::
Increase verbosity of the nanocat
*--silent,-q*::
Decrease verbosity of the nanocat
*--help,-h*::
This help text
Socket Types:
*--push*::
Use NN_PUSH socket type
*--pull*::
Use NN_PULL socket type
*--pub*::
Use NN_PUB socket type
*--sub*::
Use NN_SUB socket type
*--req*::
Use NN_REQ socket type
*--rep*::
Use NN_REP socket type
*--surveyor*::
Use NN_SURVEYOR socket type
*--respondent*::
Use NN_RESPONDENT socket type
*--bus*::
Use NN_BUS socket type
*--pair*::
Use NN_PAIR socket type
Socket Options:
*--bind* 'ADDR'::
Bind socket to the address ADDR
*--connect* 'ADDR'::
Connect socket to the address ADDR
*--bind-ipc,-X* 'PATH'::
Bind socket to the ipc address "ipc://PATH".
*--connect-ipc,-x* 'PATH'::
Connect socket to the ipc address "ipc://PATH".
*--bind-local,-L* 'PORT'::
Bind socket to the tcp address "tcp://127.0.0.1:PORT".
*--connect-local,-l* 'PORT'::
Connect socket to the tcp address "tcp://127.0.0.1:PORT".
*--recv-timeout* 'SEC'::
Set timeout for receiving a message
*--send-timeout* 'SEC'::
Set timeout for sending a message
SUB Socket Options:
*--subscribe* 'PREFIX'::
Subscribe to the prefix PREFIX. Note: socket will be
subscribed to everything (empty prefix) if no prefixes
are specified on the command-line.
Input Options:
*--format* 'FORMAT'::
Use echo format FORMAT (same as the options below)
*--raw*::
Dump message as is (Note: no delimiters are printed)
*--ascii,-A*::
Print ASCII part of message delimited by newline. All
non-ascii characters replaced by dot.
*--quoted,-Q*::
Print each message on separate line in double quotes
with C-like character escaping
*--msgpack*::
Print each message as msgpacked string (raw type). This
is useful for programmatic parsing.
Output Options:
*--interval,-i* 'SEC'::
Send message (or request) every SEC seconds
*--delay,-d* 'SEC'::
Wait for SEC seconds before sending message (useful for one-shot
PUB sockets)
*--data,-D* 'DATA'::
Send DATA to the socket and quit for PUB, PUSH, PAIR,
BUS socket. Use DATA to reply for REP or RESPONDENT
socket. Send DATA as request for REQ or SURVEYOR socket.
*--file,-F* 'PATH'::
Same as --data but get data from file PATH
EXAMPLES
--------
The ping-pong with nn_req/nn_rep sockets (must be run simultaneously):
nanocat --rep --bind tcp://127.0.0.1:1234 --data pong --format ascii
nanocat --req --connect tcp://127.0.0.1:1234 --data ping --format ascii
Or in shorter to write form:
nn_rep -L1234 -Dpong -A
nn_req -l1234 -Dping -A
Do periodic requests once a second:
nn_req -l1234 -Dping -A -i 1
The rep socket that never reply (no -D option), may be used to check if
resending the requests is actually work:
nanocat --rep --connect ipc:///var/run/app/req.socket
Send an output of the ls to whatever would connect to 127.0.0.1:1234 then exit:
ls | nanocat --push -L1234 -F-
Send heartbeats to imaginary monitoring service:
nanocat --pub --connect tpc://monitoring.example.org -D"I am alive!" --interval 10
SEE ALSO
--------
linknanomsg:nanomsg[7]
AUTHORS
-------
Paul Colomiets
nanomsg-0.8-beta/doc/tcpmuxd.txt0000664000175000017500000000132612623652600017636 0ustar00travistravis00000000000000tcpmuxd(1)
==========
NAME
----
tcpmuxd - TCP muliplexer daemon
SYNOPSIS
--------
tcpmuxd PORT
DESCRIPTION
-----------
THIS IS AN EXPERIMENTAL FEATURE. DO NOT USE.
THE FUNCTIONALITY IS SUBJECT TO CHANGE WITHOUT PRIOR NOTICE.
TCP multiplexer daemon listens on all network interfaces on TCP port specified
by argument PORT. On each incoming connection it performs TCPMUX handshake as
defined in RFC 1078. Then it hands the connection to the application bound to
the service name specified by the client (see linknanomsg:tcpmux[7] for more
details).
OPTIONS
-------
There are no options defined.
SEE ALSO
--------
linknanomsg:tcpmux[7]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_errno.txt0000664000175000017500000000224712623652600017775 0ustar00travistravis00000000000000nn_errno(3)
===========
NAME
----
nn_errno - retrieve the current errno
SYNOPSIS
--------
*#include *
*int nn_errno (void);*
DESCRIPTION
-----------
Returns value of 'errno' for the current thread.
On most systems, 'errno' can be accessed directly and this function is not
needed. However, on Windows, there are multiple implementations of the CRT
library (single-threaded, multi-threaded, release, debug) and each of them
has its own instance of 'errno'. Thus, if nanomsg library and the application
that uses it link with different versions of CRT library, they don't share
same instance of 'errno'. Consequently, error codes set by nanomsg cannot be
accessed by the application. To overcome this problem, application can use
_nn_errno()_ function to retrieve the nanomsg's value of 'errno'.
RETURN VALUE
------------
Returns value of 'errno' for the current thread.
ERRORS
------
No errors are defined.
EXAMPLE
-------
----
rc = nn_send (s, "ABC", 3, 0);
if (rc < 0)
printf ("nn_send failed with error code %d\n", nn_errno ());
----
SEE ALSO
--------
linknanomsg:nn_strerror[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_strerror.txt0000664000175000017500000000137612623652600020534 0ustar00travistravis00000000000000nn_strerror(3)
==============
NAME
----
nn_strerror - convert an error number into human-readable string
SYNOPSIS
--------
*#include *
*const char *nn_strerror (int 'errnum');*
DESCRIPTION
-----------
Converts error number (errno) into a human-readable string. As opposed to
'strerror(3)' this function handles nanomsg-specific errors in addition
to standard system errors.
RETURN VALUE
------------
Return error message string.
ERRORS
------
No errors are defined.
EXAMPLE
-------
----
rc = nn_send (s, "ABC", 3, 0);
if (rc < 0)
printf ("nn_send failed: %s\n", nn_strerror (errno));
----
SEE ALSO
--------
linknanomsg:nn_errno[3]
linknanomsg:nn_symbol[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_symbol.txt0000664000175000017500000000353712623652600020160 0ustar00travistravis00000000000000nn_symbol(3)
============
NAME
----
nn_symbol - query the names and values of nanomsg symbols
SYNOPSIS
--------
*#include *
*const char *nn_symbol (int 'i', int '*value');*
DESCRIPTION
-----------
Retrieves the symbol name and value at index 'i'. Indices start at 0. An index
has no significance to its associated symbol; the mappings may change between
library versions.
Typically a client will iterate through the symbols until nn_symbol returns
NULL in order to collect all the symbols.
All symbols exposed by 'nn_symbol' are available directly in the C API,
generally as preprocessor macros. Thus, this function is useful mostly for
language bindings that can't parse the header file and rely on retrieving the
symbols in the runtime.
Note that the NN_MSG symbol is not exported by the _nn_symbol_ function. First,
it is a pointer rather than an integer; second, the symbol is not supposed to
be exported from language bindings to the user. Instead, language bindings
should provide the zero-copy functionality in a language-specific way, if at
all (zero-copy functionality may not make sense for some languages/bindings).
RETURN VALUE
------------
If 'i' is valid, returns the name of the symbol at that index. If the pointer
'value' is not NULL, the symbol's value is stored there.
If 'i' is out-of-range, nn_symbol returns NULL and sets 'errno' to EINVAL.
ERRORS
------
*EINVAL*::
The passed index 'i' was out-of-range; it was less than zero or greater-than-or-
equal-to the number of symbols.
EXAMPLE
-------
----
int value, i;
for (i = 0; ; ++i) {
const char* name = nn_symbol (i, &value);
if (name == NULL) break;
printf ("'%s' = %d\n", name, value);
}
----
SEE ALSO
--------
linknanomsg:nn_symbol_info[3]
linknanomsg:nn_errno[3]
linknanomsg:nn_strerror[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Evan Wies
nanomsg-0.8-beta/doc/nn_symbol_info.txt0000664000175000017500000001035412623652600021166 0ustar00travistravis00000000000000nn_symbol_info(3)
=================
NAME
----
nn_symbol_info - query the names and properties of nanomsg symbols
SYNOPSIS
--------
*#include *
*int nn_symbol_info (int 'i', struct nn_symbol_properties '*buf', int 'buflen');*
DESCRIPTION
-----------
Retrieves the symbol name and value at index 'i'. Indices start at 0. An index
has no significance to its associated symbol; the mappings may change between
library versions.
The nn_symbol_properties has the following definition:
----
struct nn_symbol_properties {
/* The constant value */
int value;
/* The constant name */
const char* name;
/* The constant namespace, or zero for namespaces themselves */
int ns;
/* The option type for socket option constants */
int type;
/* The unit for the option value for socket option constants */
int unit;
};
----
More structure members may be added in future, but input pointer will be
written only up to 'buflen' so ABI is forward-compatible.
Typically a client will iterate through the symbols until nn_symbol_info
returns NULL in order to collect all the symbols.
All symbols exposed by 'nn_symbol_info' are available directly in the C API,
generally as preprocessor macros. Thus, this function is useful mostly for
language bindings that can't parse the header file and rely on retrieving the
symbols in the runtime.
Note that the NN_MSG symbol is not exported by the 'nn_symbol_info' function.
First, it is a pointer rather than an integer; second, the symbol is not
supposed to be exported from language bindings to the user. Instead, language
bindings should provide the zero-copy functionality in a language-specific way,
if at all (zero-copy functionality may not make sense for some
languages/bindings).
AVAILABLE NAMESPACES
--------------------
*NN_NS_NAMESPACE*::
Equals to zero and denotes the NN_NS_* constants themselves
*NN_NS_VERSION*::
Nanomsg version constants
*NN_NS_DOMAIN*::
Socket domain (or address family) constants AF_SP, AF_SP_RAW
*NN_NS_TRANSPORT*::
Transport name constants (used for socket options mainly)
*NN_NS_PROTOCOL*::
Socket protocol constants
*NN_NS_OPTION_LEVEL*::
Socket option level constants (NN_SOL_SOCKET)
*NN_NS_SOCKET_OPTION*::
Socket options for NN_SOL_SOCKET level
*NN_NS_TRANSPORT_OPTION*::
Socket options for transport level (used with transport constants)
*NN_NS_OPTION_TYPE*::
The option types (described below)
*NN_NS_FLAG*::
The nn_send/nn_recv flags (only NN_DONTWAIT for now)
*NN_NS_ERROR*::
The errno values
*NN_NS_LIMIT*::
Various nanomsg limits (only NN_SOCKADDR_MAX for now)
*NN_NS_EVENT*::
Event flags (bit mask) for use with nn_poll (NN_POLLIN, NN_POLLOUT)
AVAILABLE OPTION TYPES
----------------------
*NN_TYPE_NONE*::
No type, is returned for constants that are not socket options
*NN_TYPE_INT*::
The integer type
*NN_TYPE_STR*::
String (char *) type
More types may be added in future nanomsg. You may enumerate all of them using
the 'nn_symbol_info' itself by checking 'NN_NS_OPTION_TYPE' namespace.
AVAILABLE OPTION UNITS
----------------------
*NN_UNIT_NONE*::
No unit, is returned for constants that are not socket options, or do not have
any meaningful unit (strings, integer values)
*NN_UNIT_BYTES*::
The option value is expressed in bytes
*NN_UNIT_MILLISECONDS*::
The option value is expressed in milliseconds
*NN_UNIT_PRIORITY*::
The option value is a priority, an integer from 1 to 16
*NN_UNIT_BOOLEAN*::
The option value is boolean, an integer 0 or 1
More types may be added in future nanomsg. You may enumerate all of them using
the 'nn_symbol_info' itself by checking 'NN_NS_OPTION_TYPE' namespace.
RETURN VALUE
------------
If 'i' is valid, returns the number of bytes stored at the structure. The
maximum value that can be returned is 'buflen'.
If 'i' is out-of-range, nn_symbol_info returns zero.
EXAMPLE
-------
----
int i;
for (i = 0; ; ++i) {
struct nn_symbol_properties sym;
int rc = nn_symbol_info (i, &sym, sizeof (sym));
if(rc == 0)
break;
assert (rc == sizeof (sym));
printf ("'%s' = %d\n", sym.name, sym.value);
}
----
SEE ALSO
--------
linknanomsg:nn_symbol[3]
linknanomsg:nn_errno[3]
linknanomsg:nn_strerror[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Paul Colomiets
Garrett D'Amore
nanomsg-0.8-beta/doc/nn_term.txt0000664000175000017500000000227112623652600017614 0ustar00travistravis00000000000000nn_term(3)
==========
NAME
----
nn_term - notify all sockets about process termination
SYNOPSIS
--------
*#include *
*void nn_term (void);*
DESCRIPTION
-----------
To help with shutdown of multi-threaded programs nanomsg provides the
_nn_term()_ function which informs all the open sockets that process
termination is underway.
If a socket is blocked inside a blocking function, such as
linknanomsg:nn_recv[3], it will be unblocked and ETERM error will be returned
to the user. Similarly, any subsequent attempt to invoke a socket function other
than linknanomsg:nn_close[3] after _nn_term()_ was called will result
in ETERM error.
If waiting for _NN_SNDFD_ or _NN_RCVFD_ using a polling function, such as
_poll()_ or _select()_, the call will unblock with both _NN_SNDFD_ and
_NN_RCVFD_ signaled.
The _nn_term()_ function itself is non-blocking.
EXAMPLE
-------
----
s = nn_socket (AF_SP, NN_PAIR);
nn_term ();
rc = nn_send (s, "ABC", 3, 0);
assert (rc == -1 && errno == ETERM);
----
SEE ALSO
--------
linknanomsg:nn_close[3]
linknanomsg:nn_send[3]
linknanomsg:nn_recv[3]
linknanomsg:nn_getsockopt[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_allocmsg.txt0000664000175000017500000000314012623652600020442 0ustar00travistravis00000000000000nn_allocmsg(3)
==============
NAME
----
nn_allocmsg - allocate a message
SYNOPSIS
--------
*#include *
*void *nn_allocmsg (size_t 'size', int 'type');*
DESCRIPTION
-----------
Allocate a message of the specified 'size' to be sent in zero-copy fashion.
The content of the message is undefined after allocation and it should be filled
in by the user. While linknanomsg:nn_send[3] and linknanomsg:nn_sendmsg[3] allow
to send arbitrary buffers, buffers allocated using _nn_allocmsg()_ can be more
efficient for large messages as they allow for using zero-copy techniques.
'type' parameter specifies type of allocation mechanism to use. Zero is the
default one, however, individual transport mechanisms may define their
own allocation mechanisms, such as allocating in shared memory or allocating
a memory block pinned down to a physical memory address. Such allocation,
when used with the transport that defines them, should be more efficient
than the default allocation mechanism.
RETURN VALUE
------------
If the function succeeds pointer to newly allocated buffer is returned.
Otherwise, NULL is returned and 'errno' is set to to one of the values
defined below.
ERRORS
------
*EINVAL*::
Supplied allocation 'type' is invalid.
*ENOMEM*::
Not enough memory to allocate the message.
EXAMPLE
-------
----
void *buf = nn_allocmsg (12, 0);
memcpy (buf, "Hello world!", 12);
nn_send (s, &buf, NN_MSG, 0);
----
SEE ALSO
--------
linknanomsg:nn_freemsg[3]
linknanomsg:nn_reallocmsg[3]
linknanomsg:nn_send[3]
linknanomsg:nn_sendmsg[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_reallocmsg.txt0000664000175000017500000000167412623652600021003 0ustar00travistravis00000000000000nn_reallocmsg(3)
================
NAME
----
nn_reallocmsg - reallocate a message
SYNOPSIS
--------
*#include *
*void *nn_reallocmsg (void *'msg', size_t 'size');*
DESCRIPTION
-----------
Reallocate a message previously allocated by linknanomsg:nn_allocmsg[3] or
received from a peer using NN_MSG mechanism.
Note that as with the standard _realloc_, the operation may involve copying
the data in the buffer.
RETURN VALUE
------------
If the function succeeds pointer to newly allocated buffer is returned.
Otherwise, NULL is returned and 'errno' is set to to one of the values
defined below.
ERRORS
------
*ENOMEM*::
Not enough memory to allocate the message.
EXAMPLE
-------
----
void *buf = nn_allocmsg (12, 0);
void *newbuf = nn_reallocmsg (buf, 20);
nn_freemsg (newbuf);
----
SEE ALSO
--------
linknanomsg:nn_allocmsg[3]
linknanomsg:nn_freemsg[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_freemsg.txt0000664000175000017500000000204112623652600020270 0ustar00travistravis00000000000000nn_freemsg(3)
=============
NAME
----
nn_freemsg - deallocate a message
SYNOPSIS
--------
*#include *
*int nn_freemsg (void '*msg');*
DESCRIPTION
-----------
Deallocates a message allocated using linknanomsg:nn_allocmsg[3] function or
received via linknanomsg:nn_recv[3] or linknanomsg:nn_recvmsg[3] function.
While linknanomsg:nn_recv[3] and linknanomsg:nn_recvmsg[3] allow to receive data
into arbitrary buffers, using library-allocated buffers can be more
efficient for large messages as it allows for using zero-copy techniques.
RETURN VALUE
------------
If the function succeeds zero is returned. Otherwise, -1 is
returned and 'errno' is set to to one of the values defined below.
ERRORS
------
*EFAULT*::
The message pointer is invalid.
EXAMPLE
-------
----
void *buf;
nn_recv (s, &buf, NN_MSG, 0);
nn_freemsg (buf);
----
SEE ALSO
--------
linknanomsg:nn_allocmsg[3]
linknanomsg:nn_reallocmsg[3]
linknanomsg:nn_recv[3]
linknanomsg:nn_recvmsg[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_socket.txt0000664000175000017500000000435212623652600020137 0ustar00travistravis00000000000000nn_socket(3)
============
NAME
----
nn_socket - create an SP socket
SYNOPSIS
--------
*#include *
*int nn_socket (int 'domain', int 'protocol');*
DESCRIPTION
-----------
Creates an SP socket with specified 'domain' and 'protocol'. Returns a file
descriptor for the newly created socket.
Following domains are defined at the moment:
*AF_SP*::
Standard full-blown SP socket.
*AF_SP_RAW*::
Raw SP socket. Raw sockets omit the end-to-end functionality found in AF_SP
sockets and thus can be used to implement intermediary devices in SP topologies.
'protocol' parameter defines the type of the socket, which in turn determines
the exact semantics of the socket. Check manual pages for individual SP
protocols to get the list of available socket types.
The newly created socket is initially not associated with any endpoints.
In order to establish a message flow at least one endpoint has to be added
to the socket using linknanomsg:nn_bind[3] or linknanomsg:nn_connect[3]
function.
Also note that 'type' argument as found in standard _socket(2)_ function is
omitted from _nn_socket_. All the SP sockets are message-based and thus of
_SOCK_SEQPACKET_ type.
RETURN VALUE
------------
If the function succeeds file descriptor of the new socket is returned.
Otherwise, -1 is returned and 'errno' is set to to one of
the values defined below.
Note that file descriptors returned by _nn_socket_ function are not standard
file descriptors and will exhibit undefined behaviour when used with system
functions. Moreover, it may happen that a system file descriptor and file
descriptor of an SP socket will incidentally collide (be equal).
ERRORS
------
*EAFNOSUPPORT*::
Specified address family is not supported.
*EINVAL*::
Unknown protocol.
*EMFILE*::
The limit on the total number of open SP sockets or OS limit for file
descriptors has been reached.
*ETERM*::
The library is terminating.
EXAMPLE
-------
----
int s = nn_socket (AF_SP, NN_PUB);
assert (s >= 0);
----
SEE ALSO
--------
linknanomsg:nn_pubsub[7]
linknanomsg:nn_reqrep[7]
linknanomsg:nn_pipeline[7]
linknanomsg:nn_survey[7]
linknanomsg:nn_bus[7]
linknanomsg:nn_bind[3]
linknanomsg:nn_connect[3]
linknanomsg:nn_close[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_close.txt0000664000175000017500000000205412623652600017751 0ustar00travistravis00000000000000nn_close(3)
===========
NAME
----
nn_close - close an SP socket
SYNOPSIS
--------
*#include *
*int nn_close (int 's');*
DESCRIPTION
-----------
Closes the socket 's'. Any buffered inbound messages that were not yet received
by the application will be discarded. The library will try to deliver any
outstanding outbound messages for the time specified by _NN_LINGER_ socket
option. The call will block in the meantime.
RETURN VALUE
------------
If the function succeeds zero is returned. Otherwise, -1 is
returned and 'errno' is set to to one of the values defined below.
ERRORS
------
*EBADF*::
The provided socket is invalid.
*EINTR*::
Operation was interrupted by a signal. The socket is not fully closed yet.
Operation can be re-started by calling _nn_close()_ again.
EXAMPLE
-------
----
int s = nn_socket (AF_SP, NN_PUB);
assert (s >= 0);
int rc = nn_close (s);
assert (rc == 0);
----
SEE ALSO
--------
linknanomsg:nn_socket[3]
linknanomsg:nn_setsockopt[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_getsockopt.txt0000664000175000017500000001462312623652600021033 0ustar00travistravis00000000000000nn_getsockopt(3)
================
NAME
----
nn_getsockopt - retrieve a socket option
SYNOPSIS
--------
*#include *
*int nn_getsockopt (int 's', int 'level', int 'option', void '*optval', size_t '*optvallen');*
DESCRIPTION
-----------
Retrieves the value for the 'option'. The 'level' argument specifies
the protocol level at which the option resides. For generic socket-level options
use _NN_SOL_SOCKET_ level. For socket-type-specific options use socket type
for 'level' argument (e.g. _NN_SUB_). For transport-specific options use ID of
the transport as the 'level' argument (e.g. _NN_TCP_).
The value is stored in the buffer pointed to by 'optval' argument. Size of the
buffer is specified by the 'optvallen' argument. If the size of the option is
greater than size of the buffer, the value will be silently truncated.
Otherwise, the 'optvallen' will be modified to indicate the actual length of
the option.
__ header defines generic socket-level options
(_NN_SOL_SOCKET_ level). The options are as follows:
*NN_DOMAIN*::
Returns the domain constant as it was passed to _nn_socket()_.
*NN_PROTOCOL*::
Returns the protocol constant as it was passed to _nn_socket()_.
*NN_LINGER*::
Specifies how long the socket should try to send pending outbound messages
after _nn_close()_ have been called, in milliseconds. Negative value means
infinite linger. The type of the option is int. Default value
is 1000 (1 second).
*NN_SNDBUF*::
Size of the send buffer, in bytes. To prevent blocking for messages larger
than the buffer, exactly one message may be buffered in addition to the data
in the send buffer. The type of this option is int. Default value is 128kB.
*NN_RCVBUF*::
Size of the receive buffer, in bytes. To prevent blocking for messages
larger than the buffer, exactly one message may be buffered in addition
to the data in the receive buffer. The type of this option is int. Default
value is 128kB.
*NN_RCVMAXSIZE*::
Maximum message size that can be received, in bytes. Negative value means
that the received size is limited only by available addressable memory. The
type of this option is int. Default is 1024kB.
*NN_SNDTIMEO*::
The timeout for send operation on the socket, in milliseconds. If message
cannot be sent within the specified timeout, EAGAIN error is returned.
Negative value means infinite timeout. The type of the option is int.
Default value is -1.
*NN_RCVTIMEO*::
The timeout for recv operation on the socket, in milliseconds. If message
cannot be received within the specified timeout, EAGAIN error is returned.
Negative value means infinite timeout. The type of the option is int.
Default value is -1.
*NN_RECONNECT_IVL*::
For connection-based transports such as TCP, this option specifies how
long to wait, in milliseconds, when connection is broken before trying
to re-establish it. Note that actual reconnect interval may be randomised
to some extent to prevent severe reconnection storms. The type of the option
is int. Default value is 100 (0.1 second).
*NN_RECONNECT_IVL_MAX*::
This option is to be used only in addition to _NN_RECONNECT_IVL_ option.
It specifies maximum reconnection interval. On each reconnect attempt,
the previous interval is doubled until _NN_RECONNECT_IVL_MAX_ is reached.
Value of zero means that no exponential backoff is performed and reconnect
interval is based only on _NN_RECONNECT_IVL_. If _NN_RECONNECT_IVL_MAX_ is
less than _NN_RECONNECT_IVL_, it is ignored. The type of the option is int.
Default value is 0.
*NN_SNDPRIO*::
Retrieves outbound priority currently set on the socket. This
option has no effect on socket types that send messages to all the peers.
However, if the socket type sends each message to a single peer
(or a limited set of peers), peers with high priority take precedence
over peers with low priority. The type of the option is int. Highest
priority is 1, lowest priority is 16. Default value is 8.
*NN_RCVPRIO*::
Sets inbound priority for endpoints subsequently added to the socket. This
option has no effect on socket types that are not able to receive messages.
When receiving a message, messages from peer with higher priority are
received before messages from peer with lower priority. The type of the
option is int. Highest priority is 1, lowest priority is 16. Default value
is 8.
*NN_IPV4ONLY*::
If set to 1, only IPv4 addresses are used. If set to 0, both IPv4 and IPv6
addresses are used. The type of the option is int. Default value is 1.
*NN_SNDFD*::
Retrieves a file descriptor that is readable when a message can be sent
to the socket. The descriptor should be used only for polling and never
read from or written to. The type of the option is same as the type of
file descriptor on the platform. That is, int on POSIX-complaint platforms
and SOCKET on Windows. The descriptor becomes invalid and should not be
used any more once the socket is closed. This socket option is not available
for unidirectional recv-only socket types.
*NN_RCVFD*::
Retrieves a file descriptor that is readable when a message can be received
from the socket. The descriptor should be used only for polling and never
read from or written to. The type of the option is same as the type of
file descriptor on the platform. That is, int on POSIX-complaint platforms
and SOCKET on Windows. The descriptor becomes invalid and should not be
used any more once the socket is closed. This socket option is not available
for unidirectional send-only socket types.
*NN_SOCKET_NAME*::
Socket name for error reporting and statistics. The type of the option
is string. Default value is "N" where N is socket integer.
*This option is experimental, see linknanomsg:nn_env[7] for details*
RETURN VALUE
------------
If the function succeeds zero is returned. Otherwise, -1 is
returned and 'errno' is set to to one of the values defined below.
ERRORS
------
*EBADF*::
The provided socket is invalid.
*ENOPROTOOPT*::
The option is unknown at the level indicated.
*ETERM*::
The library is terminating.
EXAMPLE
-------
----
int linger;
size_t sz = sizeof (linger);
nn_getsockopt (s, NN_SOL_SOCKET, NN_LINGER, &linger, &sz);
----
SEE ALSO
--------
linknanomsg:nn_socket[3]
linknanomsg:nn_setsockopt[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_setsockopt.txt0000664000175000017500000001216212623652600021043 0ustar00travistravis00000000000000nn_setsockopt(3)
================
NAME
----
nn_setsockopt - set a socket option
SYNOPSIS
--------
*#include *
*int nn_setsockopt (int 's', int 'level', int 'option', const void '*optval', size_t 'optvallen');*
DESCRIPTION
-----------
Sets the value of the 'option'. The 'level' argument specifies the protocol
level at which the option resides. For generic socket-level options use
_NN_SOL_SOCKET_ level. For socket-type-specific options use socket type
for 'level' argument (e.g. _NN_SUB_). For transport-specific options use ID of
the transport as the 'level' argument (e.g. _NN_TCP_).
The new value is pointed to by 'optval' argument. Size of the option is
specified by the 'optvallen' argument.
__ header defines generic socket-level options
(_NN_SOL_SOCKET_ level). The options are as follows:
*NN_LINGER*::
Specifies how long the socket should try to send pending outbound messages
after _nn_close()_ have been called, in milliseconds. Negative value means
infinite linger. The type of the option is int. Default value
is 1000 (1 second).
*NN_SNDBUF*::
Size of the send buffer, in bytes. To prevent blocking for messages larger
than the buffer, exactly one message may be buffered in addition to the data
in the send buffer. The type of this option is int. Default value is 128kB.
*NN_RCVBUF*::
Size of the receive buffer, in bytes. To prevent blocking for messages
larger than the buffer, exactly one message may be buffered in addition
to the data in the receive buffer. The type of this option is int. Default
value is 128kB.
*NN_RCVMAXSIZE*::
Maximum message size that can be received, in bytes. Negative value means
that the received size is limited only by available addressable memory. The
type of this option is int. Default is 1024kB.
*NN_SNDTIMEO*::
The timeout for send operation on the socket, in milliseconds. If message
cannot be sent within the specified timeout, EAGAIN error is returned.
Negative value means infinite timeout. The type of the option is int.
Default value is -1.
*NN_RCVTIMEO*::
The timeout for recv operation on the socket, in milliseconds. If message
cannot be received within the specified timeout, EAGAIN error is returned.
Negative value means infinite timeout. The type of the option is int.
Default value is -1.
*NN_RECONNECT_IVL*::
For connection-based transports such as TCP, this option specifies how
long to wait, in milliseconds, when connection is broken before trying
to re-establish it. Note that actual reconnect interval may be randomised
to some extent to prevent severe reconnection storms. The type of the option
is int. Default value is 100 (0.1 second).
*NN_RECONNECT_IVL_MAX*::
This option is to be used only in addition to _NN_RECONNECT_IVL_ option.
It specifies maximum reconnection interval. On each reconnect attempt,
the previous interval is doubled until _NN_RECONNECT_IVL_MAX_ is reached.
Value of zero means that no exponential backoff is performed and reconnect
interval is based only on _NN_RECONNECT_IVL_. If _NN_RECONNECT_IVL_MAX_ is
less than _NN_RECONNECT_IVL_, it is ignored. The type of the option is int.
Default value is 0.
*NN_SNDPRIO*::
Sets outbound priority for endpoints subsequently added to the socket. This
option has no effect on socket types that send messages to all the peers.
However, if the socket type sends each message to a single peer
(or a limited set of peers), peers with high priority take precedence
over peers with low priority. The type of the option is int. Highest
priority is 1, lowest priority is 16. Default value is 8.
*NN_RCVPRIO*::
Sets inbound priority for endpoints subsequently added to the socket. This
option has no effect on socket types that are not able to receive messages.
When receiving a message, messages from peer with higher priority are
received before messages from peer with lower priority. The type of the
option is int. Highest priority is 1, lowest priority is 16. Default value
is 8.
*NN_IPV4ONLY*::
If set to 1, only IPv4 addresses are used. If set to 0, both IPv4 and IPv6
addresses are used. The type of the option is int. Default value is 1.
*NN_SOCKET_NAME*::
Socket name for error reporting and statistics. The type of the option
is string. Default value is "socket.N" where N is socket integer.
*This option is experimental, see linknanomsg:nn_env[7] for details*
RETURN VALUE
------------
If the function succeeds zero is returned. Otherwise, -1 is
returned and 'errno' is set to to one of the values defined below.
ERRORS
------
*EBADF*::
The provided socket is invalid.
*ENOPROTOOPT*::
The option is unknown at the level indicated.
*EINVAL*::
The specified option value is invalid.
*ETERM*::
The library is terminating.
EXAMPLE
-------
----
int linger = 1000;
nn_setsockopt (s, NN_SOL_SOCKET, NN_LINGER, &linger, sizeof (linger));
nn_setsockopt (s, NN_SUB, NN_SUB_SUBSCRIBE, "ABC", 3);
----
SEE ALSO
--------
linknanomsg:nn_socket[3]
linknanomsg:nn_getsockopt[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_bind.txt0000664000175000017500000000411012623652600017553 0ustar00travistravis00000000000000nn_bind(3)
==========
NAME
----
nn_bind - add a local endpoint to the socket
SYNOPSIS
--------
*#include *
*int nn_bind (int 's', const char '*addr');*
DESCRIPTION
-----------
Adds a local endpoint to the socket 's'. The endpoint can be then used by other
applications to connect to.
The 'addr' argument consists of two parts as follows: 'transport'`://`'address'.
The 'transport' specifies the underlying transport protocol to use. The meaning
of the 'address' part is specific to the underlying transport protocol.
For the list of available transport protocols check the list on
linknanomsg:nanomsg[7] manual page.
Maximum length of the 'addr' parameter is specified by _NN_SOCKADDR_MAX_
defined in '' header file.
Note that nn_bind and linknanomsg:nn_connect[3] may be called multiple times
on the same socket thus allowing the socket to communicate with multiple
heterogeneous endpoints.
RETURN VALUE
------------
If the function succeeds positive endpoint ID is returned. Endpoint ID can be
later used to remove the endpoint from the socket via linknanomsg:nn_shutdown[3]
function.
If the function fails, then -1 is returned and 'errno' is set to to one of
the values defined below.
ERRORS
------
*EBADF*::
The provided socket is invalid.
*EMFILE*::
Maximum number of active endpoints was reached.
*EINVAL*::
The syntax of the supplied address is invalid.
*ENAMETOOLONG*::
The supplied address is too long.
*EPROTONOSUPPORT*::
The requested transport protocol is not supported.
*EADDRNOTAVAIL*::
The requested endpoint is not local.
*ENODEV*::
Address specifies a nonexistent interface.
*EADDRINUSE*::
The requested local endpoint is already in use.
*ETERM*::
The library is terminating.
EXAMPLE
-------
----
s = nn_socket (AF_SP, NN_PUB);
eid1 = nn_bind (s, "inproc://test");
eid2 = nn_bind (s, "tcp://127.0.0.1:5560");
----
SEE ALSO
--------
linknanomsg:nn_inproc[7]
linknanomsg:nn_ipc[7]
linknanomsg:nn_tcp[7]
linknanomsg:nn_socket[3]
linknanomsg:nn_connect[3]
linknanomsg:nn_shutdown[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_connect.txt0000664000175000017500000000376412623652600020306 0ustar00travistravis00000000000000nn_connect(3)
=============
NAME
----
nn_connect - add a remote endpoint to the socket
SYNOPSIS
--------
*#include *
*int nn_connect (int 's', const char '*addr');*
DESCRIPTION
-----------
Adds a remote endpoint to the socket 's'. The library would then try to connect
to the specified remote endpoint.
The 'addr' argument consists of two parts as follows: 'transport'`://`'address'.
The 'transport' specifies the underlying transport protocol to use. The meaning
of the 'address' part is specific to the underlying transport protocol.
For the list of available transport protocols check the list on
linknanomsg:nanomsg[7] manual page.
Maximum length of the 'addr' parameter is specified by _NN_SOCKADDR_MAX_
defined in '' header file.
Note that nn_connect and linknanomsg:nn_bind[3] may be called multiple times
on the same socket thus allowing the socket to communicate with multiple
heterogeneous endpoints.
RETURN VALUE
------------
If the function succeeds positive endpoint ID is returned. Endpoint ID can be
later used to remove the endpoint from the socket via linknanomsg:nn_shutdown[3]
function.
If the function fails negative value is returned and 'errno' is set to to one of
the values defined below.
ERRORS
------
*EBADF*::
The provided socket is invalid.
*EMFILE*::
Maximum number of active endpoints was reached.
*EINVAL*::
The syntax of the supplied address is invalid.
*ENAMETOOLONG*::
The supplied address is too long.
*EPROTONOSUPPORT*::
The requested transport protocol is not supported.
*ENODEV*::
Address specifies a nonexistent interface.
*ETERM*::
The library is terminating.
EXAMPLE
-------
----
s = nn_socket (AF_SP, NN_PUB);
eid1 = nn_connect (s, "ipc:///tmp/test.ipc");
eid2 = nn_connect (s, "tcp://server001:5560");
----
SEE ALSO
--------
linknanomsg:nn_inproc[7]
linknanomsg:nn_ipc[7]
linknanomsg:nn_tcp[7]
linknanomsg:nn_socket[3]
linknanomsg:nn_bind[3]
linknanomsg:nn_shutdown[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_shutdown.txt0000664000175000017500000000246312623652600020523 0ustar00travistravis00000000000000nn_shutdown(3)
==============
NAME
----
nn_shutdown - remove an endpoint from a socket
SYNOPSIS
--------
*#include *
*int nn_shutdown (int 's', int 'how');*
DESCRIPTION
-----------
Removes an endpoint from socket 's'. 'how' parameter specifies the ID of the
endpoint to remove as returned by prior call to linknanomsg:nn_bind[3] or
linknanomsg:nn_connect[3]. _nn_shutdown()_ call will return immediately,
however, the library will try to deliver any outstanding outbound messages to
the endpoint for the time specified by _NN_LINGER_ socket option.
RETURN VALUE
------------
If the function succeeds zero is returned. Otherwise, -1 is
returned and 'errno' is set to to one of the values defined below.
ERRORS
------
*EBADF*::
The provided socket is invalid.
*EINVAL*::
The 'how' parameter doesn't correspond to an active endpoint.
*EINTR*::
Operation was interrupted by a signal. The endpoint is not fully closed yet.
Operation can be re-started by calling _nn_shutdown()_ again.
*ETERM*::
The library is terminating.
EXAMPLE
-------
----
s = nn_socket (AF_SP, NN_PUB);
eid = nn_bind (s, "inproc://test");
nn_shutdown (s, eid);
----
SEE ALSO
--------
linknanomsg:nn_socket[3]
linknanomsg:nn_bind[3]
linknanomsg:nn_connect[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_send.txt0000664000175000017500000000457212623652600017604 0ustar00travistravis00000000000000nn_send(3)
==========
NAME
----
nn_send - send a message
SYNOPSIS
--------
*#include *
*int nn_send (int 's', const void '*buf', size_t 'len', int 'flags');*
DESCRIPTION
-----------
The function will send a message containing the data from buffer pointed to
by 'buf' parameter to the socket 's'. The message will be 'len' bytes long.
Alternatively, to send a buffer allocated by linknanomsg:nn_allocmsg[3] function
set the buf parameter to point to the pointer to the buffer and 'len' parameter
to _NN_MSG_ constant. In this case a successful call to _nn_send_ will
deallocate the buffer. Trying to deallocate it afterwards will result in
undefined behaviour.
Which of the peers the message will be sent to is determined by
the particular socket type.
The 'flags' argument is a combination of the flags defined below:
*NN_DONTWAIT*::
Specifies that the operation should be performed in non-blocking mode. If the
message cannot be sent straight away, the function will fail with 'errno' set
to EAGAIN.
RETURN VALUE
------------
If the function succeeds, the number of bytes in the message is returned.
Otherwise, -1 is returned and 'errno' is set to to one of the
values defined below.
ERRORS
------
*EFAULT*::
'buf' is NULL or 'len' is NN_MSG and the message pointer (pointed to by
'buf') is NULL.
*EBADF*::
The provided socket is invalid.
*ENOTSUP*::
The operation is not supported by this socket type.
*EFSM*::
The operation cannot be performed on this socket at the moment because the socket
is not in the appropriate state. This error may occur with socket types that
switch between several states.
*EAGAIN*::
Non-blocking mode was requested and the message cannot be sent at the moment.
*EINTR*::
The operation was interrupted by delivery of a signal before the message was
sent.
*ETIMEDOUT*::
Individual socket types may define their own specific timeouts. If such timeout
is hit, this error will be returned.
*ETERM*::
The library is terminating.
EXAMPLE
-------
Using data directly:
----
nbytes = nn_send (s, "ABC", 3, 0);
assert (nbytes == 3);
----
Using a pre-allocated message buffer:
----
void *msg = nn_allocmsg(3, 0);
strncpy(msg, "ABC", 3);
nbytes = nn_send (s, &msg, NN_MSG, 0);
assert (nbytes == 3);
----
SEE ALSO
--------
linknanomsg:nn_recv[3]
linknanomsg:nn_sendmsg[3]
linknanomsg:nn_socket[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_recv.txt0000664000175000017500000000563512623652600017613 0ustar00travistravis00000000000000nn_recv(3)
==========
NAME
----
nn_recv - receive a message
SYNOPSIS
--------
*#include *
*int nn_recv (int 's', void '*buf', size_t 'len', int 'flags');*
DESCRIPTION
-----------
Receive a message from the socket 's' and store it in the buffer referenced by
the 'buf' argument. Any bytes exceeding the length specified by the 'len'
argument will be truncated.
Alternatively, _nanomsg_ can allocate the buffer for you. To do so,
let the 'buf' parameter be a pointer to a void* variable (pointer to pointer)
to the receive buffer and set the 'len' parameter to _NN_MSG_. If the call is
successful the user is responsible for deallocating the message using
the linknanomsg:nn_freemsg[3] function.
The 'flags' argument is a combination of the flags defined below:
*NN_DONTWAIT*::
Specifies that the operation should be performed in non-blocking mode. If the
message cannot be received straight away, the function will fail with 'errno'
set to EAGAIN.
RETURN VALUE
------------
If the function succeeds number of bytes in the message is returned. Otherwise,
-1 is returned and 'errno' is set to to one of the values defined
below.
ERRORS
------
*EBADF*::
The provided socket is invalid.
*ENOTSUP*::
The operation is not supported by this socket type.
*EFSM*::
The operation cannot be performed on this socket at the moment because socket is
not in the appropriate state. This error may occur with socket types that
switch between several states.
*EAGAIN*::
Non-blocking mode was requested and there's no message to receive at the moment.
*EINTR*::
The operation was interrupted by delivery of a signal before the message was
received.
*ETIMEDOUT*::
Individual socket types may define their own specific timeouts. If such timeout
is hit this error will be returned.
*ETERM*::
The library is terminating.
EXAMPLES
--------
Receiving a message into a buffer allocated by the user::
This example code will retrieve a message of either 100 bytes or less. If a
larger message was sent it will be truncated to 100 bytes.
----
char buf [100];
nbytes = nn_recv (s, buf, sizeof (buf), 0);
----
Receiving a message into a buffer allocated by _nanomsg_::
The following will get a message from the pipe with a buffer allocated by
the system. It is large enough to accommodate the entire message. This is a good
way to get the entire message without truncating if the size of the message is
unknown. It is the user's responsibility to call linknanomsg:nn_freemsg[3] after
processing the message.
----
void *buf = NULL;
nbytes = nn_recv (s, &buf, NN_MSG, 0);
if (nbytes < 0) {
/* handle error */
...
}
else {
/* process message */
...
nn_freemsg (buf);
}
----
Note that this can be more efficient than manually allocating a buffer since
it is a zero-copy operation.
SEE ALSO
--------
linknanomsg:nn_send[3]
linknanomsg:nn_recvmsg[3]
linknanomsg:nn_socket[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_sendmsg.txt0000664000175000017500000001002312623652600020277 0ustar00travistravis00000000000000nn_sendmsg(3)
=============
NAME
----
nn_sendmsg - fine-grained alternative to nn_send
SYNOPSIS
--------
*#include *
*int nn_sendmsg (int 's', const struct nn_msghdr '*msghdr', int 'flags');*
DESCRIPTION
-----------
Sends data specified by 'msghdr' parameter to socket 's' along with any
additional control data. 'msghdr' structure should be nullified before being
used.
Structure 'nn_msghdr' contains at least following members:
struct nn_iovec *msg_iov;
int msg_iovlen;
void *msg_control;
size_t msg_controllen;
'msg_iov' points to a scatter array of buffers to send. 'msg_iovlen' specifies
the size of the array.
'msg_control' points to the buffer containing control information to be
associated with the message being sent. 'msg_controllen' specifies the length
of the buffer. If there's no control information to send, 'msg_control' should
be set to NULL. For detailed discussion of how to set control data check
linknanomsg:nn_cmsg[3] man page.
Structure 'nn_iovec' defines one element in the scatter array (i.e. a buffer
to send to the socket) and contains following members:
void *iov_base;
size_t iov_len;
Alternatively, to send a buffer allocated by linknanomsg:nn_allocmsg[3] function
set 'iov_base' to point to the pointer to the buffer and 'iov_len' to _NN_MSG_
constant. In this case a successful call to _nn_sendmsg_ will deallocate the
buffer. Trying to deallocate it afterwards will result in undefined behaviour.
Also, scatter array in _nn_msghdr_ structure can contain only one element
in this case.
To which of the peers will the message be sent to is determined by
the particular socket type.
The 'flags' argument is a combination of the flags defined below:
*NN_DONTWAIT*::
Specifies that the operation should be performed in non-blocking mode. If the
message cannot be sent straight away, the function will fail with 'errno' set
to EAGAIN.
RETURN VALUE
------------
If the function succeeds number of bytes in the message is returned. Otherwise,
-1 is returned and 'errno' is set to to one of the values defined below.
ERRORS
------
*EINVAL*::
Either 'msghdr' is NULL, there are multiple scatter buffers but length is
set to 'NN_MSG' for one of them, or the sum of 'iov_len' values for the
scatter buffers overflows 'size_t'. These are early checks and no
pre-allocated message is freed in this case.
*EMSGSIZE*::
msghdr->msg_iovlen is negative. This is an early check and no pre-allocated
message is freed in this case.
*EFAULT*::
The supplied pointer for the pre-allocated message buffer or the scatter
buffer is NULL, or the length for the scatter buffer is 0.
*EBADF*::
The provided socket is invalid.
*ENOTSUP*::
The operation is not supported by this socket type.
*EFSM*::
The operation cannot be performed on this socket at the moment because socket is
not in the appropriate state. This error may occur with socket types that
switch between several states.
*EAGAIN*::
Non-blocking mode was requested and the message cannot be sent at the moment.
*EINTR*::
The operation was interrupted by delivery of a signal before the message was
sent.
*ETIMEDOUT*::
Individual socket types may define their own specific timeouts. If such timeout
is hit this error will be returned.
*ETERM*::
The library is terminating.
EXAMPLE
-------
Usage of multiple scatter buffers:
----
struct nn_msghdr hdr;
struct nn_iovec iov [2];
iov [0].iov_base = "Hello";
iov [0].iov_len = 5;
iov [1].iov_base = "World";
iov [1].iov_len = 5;
memset (&hdr, 0, sizeof (hdr));
hdr.msg_iov = iov;
hdr.msg_iovlen = 2;
nn_sendmsg (s, &hdr, 0);
----
Usage of a single message:
----
void *msg;
struct nn_msghdr hdr;
struct nn_iovec iov;
msg = nn_allocmsg(12, 0);
strcpy(msg, "Hello World");
iov.iov_base = &msg;
iov.iov_len = NN_MSG;
memset (&hdr, 0, sizeof (hdr));
hdr.msg_iov = &iov;
hdr.msg_iovlen = 1;
nn_sendmsg (s, &hdr, 0);
----
SEE ALSO
--------
linknanomsg:nn_send[3]
linknanomsg:nn_recvmsg[3]
linknanomsg:nn_allocmsg[3]
linknanomsg:nn_freemsg[3]
linknanomsg:nn_cmsg[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_recvmsg.txt0000664000175000017500000000624212623652600020315 0ustar00travistravis00000000000000nn_recvmsg(3)
=============
NAME
----
nn_recvmsg - fine-grained alternative to nn_recv
SYNOPSIS
--------
*#include *
*NN_EXPORT int nn_recvmsg (int 's', struct nn_msghdr '*msghdr', int 'flags');*
DESCRIPTION
-----------
Receives a message from socket 's' into buffers specified by 'msghdr' parameter
along with any additional control data. 'msghdr' parameter should be nullified
before being used.
Structure 'nn_msghdr' contains at least following members:
struct nn_iovec *msg_iov;
int msg_iovlen;
void *msg_control;
size_t msg_controllen;
'msg_iov' points to a gather array of buffers to fill in. 'msg_iovlen' specifies
the size of the array.
'msg_control' points to the buffer to hold control information associated with
the received message. 'msg_controllen' specifies the length of the buffer.
If the control information should not be retrieved, set 'msg_control' parameter
to NULL. For detailed discussion of how to parse the control information check
linknanomsg:nn_cmsg[3] man page.
Structure 'nn_iovec' defines one element in the gather array (a buffer to be
filled in by message data) and contains following members:
void *iov_base;
size_t iov_len;
Alternatively, _nanomsg_ library can allocate the buffer for you. To do so,
let the 'iov_base' point to void* variable to receive the buffer and set
'iov_len' to _NN_MSG_. After successful completion user is responsible
for deallocating the message using linknanomsg:nn_freemsg[3] function. Gather
array in _nn_msghdr_ structure can contain only one element in this case.
The 'flags' argument is a combination of the flags defined below:
*NN_DONTWAIT*::
Specifies that the operation should be performed in non-blocking mode. If the
message cannot be received straight away, the function will fail with 'errno'
set to EAGAIN.
RETURN VALUE
------------
If the function succeeds number of bytes in the message is returned. Otherwise,
-1 is returned and 'errno' is set to to one of the values defined
below.
ERRORS
------
*EBADF*::
The provided socket is invalid.
*ENOTSUP*::
The operation is not supported by this socket type.
*EFSM*::
The operation cannot be performed on this socket at the moment because socket is
not in the appropriate state. This error may occur with socket types that
switch between several states.
*EAGAIN*::
Non-blocking mode was requested and there's no message to receive at the moment.
*EINTR*::
The operation was interrupted by delivery of a signal before the message was
received.
*ETIMEDOUT*::
Individual socket types may define their own specific timeouts. If such timeout
is hit this error will be returned.
*ETERM*::
The library is terminating.
EXAMPLE
-------
----
struct nn_msghdr hdr;
struct nn_iovec iov [2];
char buf0 [4];
char buf1 [2];
iov [0].iov_base = buf0;
iov [0].iov_len = sizeof (buf0);
iov [1].iov_base = buf1;
iov [1].iov_len = sizeof (buf1);
memset (&hdr, 0, sizeof (hdr));
hdr.msg_iov = iov;
hdr.msg_iovlen = 2;
nn_recvmsg (s, &hdr, 0);
----
SEE ALSO
--------
linknanomsg:nn_recv[3]
linknanomsg:nn_sendmsg[3]
linknanomsg:nn_allocmsg[3]
linknanomsg:nn_freemsg[3]
linknanomsg:nn_cmsg[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_device.txt0000664000175000017500000000274212623652600020107 0ustar00travistravis00000000000000nn_device(3)
============
NAME
----
nn_device - start a device
SYNOPSIS
--------
*#include *
*int nn_device (int 's1', int 's2');*
DESCRIPTION
-----------
Starts a device to forward messages between two sockets. If both sockets are
valid, _nn_device_ function loops and sends and messages received from 's1' to
's2' and vice versa. If only one socket is valid and the other is negative,
_nn_device_ works in a "loopback" mode -- it loops and sends any messages
received from the socket back to itself.
To break the loop and make _nn_device_ function exit use
linknanomsg:nn_term[3] function.
RETURN VALUE
------------
The function loops until it hits an error. In such case it returns -1
and sets 'errno' to one of the values defined below.
ERRORS
------
*EBADF*::
One of the provided sockets is invalid.
*EINVAL*::
Either one of the socket is not an AF_SP_RAW socket; or the two sockets don't
belong to the same protocol; or the directionality of the sockets doesn't fit
(e.g. attempt to join two SINK sockets to form a device).
*EINTR*::
The operation was interrupted by delivery of a signal.
*ETERM*::
The library is terminating.
EXAMPLE
-------
----
int s1 = nn_socket (AF_SP_RAW, NN_REQ);
nn_bind (s1, "tcp://127.0.0.1:5555");
int s2 = nn_socket (AF_SP_RAW, NN_REP);
nn_bind (s2, "tcp://127.0.0.1:5556");
nn_device (s1, s2);
----
SEE ALSO
--------
linknanomsg:nn_socket[3]
linknanomsg:nn_term[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_cmsg.txt0000664000175000017500000000436312623652600017602 0ustar00travistravis00000000000000nn_cmsg(3)
==========
NAME
----
nn_cmsg - access control information
SYNOPSIS
--------
*#include *
*struct nn_cmsghdr *NN_CMSG_FIRSTHDR(struct nn_msghdr '*hdr');*
*struct nn_cmsghdr *NN_CMSG_NXTHDR(struct nn_msghdr '*hdr', struct nn_cmsghdr '*cmsg');*
*unsigned char *NN_CMSG_DATA(struct nn_cmsghdr '*cmsg');*
*size_t NN_CMSG_SPACE(size_t 'len');*
*size_t NN_CMSG_LEN(size_t 'len');*
DESCRIPTION
-----------
These functions can be used to iterate over ancillary data attached to a message.
Structure 'nn_cmsghdr' represents a single ancillary property and contains following members:
size_t cmsg_len;
int cmsg_level;
int cmsg_type;
'cmsg_len' is the size of the property data, including the preceding nn_cmsghdr structure.
'cmsg_level' is the level of the property; same values can be used as with linknanomsg:nn_getsockopt[3] and linknanomsg:nn_setsockopt[3].
'cmsg_type' is the name of the property. These names are specific for each level.
_NN_CMSG_FIRSTHDR_ returns a pointer to the first nn_cmsghdr in the control buffer in the supplied nn_msghdr structure.
_NN_CMSG_NXTHDR_ returns the next nn_cmsghdr after the supplied nn_cmsghdr. Returns NULL if there isn't enough space in the buffer.
_NN_CMSG_DATA_ returns a pointer to the data associated with supplied nn_cmsghdr.
_NN_CMSG_SPACE_ returns the number of bytes occupied by nn_cmsghdr with payload of the specified length.
_NN_CMSG_LEN_ returns the value to store in the cmsg_len member of the cmsghdr structure, taking into account any necessary alignment.
EXAMPLE
-------
Iterating over ancillary properties:
----
struct nn_cmsghdr *hdr = NN_CMSG_FIRSTHDR (&msg);
while (hdr != NULL) {
size_t len = hdr->cmsg_len - sizeof (nn_cmsghdr);
printf ("level: %d property: %d length: %dB data: ",
(int) hdr->cmsg_level,
(int) hdr->cmsg_type,
(int) len);
unsigned char *data = NN_CMSG_DATA(hdr);
while (len) {
printf ("%02X", *data);
++data;
--len;
}
printf ("\n");
hdr = NN_CMSG_NXTHDR (&msg, hdr);
}
----
SEE ALSO
--------
linknanomsg:nn_sendmsg[3]
linknanomsg:nn_recvmsg[3]
linknanomsg:nn_getsockopt[3]
linknanomsg:nn_setsockopt[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_poll.txt0000664000175000017500000000476512623652600017625 0ustar00travistravis00000000000000nn_poll(3)
==========
NAME
----
nn_poll - poll a set of SP sockets for readability and/or writability
SYNOPSIS
--------
*#include *
*int nn_poll (struct nn_pollfd *fds, int nfds, int timeout);*
DESCRIPTION
-----------
The function checks a set of SP socket and reports whether it's possible to
send a message to the socket and/or receive a message from each socket.
'fds' argument is an array of nn_pollfd structures with 'nfds' argument
specifying the size of the array:
----
struct nn_pollfd {
int fd;
short events;
short revents;
};
----
Each entry in the array represents an SP socket to check. 'events' field
specifies which events to check for. The value is a bitwise combination of
the following values:
*NN_POLLIN*::
Check whether at least one message can be received from the 'fd' socket without
blocking.
*NN_POLLOUT*::
Check whether at least one message can be sent to the 'fd' socket without
blocking.
After the function returns, 'revents' field contains bitwise combination of
NN_POLLIN and NN_POLLOUT according to whether the socket is readable or
writable.
'timeout' parameter specifies how long (in milliseconds) should the function
block if there are no events to report.
RETURN VALUE
------------
Upon successful completion, the number of nn_pollfds structures with events
signaled is returned. In case of timeout, return value is 0. In case of error,
-1 is returned and 'errno' is set the one of the values below.
ERRORS
------
*EBADF*::
Some of the provided sockets are invalid.
*EINTR*::
The operation was interrupted by delivery of a signal before the message was
sent.
*ETERM*::
The library is terminating.
NOTE
----
nn_poll is a convenience function. You can achieve same behaviour by using
NN_RCVFD and NN_SNDFD socket options. However, using the socket options
allows for usage that's not possible with nn_poll, such as simultaneous polling
for both SP and OS-level sockets, integration of SP sockets with external event
loops etc.
EXAMPLE
-------
----
struct nn_pollfd pfd [2];
pfd [0].fd = s1;
pfd [0].events = NN_POLLIN | NN_POLLOUT;
pfd [1].fd = s2;
pfd [1].events = NN_POLLIN;
rc = nn_poll (pfd, 2, 2000);
if (rc == 0) {
printf ("Timeout!");
exit (1);
}
if (rc == -1) {
printf ("Error!");
exit (1);
}
if (pfd [0].revents & NN_POLLIN) {
printf ("Message can be received from s1!");
exit (1);
}
----
SEE ALSO
--------
linknanomsg:nn_socket[3]
linknanomsg:nn_getsockopt[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nanomsg.txt0000664000175000017500000000462712623652600017623 0ustar00travistravis00000000000000nanomsg(7)
==========
NAME
----
nanomsg - scalability protocols library
SYNOPSIS
--------
*cc* ['flags'] 'files' *-lnanomsg* ['libraries']
DESCRIPTION
-----------
Following functions are exported by nanomsg library:
Create an SP socket::
linknanomsg:nn_socket[3]
Close an SP socket::
linknanomsg:nn_close[3]
Set a socket option::
linknanomsg:nn_setsockopt[3]
Retrieve a socket option::
linknanomsg:nn_getsockopt[3]
Add a local endpoint to the socket::
linknanomsg:nn_bind[3]
Add a remote endpoint to the socket::
linknanomsg:nn_connect[3]
Remove an endpoint from the socket::
linknanomsg:nn_shutdown[3]
Send a message::
linknanomsg:nn_send[3]
Receive a message::
linknanomsg:nn_recv[3]
Fine-grained alternative to nn_send::
linknanomsg:nn_sendmsg[3]
Fine-grained alternative to nn_recv::
linknanomsg:nn_recvmsg[3]
Allocation of messages::
linknanomsg:nn_allocmsg[3]
linknanomsg:nn_reallocmsg[3]
linknanomsg:nn_freemsg[3]
Manipulation of message control data::
linknanomsg:nn_cmsg[3]
Multiplexing::
linknanomsg:nn_poll[3]
Retrieve the current errno::
linknanomsg:nn_errno[3]
Convert an error number into human-readable string::
linknanomsg:nn_strerror[3]
Query the names and values of nanomsg symbols::
linknanomsg:nn_symbol[3]
Query properties of nanomsg symbols::
linknanomsg:nn_symbol_info[3]
Start a device::
linknanomsg:nn_device[3]
Notify all sockets about process termination::
linknanomsg:nn_term[3]
Environment variables that influence nanomsg work::
linknanomsg:nn_env[7]
Following scalability protocols are provided by nanomsg:
One-to-one protocol::
linknanomsg:nn_pair[7]
Request/reply protocol::
linknanomsg:nn_reqrep[7]
Publish/subscribe protocol::
linknanomsg:nn_pubsub[7]
Survey protocol::
linknanomsg:nn_survey[7]
Pipeline protocol::
linknanomsg:nn_pipeline[7]
Message bus protocol::
linknanomsg:nn_bus[7]
Following transport mechanisms are provided by nanomsg:
In-process transport::
linknanomsg:nn_inproc[7]
Inter-process transport::
linknanomsg:nn_ipc[7]
TCP transport::
linknanomsg:nn_tcp[7]
TCPMUX transport::
linknanomsg:nn_tcpmux[7]
WebSocket transport::
linknanomsg:nn_ws[7]
Following tools are installed with the library:
nanocat::
linknanomsg:nanocat[1]
tcpmuxd::
linknanomsg:tcpmuxd[1]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_pair.txt0000664000175000017500000000303412623652600017576 0ustar00travistravis00000000000000nn_pair(7)
==========
NAME
----
nn_pair - one-to-one scalability protocol
SYNOPSIS
--------
*#include *
*#include *
DESCRIPTION
-----------
Pair protocol is the simplest and least scalable scalability protocol. It allows
scaling by breaking the application in exactly two pieces. For example,
if a monolithic application handles both accounting and agenda of HR department,
it can be split into two applications (accounting vs. HR) that are run on two
separate servers. These applications can then communicate via PAIR sockets.
The downside of this protocol is that its scaling properties are very limited.
Splitting the application into two pieces allows to scale the two servers.
To add the third server to the cluster, application has to be split once more,
say by separating HR functionality into hiring module and salary computation
module. Whenever possible, try to use one of the more scalable protocols
instead.
Socket Types
~~~~~~~~~~~~
NN_PAIR::
Socket for communication with exactly one peer. Each party can send messages
at any time. If the peer is not available or send buffer is full subsequent
calls to linknanomsg:nn_send[3] will block until it's possible to send the
message.
Socket Options
~~~~~~~~~~~~~~
No protocol-specific socket options are defined at the moment.
SEE ALSO
--------
linknanomsg:nn_bus[7]
linknanomsg:nn_pubsub[7]
linknanomsg:nn_reqrep[7]
linknanomsg:nn_pipeline[7]
linknanomsg:nn_survey[7]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_reqrep.txt0000664000175000017500000000353512623652600020147 0ustar00travistravis00000000000000nn_reqrep(7)
============
NAME
----
nn_reqrep - request/reply scalability protocol
SYNOPSIS
--------
*#include *
*#include *
DESCRIPTION
-----------
This protocol is used to distribute the workload among multiple stateless
workers.
Please note that request/reply applications should be stateless.
It's important to include all the information necessary to process the
request in the request itself, including information about the sender or
the originator of the request if this is necessary to respond to the request.
Sender information cannot be retrieved from the underlying socket connection
since, firstly, transports like IPC may not have a firm notion of a message
origin. Secondly, transports that have some notion may not have a reliable one
-- a TCP disconnect may mean a new sender, or it may mean a temporary loss in
network connectivity.
For this reason, sender information must be included by the application if
required. Allocating 6 randomly-generated bytes in the message for the lifetime
of the connection is sufficient for most purposes. For longer-lived
applications, an UUID is more suitable.
Socket Types
~~~~~~~~~~~~
NN_REQ::
Used to implement the client application that sends requests and
receives replies.
NN_REP::
Used to implement the stateless worker that receives requests and sends
replies.
Socket Options
~~~~~~~~~~~~~~
NN_REQ_RESEND_IVL::
This option is defined on the full REQ socket. If reply is not received
in specified amount of milliseconds, the request will be automatically
resent. The type of this option is int. Default value is 60000 (1 minute).
SEE ALSO
--------
linknanomsg:nn_bus[7]
linknanomsg:nn_pubsub[7]
linknanomsg:nn_pipeline[7]
linknanomsg:nn_survey[7]
linknanomsg:nn_pair[7]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_pubsub.txt0000664000175000017500000000525112623652600020146 0ustar00travistravis00000000000000nn_pubsub(7)
============
NAME
----
nn_pubsub - publish/subscribe scalability protocol
SYNOPSIS
--------
*#include *
*#include *
DESCRIPTION
-----------
Broadcasts messages to multiple destinations.
Messages are sent from NN_PUB sockets and will only be received by NN_SUB
sockets that have subscribed to the matching 'topic'. Topic is an arbitrary
sequence of bytes at the beginning of the message body. The NN_SUB socket will
determine whether a message should be delivered to the user by comparing the
subscribed topics (using NN_SUB_SUBSCRIBE on a full SUB socket) to the bytes
initial bytes in the incomming message, up to the size of the topic.
----
nn_setsockopt (s, NN_SUB, NN_SUB_SUBSCRIBE, "Hello", 5);
----
Will match any message with intial 5 bytes being "Hello", for example,
message "Hello, World!" will match.
Topic with zero length matches any message.
If the socket is subscribed to multiple topics, message matching any of them
will be delivered to the user.
Since the filtering is performed on the Subscriber side, all the messages
from Publisher will be sent over the transport layer.
The entire message, including the topic, is delivered to the user.
Socket Types
~~~~~~~~~~~~
NN_PUB::
This socket is used to distribute messages to multiple destinations.
Receive operation is not defined.
NN_SUB::
Receives messages from the publisher. Only messages that the socket is
subscribed to are received. When the socket is created there are no
subscriptions and thus no messages will be received. Send operation is
not defined on this socket.
Socket Options
~~~~~~~~~~~~~~
NN_SUB_SUBSCRIBE::
Defined on full SUB socket. Subscribes for a particular topic. Type of the
option is string. A single NN_SUB socket can handle multiple subscriptions.
NN_SUB_UNSUBSCRIBE::
Defined on full SUB socket. Unsubscribes from a particular topic. Type of
the option is string.
EXAMPLE
~~~~~~~
----
int pub = nn_socket (AF_SP, NN_PUB);
int sub = nn_socket (AF_SP, NN_SUB);
int nbytes;
void *buf = NULL;
nn_setsockopt (sub, NN_SUB, NN_SUB_SUBSCRIBE, "foo", 3);
nn_setsockopt (sub, NN_SUB, NN_SUB_SUBSCRIBE, "bar", 3);
nbytes = nn_send (pub, "foo|Hello!", 10);
assert(nbytes == 10);
nbytes = nn_recv (sub, &buf, NN_MSG, 0);
assert (nbytes == 10);
nn_freemsg (buf);
nbytes = nn_send (pub, "baz|World!", 10);
/* Message is not delivered because if matches no subscription. */
nbytes = nn_recv(sub, &buf, NN_MSG, 0);
----
SEE ALSO
--------
linknanomsg:nn_bus[7]
linknanomsg:nn_reqrep[7]
linknanomsg:nn_pipeline[7]
linknanomsg:nn_survey[7]
linknanomsg:nn_pair[7]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_survey.txt0000664000175000017500000000244412623652600020204 0ustar00travistravis00000000000000nn_survey(7)
============
NAME
----
nn_survey - survey scalability protocol
SYNOPSIS
--------
*#include *
*#include *
DESCRIPTION
-----------
Allows to broadcast a survey to multiple locations and gather the responses.
Socket Types
~~~~~~~~~~~~
NN_SURVEYOR::
Used to send the survey. The survey is delivered to all the connected
respondents. Once the query is sent, the socket can be used to receive
the responses. When the survey deadline expires, receive will return
ETIMEDOUT error.
NN_RESPONDENT::
Use to respond to the survey. Survey is received using receive function,
response is sent using send function. This socket can be connected to
at most one peer.
Socket Options
~~~~~~~~~~~~~~
NN_SURVEYOR_DEADLINE::
Specifies how long to wait for responses to the survey. Once the deadline
expires, receive function will return ETIMEDOUT error and all subsequent
responses to the survey will be silently dropped. The deadline is measured
in milliseconds. Option type is int. Default value is 1000 (1 second).
SEE ALSO
--------
linknanomsg:nn_bus[7]
linknanomsg:nn_pubsub[7]
linknanomsg:nn_reqrep[7]
linknanomsg:nn_pipeline[7]
linknanomsg:nn_pair[7]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_pipeline.txt0000664000175000017500000000173412623652600020455 0ustar00travistravis00000000000000nn_pipeline(7)
==============
NAME
----
nn_pipeline - scalability protocol for passing tasks through a series of processing steps
SYNOPSIS
--------
*#include *
*#include *
DESCRIPTION
-----------
Fair queues messages from the previous processing step and load balances them
among instances of the next processing step.
Socket Types
~~~~~~~~~~~~
NN_PUSH::
This socket is used to send messages to a cluster of load-balanced
nodes. Receive operation is not implemented on this socket type.
NN_PULL::
This socket is used to receive a message from a cluster of nodes. Send
operation is not implemented on this socket type.
Socket Options
~~~~~~~~~~~~~~
No protocol-specific socket options are defined at the moment.
SEE ALSO
--------
linknanomsg:nn_bus[7]
linknanomsg:nn_pubsub[7]
linknanomsg:nn_reqrep[7]
linknanomsg:nn_survey[7]
linknanomsg:nn_pair[7]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_bus.txt0000664000175000017500000000227712623652600017444 0ustar00travistravis00000000000000nn_bus(7)
=========
NAME
----
nn_bus - message bus scalability protocol
SYNOPSIS
--------
*#include *
*#include *
DESCRIPTION
-----------
Broadcasts messages from any node to all other nodes in the topology. The socket
should never receives messages that it sent itself.
This pattern scales only to local level (within a single machine or within
a single LAN). Trying to scale it further can result in overloading individual
nodes with messages.
WARNING: For bus topology to function correctly, user is responsible for
ensuring that path from each node to any other node exists within the topology.
Raw (AF_SP_RAW) BUS socket never sends the message to the peer it was received
from.
Socket Types
~~~~~~~~~~~~
NN_BUS::
Sent messages are distributed to all nodes in the topology. Incoming
messages from all other nodes in the topology are fair-queued in the
socket.
Socket Options
~~~~~~~~~~~~~~
There are no options defined at the moment.
SEE ALSO
--------
linknanomsg:nn_pubsub[7]
linknanomsg:nn_reqrep[7]
linknanomsg:nn_pipeline[7]
linknanomsg:nn_survey[7]
linknanomsg:nn_pair[7]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_inproc.txt0000664000175000017500000000314412623652600020137 0ustar00travistravis00000000000000nn_inproc(7)
============
NAME
----
nn_inproc - in-process transport mechanism
SYNOPSIS
--------
*#include *
*#include *
DESCRIPTION
-----------
In-process transport allows to send messages between threads or modules inside a
process. In-process address is an arbitrary case-sensitive string preceded by
'inproc://' protocol specifier. All in-process addresses are visible from any
module within the process. They are not visible from outside of the process.
The nature of in-process transport makes it easy to pass pointers between
threads instead of actual data. This is, however, considered a bad application
design and violates the scalable share-nothing architecture. If you do pass
pointers among threads, synchronising thread access to shared data becomes
your responsibility. Such design also prevents moving the thread into different
process or machine once the need arises. As a rule of the thumb, don't pass
pointers among threads unless you know what you are doing.
The overall buffer size for an inproc connection is determined by NN_RCVBUF
socket option on the receiving end of the connection. NN_SNDBUF socket option
is ignored. In addition to the buffer, one message of arbitrary size will fit
into the buffer. That way, even messages larger than the buffer can be
transfered via inproc connection.
EXAMPLE
-------
----
nn_bind (s1, "inproc://test");
nn_connect (s2, "inproc://test);
----
SEE ALSO
--------
linknanomsg:nn_ipc[7]
linknanomsg:nn_tcp[7]
linknanomsg:nn_bind[3]
linknanomsg:nn_connect[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_ipc.txt0000664000175000017500000000232212623652600017415 0ustar00travistravis00000000000000nn_ipc(7)
=========
NAME
----
nn_ipc - inter-process transport mechanism
SYNOPSIS
--------
*#include *
*#include *
DESCRIPTION
-----------
Inter-process transport allows for sending messages between processes within
a single box. The implementation uses native IPC mechanism provided by the local
operating system and the IPC addresses are thus OS-specific.
On POSIX-compliant systems, UNIX domain sockets are used and IPC addresses are
file references. Note that both relative (ipc://test.ipc) and absolute
(ipc:///tmp/test.ipc) paths may be used. Also note that access rights on the IPC
files must be set in such a way that the appropriate applications can actually
use them.
On Windows, named pipes are used for IPC. IPC address is an arbitrary
case-insensitive string containing any character except for backslash.
Internally, address ipc://test means that named pipe \\.\pipe\test will be used.
EXAMPLE
-------
----
nn_bind (s1, "ipc:///tmp/test.ipc");
nn_connect (s2, "ipc:///tmp/test.ipc");
----
SEE ALSO
--------
linknanomsg:nn_inproc[7]
linknanomsg:nn_tcp[7]
linknanomsg:nn_bind[3]
linknanomsg:nn_connect[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_tcp.txt0000664000175000017500000000425512623652600017437 0ustar00travistravis00000000000000nn_tcp(7)
=========
NAME
----
nn_tcp - TCP transport mechanism
SYNOPSIS
--------
*#include *
*#include *
DESCRIPTION
-----------
TCP transport allows for passing message over the network using simple reliable
one-to-one connections. TCP is the most widely used transport protocol, it is
virtually ubiquitous and thus the transport of choice for communication over
the network.
When binding a TCP socket address of the form tcp://interface:port should be
used. Port is the TCP port number to use. Interface is one of the following
(optionally placed within square brackets):
* Asterisk character (*) meaning all local network interfaces.
* IPv4 address of a local network interface in numeric form (192.168.0.111).
* IPv6 address of a local network interface in numeric form (::1).
When connecting a TCP socket address of the form tcp://interface;address:port
should be used. Port is the TCP port number to use. Interface is optional and
specifies which local network interface to use. If not specified, OS will select
an appropriate interface itself. If specified it can be one of the following
(optionally placed within square brackets):
* IPv4 address of a local network interface in numeric form (192.168.0.111).
* IPv6 address of a local network interface in numeric form (::1).
Finally, address specifies the remote address to connect to. It can be one of
the following (optionally placed within square brackets):
* IPv4 address of a remote network interface in numeric form (192.168.0.111).
* IPv6 address of a remote network interface in numeric form (::1).
* The DNS name of the remote box.
Socket Options
~~~~~~~~~~~~~~
NN_TCP_NODELAY::
This option, when set to 1, disables Nagle's algorithm. It also disables
delaying of TCP acknowledgments. Using this option improves latency at
the expense of throughput. Type of this option is int. Default value is 0.
EXAMPLE
-------
----
nn_bind (s1, "tcp://*:5555");
nn_connect (s2, "tcp://myserver:5555");
----
SEE ALSO
--------
linknanomsg:nn_inproc[7]
linknanomsg:nn_ipc[7]
linknanomsg:nn_bind[3]
linknanomsg:nn_connect[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_tcpmux.txt0000664000175000017500000000324412623652600020166 0ustar00travistravis00000000000000nn_tcpmux(7)
============
NAME
----
nn_tcpmux - TCPMUX transport mechanism
SYNOPSIS
--------
*#include *
*#include *
DESCRIPTION
-----------
THIS IS AN EXPERIMENTAL FEATURE. DO NOT USE.
THE FUNCTIONALITY IS SUBJECT TO CHANGE WITHOUT PRIOR NOTICE.
TCPMUX transport is basically the same as TCP transport
(see linknanomsg:nn_tcp[7]) except that it allows to specify service names
along with IP addresses and TCP ports. What it means in practice is that many
applications on the same box can share the same TCP port.
When connecting and binding use the same connection string syntax as with
TCP transport, except that the initial protocol specification should be
'tcpmux://' instead of 'tcp://' and that the connection string should end
with a slash and a service name:
----
nn_connect (s, "tcpmux://192.168.0.1:5555/foo");
----
When binding to a TCPMUX endpoint, linknanomsg:nn_tcpmuxd[1] daemon must be
running on the box and specified port. There is no such requirement when
connecting to a TCPMUX endpoint.
Socket Options
~~~~~~~~~~~~~~
NN_TCPMUX_NODELAY::
This option, when set to 1, disables Nagle's algorithm. It also disables
delaying of TCP acknowledgments. Using this option improves latency at
the expense of throughput. Type of this option is int. Default value is 0.
EXAMPLE
-------
----
nn_bind (s1, "tcpmux://*:5555/foo");
nn_connect (s2, "tcpmux://server1.example.org:5555/foo");
----
SEE ALSO
--------
linknanomsg:nn_tcpmuxd[1]
linknanomsg:nn_tcp[7]
linknanomsg:nn_inproc[7]
linknanomsg:nn_ipc[7]
linknanomsg:nn_bind[3]
linknanomsg:nn_connect[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
nanomsg-0.8-beta/doc/nn_ws.txt0000664000175000017500000000542112623652600017276 0ustar00travistravis00000000000000nn_ws(7)
========
NAME
----
nn_ws - WebSocket transport mechanism
SYNOPSIS
--------
*#include *
*#include *
DESCRIPTION
-----------
THIS IS AN EXPERIMENTAL FEATURE. DO NOT USE.
THE FUNCTIONALITY IS SUBJECT TO CHANGE WITHOUT PRIOR NOTICE.
When calling either `nn_bind()` or `nn_connect()`, omitting the port defaults
to the RFC 6455 default port 80 for HTTP. Example:
ws://127.0.0.1 is equivalent to ws://127.0.0.1:80
URI limitations
~~~~~~~~~~~~~~~
When calling `nn_connect()`, the URI may also optionally include the path to a
resource and/or query parameters.
.Path and query parameters
==========================
s1 = nn_socket (AF_SP, NN_PAIR);
nn_connect (s1, "ws://example.com/path?query=value");
==========================
This implementation includes the full path and any query parameters in the
HTTP handshake when establishing connections with `nn_connect()`. This
information is not available via the nanomsg API afterwards, however.
Likewise, this implementation does not examine or use either any path or
query parameters that may be supplied to `nn_bind()`, as it only binds to
the TCP port. This implementation acts as a limited HTTP server that offers
SP over WebSocket at all URIs for the given TCP address.
Applications should not however depends on this behavior; intervening
infrastructure may proxy, filter or route based on URI, and other
implementations of the SP over WebSocket protocol may offer other
HTTP services at the same TCP port, utilizing the path, query parameters,
or both to determine the service to be used.
Socket Options
~~~~~~~~~~~~~~
NN_WS_MSG_TYPE::
This option may be set to NN_WS_MSG_TYPE_TEXT or NN_WS_MSG_TYPE_BINARY.
The value of this determines whether data messages are sent as WebSocket
text frames, or binary frames, per RFC 6455. Text frames should contain
only valid UTF-8 text in their payload, or they will be rejected. Binary
frames may contain any data. Not all WebSocket implementations support
binary frames. The default is to send binary frames.
+
This option may also be specified as control data when when sending
a message with `nn_sendmsg()`.
TODO: NN_TCP_NODELAY::
This option, when set to 1, disables Nagle's algorithm. It also disables
delaying of TCP acknowledgments. Using this option improves latency at
the expense of throughput. Type of this option is int. Default value is 0.
EXAMPLE
-------
----
nn_bind (s1, "ws://*:5555");
nn_connect (s2, "ws://myserver:5555");
----
SEE ALSO
--------
linknanomsg:nn_tcp[7]
linknanomsg:nn_inproc[7]
linknanomsg:nn_ipc[7]
linknanomsg:nn_bind[3]
linknanomsg:nn_connect[3]
linknanomsg:nanomsg[7]
AUTHORS
-------
Martin Sustrik
Jack R. Dunaway
Garrett D'Amore
nanomsg-0.8-beta/doc/nn_env.txt0000664000175000017500000000426012623652600017435 0ustar00travistravis00000000000000nn_env(7)
==========
NAME
----
nn_env - nanomsg environment variables
SYNOPSIS
--------
Environment variables that influence the way nanomsg works
DESCRIPTION
-----------
*This functionality is experimental and a subject to change at any time*
Following environment variables are used to turn on some debugging for any
nanomsg application. Please, do not try to parse output and do not
build business logic based on it.
NN_PRINT_ERRORS::
If set to non-empty string nanomsg will print errors to stderr. Some errors
will be resolved by nanomsg itself (e.g. if nanomsg can't establish
connection it will retry again in a moment). Some depend on the
environment (e.g. port that is bound by another process need to be
released). In any case nanomsg will not repeat the error message until
error is clear and appear again (e.g. connection established then broken
again).
NN_PRINT_STATISTICS::
If set to non-empty string nanomsg will print some statistics to stderr.
That's statistics is intended for debugging purposes only.
NN_STATISTICS_SOCKET::
The nanomsg address to send statistics to. Nanomsg opens NN_PUB socket
and sends statistics there. The data is sent using ESTP protocol.
NOTES
-----
The output of both debugging facilities (NN_PRINT_ERRORS, NN_PRINT_STATISTICS)
is intended for reading by human and a subject for change at any time (even
after 1.0 release).
The NN_STATISTICS_SOCKET facility is intended to use by system administrators
to debug network and application issues. The ESTP format is stable. But the
nanomsg support of it is experimental and is subject to change or removal
until 1.0 release.
Anyway, there is *no excuse* for making application logic based on the data
described here. And by application logic we mean any of the following:
* Load balancing
* Failover
* Routing requests
* Executing nn_connect/nn_bind
There are other ways for load-balancing and failover in nanomsg. If you feel
you can't do something, consider ask on the mailing list first.
SEE ALSO
--------
linknanomsg:nanomsg[7]
http://github.com/estp
http://github.com/estp/estp/blob/master/specification.rst
AUTHORS
-------
Paul Colomiets
nanomsg-0.8-beta/m4/0000775000175000017500000000000012623652617015172 5ustar00travistravis00000000000000nanomsg-0.8-beta/m4/ax_pthread.m40000664000175000017500000003270312623652600017550 0ustar00travistravis00000000000000# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
#
# DESCRIPTION
#
# This macro figures out how to build C programs using POSIX threads. It
# sets the PTHREAD_LIBS output variable to the threads library and linker
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
# flags that are needed. (The user can also force certain compiler
# flags/libs to be tested by setting these environment variables.)
#
# Also sets PTHREAD_CC to any special C compiler that is needed for
# multi-threaded programs (defaults to the value of CC otherwise). (This
# is necessary on AIX to use the special cc_r compiler alias.)
#
# NOTE: You are assumed to not only compile your program with these flags,
# but also link it with them as well. e.g. you should link with
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
#
# If you are only building threads programs, you may wish to use these
# variables in your default LIBS, CFLAGS, and CC:
#
# LIBS="$PTHREAD_LIBS $LIBS"
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# CC="$PTHREAD_CC"
#
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
#
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
# PTHREAD_CFLAGS.
#
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
# is not found. If ACTION-IF-FOUND is not specified, the default action
# will define HAVE_PTHREAD.
#
# Please let the authors know if this macro fails on any platform, or if
# you have any other suggestions or comments. This macro was based on work
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
# grateful for the helpful feedback of numerous users.
#
# Updated for Autoconf 2.68 by Daniel Richard G.
#
# LICENSE
#
# Copyright (c) 2008 Steven G. Johnson
# Copyright (c) 2011 Daniel Richard G.
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# 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 for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see .
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 21
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_LANG_PUSH([C])
ax_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on True64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes])
AC_MSG_RESULT([$ax_pthread_ok])
if test x"$ax_pthread_ok" = xno; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
fi
# We must check for the threads library under a number of different
# names; the ordering is very important because some systems
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
# Create a list of thread flags to try. Items starting with a "-" are
# C compiler flags, and other items are library names, except for "none"
# which indicates that we try without any flags at all, and "pthread-config"
# which is a program returning the flags for the Pth emulation library.
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
# pthreads: AIX (must check this before -lpthread)
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
# -pthreads: Solaris/gcc
# -mthreads: Mingw32/gcc, Lynx/gcc
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads too;
# also defines -D_REENTRANT)
# ... -mt is also the pthreads flag for HP/aCC
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)
case ${host_os} in
solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
# a function called by this macro, so we could check for that, but
# who knows whether they'll stub that too in a future libc.) So,
# we'll just look for -pthreads and -lpthread first:
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
;;
darwin*)
ax_pthread_flags="none -pthread $ax_pthread_flags"
;;
esac
# Clang doesn't consider unrecognized options an error unless we specify
# -Werror. We throw in some extra Clang-specific options to ensure that
# this doesn't happen for GCC, which also accepts -Werror.
AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
save_CFLAGS="$CFLAGS"
ax_pthread_extra_flags="-Werror"
CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
[AC_MSG_RESULT([yes])],
[ax_pthread_extra_flags=
AC_MSG_RESULT([no])])
CFLAGS="$save_CFLAGS"
if test x"$ax_pthread_ok" = xno; then
for flag in $ax_pthread_flags; do
case $flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
-*)
AC_MSG_CHECKING([whether pthreads work with $flag])
PTHREAD_CFLAGS="$flag"
;;
pthread-config)
AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
if test x"$ax_pthread_config" = xno; then continue; fi
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
;;
*)
AC_MSG_CHECKING([for the pthreads library -l$flag])
PTHREAD_LIBS="-l$flag"
;;
esac
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
# need a special flag -Kthread to make this header compile.)
# We check for pthread_join because it is in -lpthread on IRIX
# while pthread_create is in libc. We check for pthread_attr_init
# due to DEC craziness with -lpthreads. We check for
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include
static void routine(void *a) { a = 0; }
static void *start_routine(void *a) { return a; }],
[pthread_t th; pthread_attr_t attr;
pthread_create(&th, 0, start_routine, 0);
pthread_join(th, 0);
pthread_attr_init(&attr);
pthread_cleanup_push(routine, 0);
pthread_cleanup_pop(0) /* ; */])],
[ax_pthread_ok=yes],
[])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
AC_MSG_RESULT([$ax_pthread_ok])
if test "x$ax_pthread_ok" = xyes; then
break;
fi
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
done
fi
# Various other checks:
if test "x$ax_pthread_ok" = xyes; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
AC_MSG_CHECKING([for joinable pthread attribute])
attr_name=unknown
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ],
[int attr = $attr; return attr /* ; */])],
[attr_name=$attr; break],
[])
done
AC_MSG_RESULT([$attr_name])
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name],
[Define to necessary symbol if this constant
uses a non-standard name on your system.])
fi
AC_MSG_CHECKING([if more special flags are required for pthreads])
flag=no
case ${host_os} in
aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
osf* | hpux*) flag="-D_REENTRANT";;
solaris*)
if test "$GCC" = "yes"; then
flag="-D_REENTRANT"
else
# TODO: What about Clang on Solaris?
flag="-mt -D_REENTRANT"
fi
;;
esac
AC_MSG_RESULT([$flag])
if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
[ax_cv_PTHREAD_PRIO_INHERIT], [
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]],
[[int i = PTHREAD_PRIO_INHERIT;]])],
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
[ax_cv_PTHREAD_PRIO_INHERIT=no])
])
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
# More AIX lossage: compile with *_r variant
if test "x$GCC" != xyes; then
case $host_os in
aix*)
AS_CASE(["x/$CC"],
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
[#handle absolute path differently from PATH based program lookup
AS_CASE(["x$CC"],
[x/*],
[AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
[AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
;;
esac
fi
fi
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
AC_SUBST([PTHREAD_LIBS])
AC_SUBST([PTHREAD_CFLAGS])
AC_SUBST([PTHREAD_CC])
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$ax_pthread_ok" = xyes; then
ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
:
else
ax_pthread_ok=no
$2
fi
AC_LANG_POP
])dnl AX_PTHREAD
nanomsg-0.8-beta/m4/dolt.m40000664000175000017500000001255512623652600016376 0ustar00travistravis00000000000000dnl dolt, a replacement for libtool
dnl Copyright © 2007-2010 Josh Triplett
dnl Copying and distribution of this file, with or without modification,
dnl are permitted in any medium without royalty provided the copyright
dnl notice and this notice are preserved.
dnl
dnl To use dolt, invoke the DOLT macro immediately after the libtool macros.
dnl Optionally, copy this file into acinclude.m4, to avoid the need to have it
dnl installed when running autoconf on your project.
AC_DEFUN([DOLT], [
AC_REQUIRE([AC_CANONICAL_HOST])
# dolt, a replacement for libtool
# Josh Triplett
AC_PATH_PROG([DOLT_BASH], [bash])
AC_MSG_CHECKING([if dolt supports this host])
dolt_supported=yes
AS_IF([test x$DOLT_BASH = x], [dolt_supported=no])
AS_IF([test x$GCC != xyes], [dolt_supported=no])
AS_CASE([$host],
[*-*-linux*|*-*-freebsd*], [pic_options='-fPIC'],
[*-apple-darwin*], [pic_options='-fno-common'],
[*mingw*|*nacl*], [pic_options='']
[*], [dolt_supported=no]
)
AS_IF([test x$dolt_supported = xno], [
AC_MSG_RESULT([no, falling back to libtool])
LTCOMPILE='$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(COMPILE)'
LTCXXCOMPILE='$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXXCOMPILE)'
m4_pattern_allow([AM_V_lt])
], [
AC_MSG_RESULT([yes, replacing libtool])
dnl Start writing out doltcompile.
cat <<__DOLTCOMPILE__EOF__ >doltcompile
#!$DOLT_BASH
__DOLTCOMPILE__EOF__
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
args=("$[]@")
for ((arg=0; arg<${#args@<:@@@:>@}; arg++)) ; do
if test x"${args@<:@$arg@:>@}" = x-o ; then
objarg=$((arg+1))
break
fi
done
if test x$objarg = x ; then
echo 'Error: no -o on compiler command line' 1>&2
exit 1
fi
lo="${args@<:@$objarg@:>@}"
obj="${lo%.lo}"
if test x"$lo" = x"$obj" ; then
echo "Error: libtool object file name \"$lo\" does not end in .lo" 1>&2
exit 1
fi
objbase="${obj##*/}"
__DOLTCOMPILE__EOF__
dnl Write out shared compilation code.
if test x$enable_shared = xyes; then
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
libobjdir="${obj%$objbase}.libs"
if test ! -d "$libobjdir" ; then
mkdir_out="$(mkdir "$libobjdir" 2>&1)"
mkdir_ret=$?
if test "$mkdir_ret" -ne 0 && test ! -d "$libobjdir" ; then
echo "$mkdir_out" 1>&2
exit $mkdir_ret
fi
fi
pic_object="$libobjdir/$objbase.o"
args@<:@$objarg@:>@="$pic_object"
__DOLTCOMPILE__EOF__
cat <<__DOLTCOMPILE__EOF__ >>doltcompile
"\${args@<:@@@:>@}" $pic_options -DPIC || exit \$?
__DOLTCOMPILE__EOF__
fi
dnl Write out static compilation code.
dnl Avoid duplicate compiler output if also building shared objects.
if test x$enable_static = xyes; then
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
non_pic_object="$obj.o"
args@<:@$objarg@:>@="$non_pic_object"
__DOLTCOMPILE__EOF__
if test x$enable_shared = xyes; then
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
"${args@<:@@@:>@}" >/dev/null 2>&1 || exit $?
__DOLTCOMPILE__EOF__
else
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
"${args@<:@@@:>@}" || exit $?
__DOLTCOMPILE__EOF__
fi
fi
dnl Write out the code to write the .lo file.
dnl The second line of the .lo file must match "^# Generated by .*libtool"
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
{
echo "# $lo - a libtool object file"
echo "# Generated by doltcompile, not libtool"
__DOLTCOMPILE__EOF__
if test x$enable_shared = xyes; then
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
echo "pic_object='.libs/${objbase}.o'"
__DOLTCOMPILE__EOF__
else
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
echo pic_object=none
__DOLTCOMPILE__EOF__
fi
if test x$enable_static = xyes; then
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
echo "non_pic_object='${objbase}.o'"
__DOLTCOMPILE__EOF__
else
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
echo non_pic_object=none
__DOLTCOMPILE__EOF__
fi
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
} > "$lo"
__DOLTCOMPILE__EOF__
dnl Done writing out doltcompile; substitute it for libtool compilation.
chmod +x doltcompile
LTCOMPILE='$(top_builddir)/doltcompile $(COMPILE)'
LTCXXCOMPILE='$(top_builddir)/doltcompile $(CXXCOMPILE)'
dnl automake ignores LTCOMPILE and LTCXXCOMPILE when it has separate CFLAGS for
dnl a target, so write out a libtool wrapper to handle that case.
dnl Note that doltlibtool does not handle inferred tags or option arguments
dnl without '=', because automake does not use them.
cat <<__DOLTLIBTOOL__EOF__ > doltlibtool
#!$DOLT_BASH
__DOLTLIBTOOL__EOF__
cat <<'__DOLTLIBTOOL__EOF__' >>doltlibtool
top_builddir_slash="${0%%doltlibtool}"
: ${top_builddir_slash:=./}
args=()
modeok=false
tagok=false
for arg in "$[]@"; do
case "$arg" in
--mode=compile) modeok=true ;;
--tag=CC|--tag=CXX) tagok=true ;;
--silent|--quiet) ;;
*) args@<:@${#args[@]}@:>@="$arg" ;;
esac
done
if $modeok && $tagok ; then
. ${top_builddir_slash}doltcompile "${args@<:@@@:>@}"
else
exec ${top_builddir_slash}libtool "$[]@"
fi
__DOLTLIBTOOL__EOF__
dnl Done writing out doltlibtool; substitute it for libtool.
chmod +x doltlibtool
LIBTOOL='$(top_builddir)/doltlibtool'
DOLT_CLEANFILES="doltlibtool doltcompile"
AC_SUBST(DOLT_CLEANFILES)
])
AC_SUBST(LTCOMPILE)
AC_SUBST(LTCXXCOMPILE)
# end dolt
])
nanomsg-0.8-beta/m4/libtool.m40000644000175000017500000106043412623652607017105 0ustar00travistravis00000000000000# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
#
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# Foundation, Inc.
# Written by Gordon Matzigkeit, 1996
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
m4_define([_LT_COPYING], [dnl
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# Foundation, Inc.
# Written by Gordon Matzigkeit, 1996
#
# This file is part of GNU Libtool.
#
# GNU Libtool is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# As a special exception to the GNU General Public License,
# if you distribute this file as part of a program or library that
# is built using GNU Libtool, you may include this file under the
# same distribution terms that you use for the rest of that program.
#
# GNU Libtool 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 for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Libtool; see the file COPYING. If not, a copy
# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
# obtained by writing to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
])
# serial 57 LT_INIT
# LT_PREREQ(VERSION)
# ------------------
# Complain and exit if this libtool version is less that VERSION.
m4_defun([LT_PREREQ],
[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
[m4_default([$3],
[m4_fatal([Libtool version $1 or higher is required],
63)])],
[$2])])
# _LT_CHECK_BUILDDIR
# ------------------
# Complain if the absolute build directory name contains unusual characters
m4_defun([_LT_CHECK_BUILDDIR],
[case `pwd` in
*\ * | *\ *)
AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
esac
])
# LT_INIT([OPTIONS])
# ------------------
AC_DEFUN([LT_INIT],
[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
AC_BEFORE([$0], [LT_LANG])dnl
AC_BEFORE([$0], [LT_OUTPUT])dnl
AC_BEFORE([$0], [LTDL_INIT])dnl
m4_require([_LT_CHECK_BUILDDIR])dnl
dnl Autoconf doesn't catch unexpanded LT_ macros by default:
m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
dnl unless we require an AC_DEFUNed macro:
AC_REQUIRE([LTOPTIONS_VERSION])dnl
AC_REQUIRE([LTSUGAR_VERSION])dnl
AC_REQUIRE([LTVERSION_VERSION])dnl
AC_REQUIRE([LTOBSOLETE_VERSION])dnl
m4_require([_LT_PROG_LTMAIN])dnl
_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
dnl Parse OPTIONS
_LT_SET_OPTIONS([$0], [$1])
# This can be used to rebuild libtool when needed
LIBTOOL_DEPS="$ltmain"
# Always use our own libtool.
LIBTOOL='$(SHELL) $(top_builddir)/libtool'
AC_SUBST(LIBTOOL)dnl
_LT_SETUP
# Only expand once:
m4_define([LT_INIT])
])# LT_INIT
# Old names:
AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
# _LT_CC_BASENAME(CC)
# -------------------
# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
m4_defun([_LT_CC_BASENAME],
[for cc_temp in $1""; do
case $cc_temp in
compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
\-*) ;;
*) break;;
esac
done
cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
])
# _LT_FILEUTILS_DEFAULTS
# ----------------------
# It is okay to use these file commands and assume they have been set
# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
m4_defun([_LT_FILEUTILS_DEFAULTS],
[: ${CP="cp -f"}
: ${MV="mv -f"}
: ${RM="rm -f"}
])# _LT_FILEUTILS_DEFAULTS
# _LT_SETUP
# ---------
m4_defun([_LT_SETUP],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
AC_REQUIRE([AC_CANONICAL_BUILD])dnl
AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
dnl
_LT_DECL([], [host_alias], [0], [The host system])dnl
_LT_DECL([], [host], [0])dnl
_LT_DECL([], [host_os], [0])dnl
dnl
_LT_DECL([], [build_alias], [0], [The build system])dnl
_LT_DECL([], [build], [0])dnl
_LT_DECL([], [build_os], [0])dnl
dnl
AC_REQUIRE([AC_PROG_CC])dnl
AC_REQUIRE([LT_PATH_LD])dnl
AC_REQUIRE([LT_PATH_NM])dnl
dnl
AC_REQUIRE([AC_PROG_LN_S])dnl
test -z "$LN_S" && LN_S="ln -s"
_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
dnl
AC_REQUIRE([LT_CMD_MAX_LEN])dnl
_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
dnl
m4_require([_LT_FILEUTILS_DEFAULTS])dnl
m4_require([_LT_CHECK_SHELL_FEATURES])dnl
m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
m4_require([_LT_CMD_RELOAD])dnl
m4_require([_LT_CHECK_MAGIC_METHOD])dnl
m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
m4_require([_LT_CMD_OLD_ARCHIVE])dnl
m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
m4_require([_LT_WITH_SYSROOT])dnl
_LT_CONFIG_LIBTOOL_INIT([
# See if we are running on zsh, and set the options which allow our
# commands through without removal of \ escapes INIT.
if test -n "\${ZSH_VERSION+set}" ; then
setopt NO_GLOB_SUBST
fi
])
if test -n "${ZSH_VERSION+set}" ; then
setopt NO_GLOB_SUBST
fi
_LT_CHECK_OBJDIR
m4_require([_LT_TAG_COMPILER])dnl
case $host_os in
aix3*)
# AIX sometimes has problems with the GCC collect2 program. For some
# reason, if we set the COLLECT_NAMES environment variable, the problems
# vanish in a puff of smoke.
if test "X${COLLECT_NAMES+set}" != Xset; then
COLLECT_NAMES=
export COLLECT_NAMES
fi
;;
esac
# Global variables:
ofile=libtool
can_build_shared=yes
# All known linkers require a `.a' archive for static linking (except MSVC,
# which needs '.lib').
libext=a
with_gnu_ld="$lt_cv_prog_gnu_ld"
old_CC="$CC"
old_CFLAGS="$CFLAGS"
# Set sane defaults for various variables
test -z "$CC" && CC=cc
test -z "$LTCC" && LTCC=$CC
test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
test -z "$LD" && LD=ld
test -z "$ac_objext" && ac_objext=o
_LT_CC_BASENAME([$compiler])
# Only perform the check for file, if the check method requires it
test -z "$MAGIC_CMD" && MAGIC_CMD=file
case $deplibs_check_method in
file_magic*)
if test "$file_magic_cmd" = '$MAGIC_CMD'; then
_LT_PATH_MAGIC
fi
;;
esac
# Use C for the default configuration in the libtool script
LT_SUPPORTED_TAG([CC])
_LT_LANG_C_CONFIG
_LT_LANG_DEFAULT_CONFIG
_LT_CONFIG_COMMANDS
])# _LT_SETUP
# _LT_PREPARE_SED_QUOTE_VARS
# --------------------------
# Define a few sed substitution that help us do robust quoting.
m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
[# Backslashify metacharacters that are still active within
# double-quoted strings.
sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
# Same as above, but do not quote variable references.
double_quote_subst='s/\([["`\\]]\)/\\\1/g'
# Sed substitution to delay expansion of an escaped shell variable in a
# double_quote_subst'ed string.
delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
# Sed substitution to delay expansion of an escaped single quote.
delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
# Sed substitution to avoid accidental globbing in evaled expressions
no_glob_subst='s/\*/\\\*/g'
])
# _LT_PROG_LTMAIN
# ---------------
# Note that this code is called both from `configure', and `config.status'
# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably,
# `config.status' has no value for ac_aux_dir unless we are using Automake,
# so we pass a copy along to make sure it has a sensible value anyway.
m4_defun([_LT_PROG_LTMAIN],
[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
ltmain="$ac_aux_dir/ltmain.sh"
])# _LT_PROG_LTMAIN
## ------------------------------------- ##
## Accumulate code for creating libtool. ##
## ------------------------------------- ##
# So that we can recreate a full libtool script including additional
# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
# in macros and then make a single call at the end using the `libtool'
# label.
# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
# ----------------------------------------
# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
m4_define([_LT_CONFIG_LIBTOOL_INIT],
[m4_ifval([$1],
[m4_append([_LT_OUTPUT_LIBTOOL_INIT],
[$1
])])])
# Initialize.
m4_define([_LT_OUTPUT_LIBTOOL_INIT])
# _LT_CONFIG_LIBTOOL([COMMANDS])
# ------------------------------
# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
m4_define([_LT_CONFIG_LIBTOOL],
[m4_ifval([$1],
[m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
[$1
])])])
# Initialize.
m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
# -----------------------------------------------------
m4_defun([_LT_CONFIG_SAVE_COMMANDS],
[_LT_CONFIG_LIBTOOL([$1])
_LT_CONFIG_LIBTOOL_INIT([$2])
])
# _LT_FORMAT_COMMENT([COMMENT])
# -----------------------------
# Add leading comment marks to the start of each line, and a trailing
# full-stop to the whole comment if one is not present already.
m4_define([_LT_FORMAT_COMMENT],
[m4_ifval([$1], [
m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
[['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
)])
## ------------------------ ##
## FIXME: Eliminate VARNAME ##
## ------------------------ ##
# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
# -------------------------------------------------------------------
# CONFIGNAME is the name given to the value in the libtool script.
# VARNAME is the (base) name used in the configure script.
# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
# VARNAME. Any other value will be used directly.
m4_define([_LT_DECL],
[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
[lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
[m4_ifval([$1], [$1], [$2])])
lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
m4_ifval([$4],
[lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
lt_dict_add_subkey([lt_decl_dict], [$2],
[tagged?], [m4_ifval([$5], [yes], [no])])])
])
# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
# --------------------------------------------------------
m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
# ------------------------------------------------
m4_define([lt_decl_tag_varnames],
[_lt_decl_filter([tagged?], [yes], $@)])
# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
# ---------------------------------------------------------
m4_define([_lt_decl_filter],
[m4_case([$#],
[0], [m4_fatal([$0: too few arguments: $#])],
[1], [m4_fatal([$0: too few arguments: $#: $1])],
[2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
[3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
[lt_dict_filter([lt_decl_dict], $@)])[]dnl
])
# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
# --------------------------------------------------
m4_define([lt_decl_quote_varnames],
[_lt_decl_filter([value], [1], $@)])
# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
# ---------------------------------------------------
m4_define([lt_decl_dquote_varnames],
[_lt_decl_filter([value], [2], $@)])
# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
# ---------------------------------------------------
m4_define([lt_decl_varnames_tagged],
[m4_assert([$# <= 2])dnl
_$0(m4_quote(m4_default([$1], [[, ]])),
m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
m4_define([_lt_decl_varnames_tagged],
[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
# ------------------------------------------------
m4_define([lt_decl_all_varnames],
[_$0(m4_quote(m4_default([$1], [[, ]])),
m4_if([$2], [],
m4_quote(lt_decl_varnames),
m4_quote(m4_shift($@))))[]dnl
])
m4_define([_lt_decl_all_varnames],
[lt_join($@, lt_decl_varnames_tagged([$1],
lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
])
# _LT_CONFIG_STATUS_DECLARE([VARNAME])
# ------------------------------------
# Quote a variable value, and forward it to `config.status' so that its
# declaration there will have the same value as in `configure'. VARNAME
# must have a single quote delimited value for this to work.
m4_define([_LT_CONFIG_STATUS_DECLARE],
[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
# _LT_CONFIG_STATUS_DECLARATIONS
# ------------------------------
# We delimit libtool config variables with single quotes, so when
# we write them to config.status, we have to be sure to quote all
# embedded single quotes properly. In configure, this macro expands
# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
#
# ='`$ECHO "$" | $SED "$delay_single_quote_subst"`'
m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
[m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
# _LT_LIBTOOL_TAGS
# ----------------
# Output comment and list of tags supported by the script
m4_defun([_LT_LIBTOOL_TAGS],
[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
available_tags="_LT_TAGS"dnl
])
# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
# -----------------------------------
# Extract the dictionary values for VARNAME (optionally with TAG) and
# expand to a commented shell variable setting:
#
# # Some comment about what VAR is for.
# visible_name=$lt_internal_name
m4_define([_LT_LIBTOOL_DECLARE],
[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
[description])))[]dnl
m4_pushdef([_libtool_name],
m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
[0], [_libtool_name=[$]$1],
[1], [_libtool_name=$lt_[]$1],
[2], [_libtool_name=$lt_[]$1],
[_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
])
# _LT_LIBTOOL_CONFIG_VARS
# -----------------------
# Produce commented declarations of non-tagged libtool config variables
# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
# section) are produced by _LT_LIBTOOL_TAG_VARS.
m4_defun([_LT_LIBTOOL_CONFIG_VARS],
[m4_foreach([_lt_var],
m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
[m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
# _LT_LIBTOOL_TAG_VARS(TAG)
# -------------------------
m4_define([_LT_LIBTOOL_TAG_VARS],
[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
[m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
# _LT_TAGVAR(VARNAME, [TAGNAME])
# ------------------------------
m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
# _LT_CONFIG_COMMANDS
# -------------------
# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of
# variables for single and double quote escaping we saved from calls
# to _LT_DECL, we can put quote escaped variables declarations
# into `config.status', and then the shell code to quote escape them in
# for loops in `config.status'. Finally, any additional code accumulated
# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
m4_defun([_LT_CONFIG_COMMANDS],
[AC_PROVIDE_IFELSE([LT_OUTPUT],
dnl If the libtool generation code has been placed in $CONFIG_LT,
dnl instead of duplicating it all over again into config.status,
dnl then we will have config.status run $CONFIG_LT later, so it
dnl needs to know what name is stored there:
[AC_CONFIG_COMMANDS([libtool],
[$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
dnl If the libtool generation code is destined for config.status,
dnl expand the accumulated commands and init code now:
[AC_CONFIG_COMMANDS([libtool],
[_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
])#_LT_CONFIG_COMMANDS
# Initialize.
m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
[
# The HP-UX ksh and POSIX shell print the target directory to stdout
# if CDPATH is set.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
sed_quote_subst='$sed_quote_subst'
double_quote_subst='$double_quote_subst'
delay_variable_subst='$delay_variable_subst'
_LT_CONFIG_STATUS_DECLARATIONS
LTCC='$LTCC'
LTCFLAGS='$LTCFLAGS'
compiler='$compiler_DEFAULT'
# A function that is used when there is no print builtin or printf.
func_fallback_echo ()
{
eval 'cat <<_LTECHO_EOF
\$[]1
_LTECHO_EOF'
}
# Quote evaled strings.
for var in lt_decl_all_varnames([[ \
]], lt_decl_quote_varnames); do
case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
*[[\\\\\\\`\\"\\\$]]*)
eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
;;
*)
eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
;;
esac
done
# Double-quote double-evaled strings.
for var in lt_decl_all_varnames([[ \
]], lt_decl_dquote_varnames); do
case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
*[[\\\\\\\`\\"\\\$]]*)
eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
;;
*)
eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
;;
esac
done
_LT_OUTPUT_LIBTOOL_INIT
])
# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
# ------------------------------------
# Generate a child script FILE with all initialization necessary to
# reuse the environment learned by the parent script, and make the
# file executable. If COMMENT is supplied, it is inserted after the
# `#!' sequence but before initialization text begins. After this
# macro, additional text can be appended to FILE to form the body of
# the child script. The macro ends with non-zero status if the
# file could not be fully written (such as if the disk is full).
m4_ifdef([AS_INIT_GENERATED],
[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
[m4_defun([_LT_GENERATED_FILE_INIT],
[m4_require([AS_PREPARE])]dnl
[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
[lt_write_fail=0
cat >$1 <<_ASEOF || lt_write_fail=1
#! $SHELL
# Generated by $as_me.
$2
SHELL=\${CONFIG_SHELL-$SHELL}
export SHELL
_ASEOF
cat >>$1 <<\_ASEOF || lt_write_fail=1
AS_SHELL_SANITIZE
_AS_PREPARE
exec AS_MESSAGE_FD>&1
_ASEOF
test $lt_write_fail = 0 && chmod +x $1[]dnl
m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
# LT_OUTPUT
# ---------
# This macro allows early generation of the libtool script (before
# AC_OUTPUT is called), incase it is used in configure for compilation
# tests.
AC_DEFUN([LT_OUTPUT],
[: ${CONFIG_LT=./config.lt}
AC_MSG_NOTICE([creating $CONFIG_LT])
_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
[# Run this file to recreate a libtool stub with the current configuration.])
cat >>"$CONFIG_LT" <<\_LTEOF
lt_cl_silent=false
exec AS_MESSAGE_LOG_FD>>config.log
{
echo
AS_BOX([Running $as_me.])
} >&AS_MESSAGE_LOG_FD
lt_cl_help="\
\`$as_me' creates a local libtool stub from the current configuration,
for use in further configure time tests before the real libtool is
generated.
Usage: $[0] [[OPTIONS]]
-h, --help print this help, then exit
-V, --version print version number, then exit
-q, --quiet do not print progress messages
-d, --debug don't remove temporary files
Report bugs to ."
lt_cl_version="\
m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
configured by $[0], generated by m4_PACKAGE_STRING.
Copyright (C) 2011 Free Software Foundation, Inc.
This config.lt script is free software; the Free Software Foundation
gives unlimited permision to copy, distribute and modify it."
while test $[#] != 0
do
case $[1] in
--version | --v* | -V )
echo "$lt_cl_version"; exit 0 ;;
--help | --h* | -h )
echo "$lt_cl_help"; exit 0 ;;
--debug | --d* | -d )
debug=: ;;
--quiet | --q* | --silent | --s* | -q )
lt_cl_silent=: ;;
-*) AC_MSG_ERROR([unrecognized option: $[1]
Try \`$[0] --help' for more information.]) ;;
*) AC_MSG_ERROR([unrecognized argument: $[1]
Try \`$[0] --help' for more information.]) ;;
esac
shift
done
if $lt_cl_silent; then
exec AS_MESSAGE_FD>/dev/null
fi
_LTEOF
cat >>"$CONFIG_LT" <<_LTEOF
_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
_LTEOF
cat >>"$CONFIG_LT" <<\_LTEOF
AC_MSG_NOTICE([creating $ofile])
_LT_OUTPUT_LIBTOOL_COMMANDS
AS_EXIT(0)
_LTEOF
chmod +x "$CONFIG_LT"
# configure is writing to config.log, but config.lt does its own redirection,
# appending to config.log, which fails on DOS, as config.log is still kept
# open by configure. Here we exec the FD to /dev/null, effectively closing
# config.log, so it can be properly (re)opened and appended to by config.lt.
lt_cl_success=:
test "$silent" = yes &&
lt_config_lt_args="$lt_config_lt_args --quiet"
exec AS_MESSAGE_LOG_FD>/dev/null
$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
exec AS_MESSAGE_LOG_FD>>config.log
$lt_cl_success || AS_EXIT(1)
])# LT_OUTPUT
# _LT_CONFIG(TAG)
# ---------------
# If TAG is the built-in tag, create an initial libtool script with a
# default configuration from the untagged config vars. Otherwise add code
# to config.status for appending the configuration named by TAG from the
# matching tagged config vars.
m4_defun([_LT_CONFIG],
[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
_LT_CONFIG_SAVE_COMMANDS([
m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
m4_if(_LT_TAG, [C], [
# See if we are running on zsh, and set the options which allow our
# commands through without removal of \ escapes.
if test -n "${ZSH_VERSION+set}" ; then
setopt NO_GLOB_SUBST
fi
cfgfile="${ofile}T"
trap "$RM \"$cfgfile\"; exit 1" 1 2 15
$RM "$cfgfile"
cat <<_LT_EOF >> "$cfgfile"
#! $SHELL
# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
# NOTE: Changes made to this file will be lost: look at ltmain.sh.
#
_LT_COPYING
_LT_LIBTOOL_TAGS
# ### BEGIN LIBTOOL CONFIG
_LT_LIBTOOL_CONFIG_VARS
_LT_LIBTOOL_TAG_VARS
# ### END LIBTOOL CONFIG
_LT_EOF
case $host_os in
aix3*)
cat <<\_LT_EOF >> "$cfgfile"
# AIX sometimes has problems with the GCC collect2 program. For some
# reason, if we set the COLLECT_NAMES environment variable, the problems
# vanish in a puff of smoke.
if test "X${COLLECT_NAMES+set}" != Xset; then
COLLECT_NAMES=
export COLLECT_NAMES
fi
_LT_EOF
;;
esac
_LT_PROG_LTMAIN
# We use sed instead of cat because bash on DJGPP gets confused if
# if finds mixed CR/LF and LF-only lines. Since sed operates in
# text mode, it properly converts lines to CR/LF. This bash problem
# is reportedly fixed, but why not run on old versions too?
sed '$q' "$ltmain" >> "$cfgfile" \
|| (rm -f "$cfgfile"; exit 1)
_LT_PROG_REPLACE_SHELLFNS
mv -f "$cfgfile" "$ofile" ||
(rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
chmod +x "$ofile"
],
[cat <<_LT_EOF >> "$ofile"
dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
dnl in a comment (ie after a #).
# ### BEGIN LIBTOOL TAG CONFIG: $1
_LT_LIBTOOL_TAG_VARS(_LT_TAG)
# ### END LIBTOOL TAG CONFIG: $1
_LT_EOF
])dnl /m4_if
],
[m4_if([$1], [], [
PACKAGE='$PACKAGE'
VERSION='$VERSION'
TIMESTAMP='$TIMESTAMP'
RM='$RM'
ofile='$ofile'], [])
])dnl /_LT_CONFIG_SAVE_COMMANDS
])# _LT_CONFIG
# LT_SUPPORTED_TAG(TAG)
# ---------------------
# Trace this macro to discover what tags are supported by the libtool
# --tag option, using:
# autoconf --trace 'LT_SUPPORTED_TAG:$1'
AC_DEFUN([LT_SUPPORTED_TAG], [])
# C support is built-in for now
m4_define([_LT_LANG_C_enabled], [])
m4_define([_LT_TAGS], [])
# LT_LANG(LANG)
# -------------
# Enable libtool support for the given language if not already enabled.
AC_DEFUN([LT_LANG],
[AC_BEFORE([$0], [LT_OUTPUT])dnl
m4_case([$1],
[C], [_LT_LANG(C)],
[C++], [_LT_LANG(CXX)],
[Go], [_LT_LANG(GO)],
[Java], [_LT_LANG(GCJ)],
[Fortran 77], [_LT_LANG(F77)],
[Fortran], [_LT_LANG(FC)],
[Windows Resource], [_LT_LANG(RC)],
[m4_ifdef([_LT_LANG_]$1[_CONFIG],
[_LT_LANG($1)],
[m4_fatal([$0: unsupported language: "$1"])])])dnl
])# LT_LANG
# _LT_LANG(LANGNAME)
# ------------------
m4_defun([_LT_LANG],
[m4_ifdef([_LT_LANG_]$1[_enabled], [],
[LT_SUPPORTED_TAG([$1])dnl
m4_append([_LT_TAGS], [$1 ])dnl
m4_define([_LT_LANG_]$1[_enabled], [])dnl
_LT_LANG_$1_CONFIG($1)])dnl
])# _LT_LANG
m4_ifndef([AC_PROG_GO], [
############################################################
# NOTE: This macro has been submitted for inclusion into #
# GNU Autoconf as AC_PROG_GO. When it is available in #
# a released version of Autoconf we should remove this #
# macro and use it instead. #
############################################################
m4_defun([AC_PROG_GO],
[AC_LANG_PUSH(Go)dnl
AC_ARG_VAR([GOC], [Go compiler command])dnl
AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
_AC_ARG_VAR_LDFLAGS()dnl
AC_CHECK_TOOL(GOC, gccgo)
if test -z "$GOC"; then
if test -n "$ac_tool_prefix"; then
AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
fi
fi
if test -z "$GOC"; then
AC_CHECK_PROG(GOC, gccgo, gccgo, false)
fi
])#m4_defun
])#m4_ifndef
# _LT_LANG_DEFAULT_CONFIG
# -----------------------
m4_defun([_LT_LANG_DEFAULT_CONFIG],
[AC_PROVIDE_IFELSE([AC_PROG_CXX],
[LT_LANG(CXX)],
[m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
AC_PROVIDE_IFELSE([AC_PROG_F77],
[LT_LANG(F77)],
[m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
AC_PROVIDE_IFELSE([AC_PROG_FC],
[LT_LANG(FC)],
[m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
dnl pulling things in needlessly.
AC_PROVIDE_IFELSE([AC_PROG_GCJ],
[LT_LANG(GCJ)],
[AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
[LT_LANG(GCJ)],
[AC_PROVIDE_IFELSE([LT_PROG_GCJ],
[LT_LANG(GCJ)],
[m4_ifdef([AC_PROG_GCJ],
[m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
m4_ifdef([A][M_PROG_GCJ],
[m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
m4_ifdef([LT_PROG_GCJ],
[m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
AC_PROVIDE_IFELSE([AC_PROG_GO],
[LT_LANG(GO)],
[m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
AC_PROVIDE_IFELSE([LT_PROG_RC],
[LT_LANG(RC)],
[m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
])# _LT_LANG_DEFAULT_CONFIG
# Obsolete macros:
AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
dnl AC_DEFUN([AC_LIBTOOL_F77], [])
dnl AC_DEFUN([AC_LIBTOOL_FC], [])
dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
dnl AC_DEFUN([AC_LIBTOOL_RC], [])
# _LT_TAG_COMPILER
# ----------------
m4_defun([_LT_TAG_COMPILER],
[AC_REQUIRE([AC_PROG_CC])dnl
_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
# If no C compiler was specified, use CC.
LTCC=${LTCC-"$CC"}
# If no C compiler flags were specified, use CFLAGS.
LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
# Allow CC to be a program name with arguments.
compiler=$CC
])# _LT_TAG_COMPILER
# _LT_COMPILER_BOILERPLATE
# ------------------------
# Check for compiler boilerplate output or warnings with
# the simple compiler test code.
m4_defun([_LT_COMPILER_BOILERPLATE],
[m4_require([_LT_DECL_SED])dnl
ac_outfile=conftest.$ac_objext
echo "$lt_simple_compile_test_code" >conftest.$ac_ext
eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
_lt_compiler_boilerplate=`cat conftest.err`
$RM conftest*
])# _LT_COMPILER_BOILERPLATE
# _LT_LINKER_BOILERPLATE
# ----------------------
# Check for linker boilerplate output or warnings with
# the simple link test code.
m4_defun([_LT_LINKER_BOILERPLATE],
[m4_require([_LT_DECL_SED])dnl
ac_outfile=conftest.$ac_objext
echo "$lt_simple_link_test_code" >conftest.$ac_ext
eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
_lt_linker_boilerplate=`cat conftest.err`
$RM -r conftest*
])# _LT_LINKER_BOILERPLATE
# _LT_REQUIRED_DARWIN_CHECKS
# -------------------------
m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
case $host_os in
rhapsody* | darwin*)
AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
AC_CHECK_TOOL([LIPO], [lipo], [:])
AC_CHECK_TOOL([OTOOL], [otool], [:])
AC_CHECK_TOOL([OTOOL64], [otool64], [:])
_LT_DECL([], [DSYMUTIL], [1],
[Tool to manipulate archived DWARF debug symbol files on Mac OS X])
_LT_DECL([], [NMEDIT], [1],
[Tool to change global to local symbols on Mac OS X])
_LT_DECL([], [LIPO], [1],
[Tool to manipulate fat objects and archives on Mac OS X])
_LT_DECL([], [OTOOL], [1],
[ldd/readelf like tool for Mach-O binaries on Mac OS X])
_LT_DECL([], [OTOOL64], [1],
[ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
[lt_cv_apple_cc_single_mod=no
if test -z "${LT_MULTI_MODULE}"; then
# By default we will add the -single_module flag. You can override
# by either setting the environment variable LT_MULTI_MODULE
# non-empty at configure time, or by adding -multi_module to the
# link flags.
rm -rf libconftest.dylib*
echo "int foo(void){return 1;}" > conftest.c
echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
-dynamiclib -Wl,-single_module conftest.c 2>conftest.err
_lt_result=$?
# If there is a non-empty error log, and "single_module"
# appears in it, assume the flag caused a linker warning
if test -s conftest.err && $GREP single_module conftest.err; then
cat conftest.err >&AS_MESSAGE_LOG_FD
# Otherwise, if the output was created with a 0 exit code from
# the compiler, it worked.
elif test -f libconftest.dylib && test $_lt_result -eq 0; then
lt_cv_apple_cc_single_mod=yes
else
cat conftest.err >&AS_MESSAGE_LOG_FD
fi
rm -rf libconftest.dylib*
rm -f conftest.*
fi])
AC_CACHE_CHECK([for -exported_symbols_list linker flag],
[lt_cv_ld_exported_symbols_list],
[lt_cv_ld_exported_symbols_list=no
save_LDFLAGS=$LDFLAGS
echo "_main" > conftest.sym
LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
[lt_cv_ld_exported_symbols_list=yes],
[lt_cv_ld_exported_symbols_list=no])
LDFLAGS="$save_LDFLAGS"
])
AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
[lt_cv_ld_force_load=no
cat > conftest.c << _LT_EOF
int forced_loaded() { return 2;}
_LT_EOF
echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
$LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
$AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
$RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
cat > conftest.c << _LT_EOF
int main() { return 0;}
_LT_EOF
echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
_lt_result=$?
if test -s conftest.err && $GREP force_load conftest.err; then
cat conftest.err >&AS_MESSAGE_LOG_FD
elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
lt_cv_ld_force_load=yes
else
cat conftest.err >&AS_MESSAGE_LOG_FD
fi
rm -f conftest.err libconftest.a conftest conftest.c
rm -rf conftest.dSYM
])
case $host_os in
rhapsody* | darwin1.[[012]])
_lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
darwin1.*)
_lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
darwin*) # darwin 5.x on
# if running on 10.5 or later, the deployment target defaults
# to the OS version, if on x86, and 10.4, the deployment
# target defaults to 10.4. Don't you love it?
case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
_lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
10.[[012]]*)
_lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
10.*)
_lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
esac
;;
esac
if test "$lt_cv_apple_cc_single_mod" = "yes"; then
_lt_dar_single_mod='$single_module'
fi
if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
_lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
else
_lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
fi
if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
_lt_dsymutil='~$DSYMUTIL $lib || :'
else
_lt_dsymutil=
fi
;;
esac
])
# _LT_DARWIN_LINKER_FEATURES([TAG])
# ---------------------------------
# Checks for linker and compiler features on darwin
m4_defun([_LT_DARWIN_LINKER_FEATURES],
[
m4_require([_LT_REQUIRED_DARWIN_CHECKS])
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(hardcode_direct, $1)=no
_LT_TAGVAR(hardcode_automatic, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
if test "$lt_cv_ld_force_load" = "yes"; then
_LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
[FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes])
else
_LT_TAGVAR(whole_archive_flag_spec, $1)=''
fi
_LT_TAGVAR(link_all_deplibs, $1)=yes
_LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
case $cc_basename in
ifort*) _lt_dar_can_shared=yes ;;
*) _lt_dar_can_shared=$GCC ;;
esac
if test "$_lt_dar_can_shared" = "yes"; then
output_verbose_link_cmd=func_echo_all
_LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
_LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
_LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
_LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
m4_if([$1], [CXX],
[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then
_LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
_LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
fi
],[])
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
])
# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
# ----------------------------------
# Links a minimal program and checks the executable
# for the system default hardcoded library path. In most cases,
# this is /usr/lib:/lib, but when the MPI compilers are used
# the location of the communication and MPI libs are included too.
# If we don't find anything, use the default library path according
# to the aix ld manual.
# Store the results from the different compilers for each TAGNAME.
# Allow to override them for all tags through lt_cv_aix_libpath.
m4_defun([_LT_SYS_MODULE_PATH_AIX],
[m4_require([_LT_DECL_SED])dnl
if test "${lt_cv_aix_libpath+set}" = set; then
aix_libpath=$lt_cv_aix_libpath
else
AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
[AC_LINK_IFELSE([AC_LANG_PROGRAM],[
lt_aix_libpath_sed='[
/Import File Strings/,/^$/ {
/^0/ {
s/^0 *\([^ ]*\) *$/\1/
p
}
}]'
_LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
# Check for a 64-bit object if we didn't find anything.
if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
_LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
fi],[])
if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
_LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
fi
])
aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
fi
])# _LT_SYS_MODULE_PATH_AIX
# _LT_SHELL_INIT(ARG)
# -------------------
m4_define([_LT_SHELL_INIT],
[m4_divert_text([M4SH-INIT], [$1
])])# _LT_SHELL_INIT
# _LT_PROG_ECHO_BACKSLASH
# -----------------------
# Find how we can fake an echo command that does not interpret backslash.
# In particular, with Autoconf 2.60 or later we add some code to the start
# of the generated configure script which will find a shell with a builtin
# printf (which we can use as an echo command).
m4_defun([_LT_PROG_ECHO_BACKSLASH],
[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
AC_MSG_CHECKING([how to print strings])
# Test print first, because it will be a builtin if present.
if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
ECHO='print -r --'
elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
ECHO='printf %s\n'
else
# Use this function as a fallback that always works.
func_fallback_echo ()
{
eval 'cat <<_LTECHO_EOF
$[]1
_LTECHO_EOF'
}
ECHO='func_fallback_echo'
fi
# func_echo_all arg...
# Invoke $ECHO with all args, space-separated.
func_echo_all ()
{
$ECHO "$*"
}
case "$ECHO" in
printf*) AC_MSG_RESULT([printf]) ;;
print*) AC_MSG_RESULT([print -r]) ;;
*) AC_MSG_RESULT([cat]) ;;
esac
m4_ifdef([_AS_DETECT_SUGGESTED],
[_AS_DETECT_SUGGESTED([
test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
PATH=/empty FPATH=/empty; export PATH FPATH
test "X`printf %s $ECHO`" = "X$ECHO" \
|| test "X`print -r -- $ECHO`" = "X$ECHO" )])])
_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
])# _LT_PROG_ECHO_BACKSLASH
# _LT_WITH_SYSROOT
# ----------------
AC_DEFUN([_LT_WITH_SYSROOT],
[AC_MSG_CHECKING([for sysroot])
AC_ARG_WITH([sysroot],
[ --with-sysroot[=DIR] Search for dependent libraries within DIR
(or the compiler's sysroot if not specified).],
[], [with_sysroot=no])
dnl lt_sysroot will always be passed unquoted. We quote it here
dnl in case the user passed a directory name.
lt_sysroot=
case ${with_sysroot} in #(
yes)
if test "$GCC" = yes; then
lt_sysroot=`$CC --print-sysroot 2>/dev/null`
fi
;; #(
/*)
lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
;; #(
no|'')
;; #(
*)
AC_MSG_RESULT([${with_sysroot}])
AC_MSG_ERROR([The sysroot must be an absolute path.])
;;
esac
AC_MSG_RESULT([${lt_sysroot:-no}])
_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
[dependent libraries, and in which our libraries should be installed.])])
# _LT_ENABLE_LOCK
# ---------------
m4_defun([_LT_ENABLE_LOCK],
[AC_ARG_ENABLE([libtool-lock],
[AS_HELP_STRING([--disable-libtool-lock],
[avoid locking (might break parallel builds)])])
test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
# Some flags need to be propagated to the compiler or linker for good
# libtool support.
case $host in
ia64-*-hpux*)
# Find out which ABI we are using.
echo 'int i;' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
case `/usr/bin/file conftest.$ac_objext` in
*ELF-32*)
HPUX_IA64_MODE="32"
;;
*ELF-64*)
HPUX_IA64_MODE="64"
;;
esac
fi
rm -rf conftest*
;;
*-*-irix6*)
# Find out which ABI we are using.
echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
if test "$lt_cv_prog_gnu_ld" = yes; then
case `/usr/bin/file conftest.$ac_objext` in
*32-bit*)
LD="${LD-ld} -melf32bsmip"
;;
*N32*)
LD="${LD-ld} -melf32bmipn32"
;;
*64-bit*)
LD="${LD-ld} -melf64bmip"
;;
esac
else
case `/usr/bin/file conftest.$ac_objext` in
*32-bit*)
LD="${LD-ld} -32"
;;
*N32*)
LD="${LD-ld} -n32"
;;
*64-bit*)
LD="${LD-ld} -64"
;;
esac
fi
fi
rm -rf conftest*
;;
x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
# Find out which ABI we are using.
echo 'int i;' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
case `/usr/bin/file conftest.o` in
*32-bit*)
case $host in
x86_64-*kfreebsd*-gnu)
LD="${LD-ld} -m elf_i386_fbsd"
;;
x86_64-*linux*)
LD="${LD-ld} -m elf_i386"
;;
ppc64-*linux*|powerpc64-*linux*)
LD="${LD-ld} -m elf32ppclinux"
;;
s390x-*linux*)
LD="${LD-ld} -m elf_s390"
;;
sparc64-*linux*)
LD="${LD-ld} -m elf32_sparc"
;;
esac
;;
*64-bit*)
case $host in
x86_64-*kfreebsd*-gnu)
LD="${LD-ld} -m elf_x86_64_fbsd"
;;
x86_64-*linux*)
LD="${LD-ld} -m elf_x86_64"
;;
ppc*-*linux*|powerpc*-*linux*)
LD="${LD-ld} -m elf64ppc"
;;
s390*-*linux*|s390*-*tpf*)
LD="${LD-ld} -m elf64_s390"
;;
sparc*-*linux*)
LD="${LD-ld} -m elf64_sparc"
;;
esac
;;
esac
fi
rm -rf conftest*
;;
*-*-sco3.2v5*)
# On SCO OpenServer 5, we need -belf to get full-featured binaries.
SAVE_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -belf"
AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
[AC_LANG_PUSH(C)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
AC_LANG_POP])
if test x"$lt_cv_cc_needs_belf" != x"yes"; then
# this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
CFLAGS="$SAVE_CFLAGS"
fi
;;
*-*solaris*)
# Find out which ABI we are using.
echo 'int i;' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
case `/usr/bin/file conftest.o` in
*64-bit*)
case $lt_cv_prog_gnu_ld in
yes*)
case $host in
i?86-*-solaris*)
LD="${LD-ld} -m elf_x86_64"
;;
sparc*-*-solaris*)
LD="${LD-ld} -m elf64_sparc"
;;
esac
# GNU ld 2.21 introduced _sol2 emulations. Use them if available.
if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
LD="${LD-ld}_sol2"
fi
;;
*)
if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
LD="${LD-ld} -64"
fi
;;
esac
;;
esac
fi
rm -rf conftest*
;;
esac
need_locks="$enable_libtool_lock"
])# _LT_ENABLE_LOCK
# _LT_PROG_AR
# -----------
m4_defun([_LT_PROG_AR],
[AC_CHECK_TOOLS(AR, [ar], false)
: ${AR=ar}
: ${AR_FLAGS=cru}
_LT_DECL([], [AR], [1], [The archiver])
_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
[lt_cv_ar_at_file=no
AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
[echo conftest.$ac_objext > conftest.lst
lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
AC_TRY_EVAL([lt_ar_try])
if test "$ac_status" -eq 0; then
# Ensure the archiver fails upon bogus file names.
rm -f conftest.$ac_objext libconftest.a
AC_TRY_EVAL([lt_ar_try])
if test "$ac_status" -ne 0; then
lt_cv_ar_at_file=@
fi
fi
rm -f conftest.* libconftest.a
])
])
if test "x$lt_cv_ar_at_file" = xno; then
archiver_list_spec=
else
archiver_list_spec=$lt_cv_ar_at_file
fi
_LT_DECL([], [archiver_list_spec], [1],
[How to feed a file listing to the archiver])
])# _LT_PROG_AR
# _LT_CMD_OLD_ARCHIVE
# -------------------
m4_defun([_LT_CMD_OLD_ARCHIVE],
[_LT_PROG_AR
AC_CHECK_TOOL(STRIP, strip, :)
test -z "$STRIP" && STRIP=:
_LT_DECL([], [STRIP], [1], [A symbol stripping program])
AC_CHECK_TOOL(RANLIB, ranlib, :)
test -z "$RANLIB" && RANLIB=:
_LT_DECL([], [RANLIB], [1],
[Commands used to install an old-style archive])
# Determine commands to create old-style static archives.
old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
old_postinstall_cmds='chmod 644 $oldlib'
old_postuninstall_cmds=
if test -n "$RANLIB"; then
case $host_os in
openbsd*)
old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
;;
*)
old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
;;
esac
old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
fi
case $host_os in
darwin*)
lock_old_archive_extraction=yes ;;
*)
lock_old_archive_extraction=no ;;
esac
_LT_DECL([], [old_postinstall_cmds], [2])
_LT_DECL([], [old_postuninstall_cmds], [2])
_LT_TAGDECL([], [old_archive_cmds], [2],
[Commands used to build an old-style archive])
_LT_DECL([], [lock_old_archive_extraction], [0],
[Whether to use a lock for old archive extraction])
])# _LT_CMD_OLD_ARCHIVE
# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
# ----------------------------------------------------------------
# Check whether the given compiler option works
AC_DEFUN([_LT_COMPILER_OPTION],
[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
m4_require([_LT_DECL_SED])dnl
AC_CACHE_CHECK([$1], [$2],
[$2=no
m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
lt_compiler_flag="$3"
# Insert the option either (1) after the last *FLAGS variable, or
# (2) before a word containing "conftest.", or (3) at the end.
# Note that $ac_compile itself does not contain backslashes and begins
# with a dollar sign (not a hyphen), so the echo should work correctly.
# The option is referenced via a variable to avoid confusing sed.
lt_compile=`echo "$ac_compile" | $SED \
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&AS_MESSAGE_LOG_FD
echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
$ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
$SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
$2=yes
fi
fi
$RM conftest*
])
if test x"[$]$2" = xyes; then
m4_if([$5], , :, [$5])
else
m4_if([$6], , :, [$6])
fi
])# _LT_COMPILER_OPTION
# Old name:
AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
# [ACTION-SUCCESS], [ACTION-FAILURE])
# ----------------------------------------------------
# Check whether the given linker option works
AC_DEFUN([_LT_LINKER_OPTION],
[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
m4_require([_LT_DECL_SED])dnl
AC_CACHE_CHECK([$1], [$2],
[$2=no
save_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS $3"
echo "$lt_simple_link_test_code" > conftest.$ac_ext
if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
# The linker can only warn and ignore the option if not recognized
# So say no if there are warnings
if test -s conftest.err; then
# Append any errors to the config.log.
cat conftest.err 1>&AS_MESSAGE_LOG_FD
$ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
$SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
if diff conftest.exp conftest.er2 >/dev/null; then
$2=yes
fi
else
$2=yes
fi
fi
$RM -r conftest*
LDFLAGS="$save_LDFLAGS"
])
if test x"[$]$2" = xyes; then
m4_if([$4], , :, [$4])
else
m4_if([$5], , :, [$5])
fi
])# _LT_LINKER_OPTION
# Old name:
AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
# LT_CMD_MAX_LEN
#---------------
AC_DEFUN([LT_CMD_MAX_LEN],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
# find the maximum length of command line arguments
AC_MSG_CHECKING([the maximum length of command line arguments])
AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
i=0
teststring="ABCD"
case $build_os in
msdosdjgpp*)
# On DJGPP, this test can blow up pretty badly due to problems in libc
# (any single argument exceeding 2000 bytes causes a buffer overrun
# during glob expansion). Even if it were fixed, the result of this
# check would be larger than it should be.
lt_cv_sys_max_cmd_len=12288; # 12K is about right
;;
gnu*)
# Under GNU Hurd, this test is not required because there is
# no limit to the length of command line arguments.
# Libtool will interpret -1 as no limit whatsoever
lt_cv_sys_max_cmd_len=-1;
;;
cygwin* | mingw* | cegcc*)
# On Win9x/ME, this test blows up -- it succeeds, but takes
# about 5 minutes as the teststring grows exponentially.
# Worse, since 9x/ME are not pre-emptively multitasking,
# you end up with a "frozen" computer, even though with patience
# the test eventually succeeds (with a max line length of 256k).
# Instead, let's just punt: use the minimum linelength reported by
# all of the supported platforms: 8192 (on NT/2K/XP).
lt_cv_sys_max_cmd_len=8192;
;;
mint*)
# On MiNT this can take a long time and run out of memory.
lt_cv_sys_max_cmd_len=8192;
;;
amigaos*)
# On AmigaOS with pdksh, this test takes hours, literally.
# So we just punt and use a minimum line length of 8192.
lt_cv_sys_max_cmd_len=8192;
;;
netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
# This has been around since 386BSD, at least. Likely further.
if test -x /sbin/sysctl; then
lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
elif test -x /usr/sbin/sysctl; then
lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
else
lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
fi
# And add a safety zone
lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
;;
interix*)
# We know the value 262144 and hardcode it with a safety zone (like BSD)
lt_cv_sys_max_cmd_len=196608
;;
os2*)
# The test takes a long time on OS/2.
lt_cv_sys_max_cmd_len=8192
;;
osf*)
# Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
# due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
# nice to cause kernel panics so lets avoid the loop below.
# First set a reasonable default.
lt_cv_sys_max_cmd_len=16384
#
if test -x /sbin/sysconfig; then
case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
*1*) lt_cv_sys_max_cmd_len=-1 ;;
esac
fi
;;
sco3.2v5*)
lt_cv_sys_max_cmd_len=102400
;;
sysv5* | sco5v6* | sysv4.2uw2*)
kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
if test -n "$kargmax"; then
lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
else
lt_cv_sys_max_cmd_len=32768
fi
;;
*)
lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
if test -n "$lt_cv_sys_max_cmd_len"; then
lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
else
# Make teststring a little bigger before we do anything with it.
# a 1K string should be a reasonable start.
for i in 1 2 3 4 5 6 7 8 ; do
teststring=$teststring$teststring
done
SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
# If test is not a shell built-in, we'll probably end up computing a
# maximum length that is only half of the actual maximum length, but
# we can't tell.
while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
= "X$teststring$teststring"; } >/dev/null 2>&1 &&
test $i != 17 # 1/2 MB should be enough
do
i=`expr $i + 1`
teststring=$teststring$teststring
done
# Only check the string length outside the loop.
lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
teststring=
# Add a significant safety factor because C++ compilers can tack on
# massive amounts of additional arguments before passing them to the
# linker. It appears as though 1/2 is a usable value.
lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
fi
;;
esac
])
if test -n $lt_cv_sys_max_cmd_len ; then
AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
else
AC_MSG_RESULT(none)
fi
max_cmd_len=$lt_cv_sys_max_cmd_len
_LT_DECL([], [max_cmd_len], [0],
[What is the maximum length of a command?])
])# LT_CMD_MAX_LEN
# Old name:
AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
# _LT_HEADER_DLFCN
# ----------------
m4_defun([_LT_HEADER_DLFCN],
[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
])# _LT_HEADER_DLFCN
# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
# ----------------------------------------------------------------
m4_defun([_LT_TRY_DLOPEN_SELF],
[m4_require([_LT_HEADER_DLFCN])dnl
if test "$cross_compiling" = yes; then :
[$4]
else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
[#line $LINENO "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
#include
#endif
#include
#ifdef RTLD_GLOBAL
# define LT_DLGLOBAL RTLD_GLOBAL
#else
# ifdef DL_GLOBAL
# define LT_DLGLOBAL DL_GLOBAL
# else
# define LT_DLGLOBAL 0
# endif
#endif
/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
find out it does not work in some platform. */
#ifndef LT_DLLAZY_OR_NOW
# ifdef RTLD_LAZY
# define LT_DLLAZY_OR_NOW RTLD_LAZY
# else
# ifdef DL_LAZY
# define LT_DLLAZY_OR_NOW DL_LAZY
# else
# ifdef RTLD_NOW
# define LT_DLLAZY_OR_NOW RTLD_NOW
# else
# ifdef DL_NOW
# define LT_DLLAZY_OR_NOW DL_NOW
# else
# define LT_DLLAZY_OR_NOW 0
# endif
# endif
# endif
# endif
#endif
/* When -fvisbility=hidden is used, assume the code has been annotated
correspondingly for the symbols needed. */
#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
int fnord () __attribute__((visibility("default")));
#endif
int fnord () { return 42; }
int main ()
{
void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
int status = $lt_dlunknown;
if (self)
{
if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
else
{
if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
else puts (dlerror ());
}
/* dlclose (self); */
}
else
puts (dlerror ());
return status;
}]
_LT_EOF
if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
(./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
lt_status=$?
case x$lt_status in
x$lt_dlno_uscore) $1 ;;
x$lt_dlneed_uscore) $2 ;;
x$lt_dlunknown|x*) $3 ;;
esac
else :
# compilation failed
$3
fi
fi
rm -fr conftest*
])# _LT_TRY_DLOPEN_SELF
# LT_SYS_DLOPEN_SELF
# ------------------
AC_DEFUN([LT_SYS_DLOPEN_SELF],
[m4_require([_LT_HEADER_DLFCN])dnl
if test "x$enable_dlopen" != xyes; then
enable_dlopen=unknown
enable_dlopen_self=unknown
enable_dlopen_self_static=unknown
else
lt_cv_dlopen=no
lt_cv_dlopen_libs=
case $host_os in
beos*)
lt_cv_dlopen="load_add_on"
lt_cv_dlopen_libs=
lt_cv_dlopen_self=yes
;;
mingw* | pw32* | cegcc*)
lt_cv_dlopen="LoadLibrary"
lt_cv_dlopen_libs=
;;
cygwin*)
lt_cv_dlopen="dlopen"
lt_cv_dlopen_libs=
;;
darwin*)
# if libdl is installed we need to link against it
AC_CHECK_LIB([dl], [dlopen],
[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
lt_cv_dlopen="dyld"
lt_cv_dlopen_libs=
lt_cv_dlopen_self=yes
])
;;
*)
AC_CHECK_FUNC([shl_load],
[lt_cv_dlopen="shl_load"],
[AC_CHECK_LIB([dld], [shl_load],
[lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
[AC_CHECK_FUNC([dlopen],
[lt_cv_dlopen="dlopen"],
[AC_CHECK_LIB([dl], [dlopen],
[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
[AC_CHECK_LIB([svld], [dlopen],
[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
[AC_CHECK_LIB([dld], [dld_link],
[lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
])
])
])
])
])
;;
esac
if test "x$lt_cv_dlopen" != xno; then
enable_dlopen=yes
else
enable_dlopen=no
fi
case $lt_cv_dlopen in
dlopen)
save_CPPFLAGS="$CPPFLAGS"
test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
save_LDFLAGS="$LDFLAGS"
wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
save_LIBS="$LIBS"
LIBS="$lt_cv_dlopen_libs $LIBS"
AC_CACHE_CHECK([whether a program can dlopen itself],
lt_cv_dlopen_self, [dnl
_LT_TRY_DLOPEN_SELF(
lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
])
if test "x$lt_cv_dlopen_self" = xyes; then
wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
lt_cv_dlopen_self_static, [dnl
_LT_TRY_DLOPEN_SELF(
lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
])
fi
CPPFLAGS="$save_CPPFLAGS"
LDFLAGS="$save_LDFLAGS"
LIBS="$save_LIBS"
;;
esac
case $lt_cv_dlopen_self in
yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
*) enable_dlopen_self=unknown ;;
esac
case $lt_cv_dlopen_self_static in
yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
*) enable_dlopen_self_static=unknown ;;
esac
fi
_LT_DECL([dlopen_support], [enable_dlopen], [0],
[Whether dlopen is supported])
_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
[Whether dlopen of programs is supported])
_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
[Whether dlopen of statically linked programs is supported])
])# LT_SYS_DLOPEN_SELF
# Old name:
AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
# _LT_COMPILER_C_O([TAGNAME])
# ---------------------------
# Check to see if options -c and -o are simultaneously supported by compiler.
# This macro does not hard code the compiler like AC_PROG_CC_C_O.
m4_defun([_LT_COMPILER_C_O],
[m4_require([_LT_DECL_SED])dnl
m4_require([_LT_FILEUTILS_DEFAULTS])dnl
m4_require([_LT_TAG_COMPILER])dnl
AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
[_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
[_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
$RM -r conftest 2>/dev/null
mkdir conftest
cd conftest
mkdir out
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
lt_compiler_flag="-o out/conftest2.$ac_objext"
# Insert the option either (1) after the last *FLAGS variable, or
# (2) before a word containing "conftest.", or (3) at the end.
# Note that $ac_compile itself does not contain backslashes and begins
# with a dollar sign (not a hyphen), so the echo should work correctly.
lt_compile=`echo "$ac_compile" | $SED \
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&AS_MESSAGE_LOG_FD
echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
$ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
$SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
fi
fi
chmod u+w . 2>&AS_MESSAGE_LOG_FD
$RM conftest*
# SGI C++ compiler will create directory out/ii_files/ for
# template instantiation
test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
$RM out/* && rmdir out
cd ..
$RM -r conftest
$RM conftest*
])
_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
[Does compiler simultaneously support -c and -o options?])
])# _LT_COMPILER_C_O
# _LT_COMPILER_FILE_LOCKS([TAGNAME])
# ----------------------------------
# Check to see if we can do hard links to lock some files if needed
m4_defun([_LT_COMPILER_FILE_LOCKS],
[m4_require([_LT_ENABLE_LOCK])dnl
m4_require([_LT_FILEUTILS_DEFAULTS])dnl
_LT_COMPILER_C_O([$1])
hard_links="nottested"
if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
# do not overwrite the value of need_locks provided by the user
AC_MSG_CHECKING([if we can lock with hard links])
hard_links=yes
$RM conftest*
ln conftest.a conftest.b 2>/dev/null && hard_links=no
touch conftest.a
ln conftest.a conftest.b 2>&5 || hard_links=no
ln conftest.a conftest.b 2>/dev/null && hard_links=no
AC_MSG_RESULT([$hard_links])
if test "$hard_links" = no; then
AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
need_locks=warn
fi
else
need_locks=no
fi
_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
])# _LT_COMPILER_FILE_LOCKS
# _LT_CHECK_OBJDIR
# ----------------
m4_defun([_LT_CHECK_OBJDIR],
[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
[rm -f .libs 2>/dev/null
mkdir .libs 2>/dev/null
if test -d .libs; then
lt_cv_objdir=.libs
else
# MS-DOS does not allow filenames that begin with a dot.
lt_cv_objdir=_libs
fi
rmdir .libs 2>/dev/null])
objdir=$lt_cv_objdir
_LT_DECL([], [objdir], [0],
[The name of the directory that contains temporary libtool files])dnl
m4_pattern_allow([LT_OBJDIR])dnl
AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
[Define to the sub-directory in which libtool stores uninstalled libraries.])
])# _LT_CHECK_OBJDIR
# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
# --------------------------------------
# Check hardcoding attributes.
m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
[AC_MSG_CHECKING([how to hardcode library paths into programs])
_LT_TAGVAR(hardcode_action, $1)=
if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
test -n "$_LT_TAGVAR(runpath_var, $1)" ||
test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
# We can hardcode non-existent directories.
if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
# If the only mechanism to avoid hardcoding is shlibpath_var, we
# have to relink, otherwise we might link with an installed library
# when we should be linking with a yet-to-be-installed one
## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
# Linking always hardcodes the temporary library directory.
_LT_TAGVAR(hardcode_action, $1)=relink
else
# We can link without hardcoding, and we can hardcode nonexisting dirs.
_LT_TAGVAR(hardcode_action, $1)=immediate
fi
else
# We cannot hardcode anything, or else we can only hardcode existing
# directories.
_LT_TAGVAR(hardcode_action, $1)=unsupported
fi
AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
# Fast installation is not supported
enable_fast_install=no
elif test "$shlibpath_overrides_runpath" = yes ||
test "$enable_shared" = no; then
# Fast installation is not necessary
enable_fast_install=needless
fi
_LT_TAGDECL([], [hardcode_action], [0],
[How to hardcode a shared library path into an executable])
])# _LT_LINKER_HARDCODE_LIBPATH
# _LT_CMD_STRIPLIB
# ----------------
m4_defun([_LT_CMD_STRIPLIB],
[m4_require([_LT_DECL_EGREP])
striplib=
old_striplib=
AC_MSG_CHECKING([whether stripping libraries is possible])
if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
test -z "$striplib" && striplib="$STRIP --strip-unneeded"
AC_MSG_RESULT([yes])
else
# FIXME - insert some real tests, host_os isn't really good enough
case $host_os in
darwin*)
if test -n "$STRIP" ; then
striplib="$STRIP -x"
old_striplib="$STRIP -S"
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
;;
*)
AC_MSG_RESULT([no])
;;
esac
fi
_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
_LT_DECL([], [striplib], [1])
])# _LT_CMD_STRIPLIB
# _LT_SYS_DYNAMIC_LINKER([TAG])
# -----------------------------
# PORTME Fill in your ld.so characteristics
m4_defun([_LT_SYS_DYNAMIC_LINKER],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
m4_require([_LT_DECL_EGREP])dnl
m4_require([_LT_FILEUTILS_DEFAULTS])dnl
m4_require([_LT_DECL_OBJDUMP])dnl
m4_require([_LT_DECL_SED])dnl
m4_require([_LT_CHECK_SHELL_FEATURES])dnl
AC_MSG_CHECKING([dynamic linker characteristics])
m4_if([$1],
[], [
if test "$GCC" = yes; then
case $host_os in
darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
*) lt_awk_arg="/^libraries:/" ;;
esac
case $host_os in
mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
*) lt_sed_strip_eq="s,=/,/,g" ;;
esac
lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
case $lt_search_path_spec in
*\;*)
# if the path contains ";" then we assume it to be the separator
# otherwise default to the standard path separator (i.e. ":") - it is
# assumed that no part of a normal pathname contains ";" but that should
# okay in the real world where ";" in dirpaths is itself problematic.
lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
;;
*)
lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
;;
esac
# Ok, now we have the path, separated by spaces, we can step through it
# and add multilib dir if necessary.
lt_tmp_lt_search_path_spec=
lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
for lt_sys_path in $lt_search_path_spec; do
if test -d "$lt_sys_path/$lt_multi_os_dir"; then
lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
else
test -d "$lt_sys_path" && \
lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
fi
done
lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
BEGIN {RS=" "; FS="/|\n";} {
lt_foo="";
lt_count=0;
for (lt_i = NF; lt_i > 0; lt_i--) {
if ($lt_i != "" && $lt_i != ".") {
if ($lt_i == "..") {
lt_count++;
} else {
if (lt_count == 0) {
lt_foo="/" $lt_i lt_foo;
} else {
lt_count--;
}
}
}
}
if (lt_foo != "") { lt_freq[[lt_foo]]++; }
if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
}'`
# AWK program above erroneously prepends '/' to C:/dos/paths
# for these hosts.
case $host_os in
mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
$SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
esac
sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
else
sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
fi])
library_names_spec=
libname_spec='lib$name'
soname_spec=
shrext_cmds=".so"
postinstall_cmds=
postuninstall_cmds=
finish_cmds=
finish_eval=
shlibpath_var=
shlibpath_overrides_runpath=unknown
version_type=none
dynamic_linker="$host_os ld.so"
sys_lib_dlsearch_path_spec="/lib /usr/lib"
need_lib_prefix=unknown
hardcode_into_libs=no
# when you set need_version to no, make sure it does not cause -set_version
# flags to be left without arguments
need_version=unknown
case $host_os in
aix3*)
version_type=linux # correct to gnu/linux during the next big refactor
library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
shlibpath_var=LIBPATH
# AIX 3 has no versioning support, so we append a major version to the name.
soname_spec='${libname}${release}${shared_ext}$major'
;;
aix[[4-9]]*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
hardcode_into_libs=yes
if test "$host_cpu" = ia64; then
# AIX 5 supports IA64
library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
shlibpath_var=LD_LIBRARY_PATH
else
# With GCC up to 2.95.x, collect2 would create an import file
# for dependence libraries. The import file would start with
# the line `#! .'. This would cause the generated library to
# depend on `.', always an invalid library. This was fixed in
# development snapshots of GCC prior to 3.0.
case $host_os in
aix4 | aix4.[[01]] | aix4.[[01]].*)
if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
echo ' yes '
echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
:
else
can_build_shared=no
fi
;;
esac
# AIX (on Power*) has no versioning support, so currently we can not hardcode correct
# soname into executable. Probably we can add versioning support to
# collect2, so additional links can be useful in future.
if test "$aix_use_runtimelinking" = yes; then
# If using run time linking (on AIX 4.2 or later) use lib.so
# instead of lib.a to let people know that these are not
# typical AIX shared libraries.
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
else
# We preserve .a as extension for shared libraries through AIX4.2
# and later when we are not doing run time linking.
library_names_spec='${libname}${release}.a $libname.a'
soname_spec='${libname}${release}${shared_ext}$major'
fi
shlibpath_var=LIBPATH
fi
;;
amigaos*)
case $host_cpu in
powerpc)
# Since July 2007 AmigaOS4 officially supports .so libraries.
# When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
;;
m68k)
library_names_spec='$libname.ixlibrary $libname.a'
# Create ${libname}_ixlibrary.a entries in /sys/libs.
finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
;;
esac
;;
beos*)
library_names_spec='${libname}${shared_ext}'
dynamic_linker="$host_os ld.so"
shlibpath_var=LIBRARY_PATH
;;
bsdi[[45]]*)
version_type=linux # correct to gnu/linux during the next big refactor
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
shlibpath_var=LD_LIBRARY_PATH
sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
# the default ld.so.conf also contains /usr/contrib/lib and
# /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
# libtool to hard-code these into programs
;;
cygwin* | mingw* | pw32* | cegcc*)
version_type=windows
shrext_cmds=".dll"
need_version=no
need_lib_prefix=no
case $GCC,$cc_basename in
yes,*)
# gcc
library_names_spec='$libname.dll.a'
# DLL is installed to $(libdir)/../bin by postinstall_cmds
postinstall_cmds='base_file=`basename \${file}`~
dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
dldir=$destdir/`dirname \$dlpath`~
test -d \$dldir || mkdir -p \$dldir~
$install_prog $dir/$dlname \$dldir/$dlname~
chmod a+x \$dldir/$dlname~
if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
fi'
postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
dlpath=$dir/\$dldll~
$RM \$dlpath'
shlibpath_overrides_runpath=yes
case $host_os in
cygwin*)
# Cygwin DLLs use 'cyg' prefix rather than 'lib'
soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
m4_if([$1], [],[
sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
;;
mingw* | cegcc*)
# MinGW DLLs use traditional 'lib' prefix
soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
;;
pw32*)
# pw32 DLLs use 'pw' prefix rather than 'lib'
library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
;;
esac
dynamic_linker='Win32 ld.exe'
;;
*,cl*)
# Native MSVC
libname_spec='$name'
soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
library_names_spec='${libname}.dll.lib'
case $build_os in
mingw*)
sys_lib_search_path_spec=
lt_save_ifs=$IFS
IFS=';'
for lt_path in $LIB
do
IFS=$lt_save_ifs
# Let DOS variable expansion print the short 8.3 style file name.
lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
done
IFS=$lt_save_ifs
# Convert to MSYS style.
sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
;;
cygwin*)
# Convert to unix form, then to dos form, then back to unix form
# but this time dos style (no spaces!) so that the unix form looks
# like /cygdrive/c/PROGRA~1:/cygdr...
sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
;;
*)
sys_lib_search_path_spec="$LIB"
if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
# It is most probably a Windows format PATH.
sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
else
sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
fi
# FIXME: find the short name or the path components, as spaces are
# common. (e.g. "Program Files" -> "PROGRA~1")
;;
esac
# DLL is installed to $(libdir)/../bin by postinstall_cmds
postinstall_cmds='base_file=`basename \${file}`~
dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
dldir=$destdir/`dirname \$dlpath`~
test -d \$dldir || mkdir -p \$dldir~
$install_prog $dir/$dlname \$dldir/$dlname'
postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
dlpath=$dir/\$dldll~
$RM \$dlpath'
shlibpath_overrides_runpath=yes
dynamic_linker='Win32 link.exe'
;;
*)
# Assume MSVC wrapper
library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
dynamic_linker='Win32 ld.exe'
;;
esac
# FIXME: first we should search . and the directory the executable is in
shlibpath_var=PATH
;;
darwin* | rhapsody*)
dynamic_linker="$host_os dyld"
version_type=darwin
need_lib_prefix=no
need_version=no
library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
soname_spec='${libname}${release}${major}$shared_ext'
shlibpath_overrides_runpath=yes
shlibpath_var=DYLD_LIBRARY_PATH
shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
m4_if([$1], [],[
sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
;;
dgux*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
soname_spec='${libname}${release}${shared_ext}$major'
shlibpath_var=LD_LIBRARY_PATH
;;
freebsd* | dragonfly*)
# DragonFly does not have aout. When/if they implement a new
# versioning mechanism, adjust this.
if test -x /usr/bin/objformat; then
objformat=`/usr/bin/objformat`
else
case $host_os in
freebsd[[23]].*) objformat=aout ;;
*) objformat=elf ;;
esac
fi
version_type=freebsd-$objformat
case $version_type in
freebsd-elf*)
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
need_version=no
need_lib_prefix=no
;;
freebsd-*)
library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
need_version=yes
;;
esac
shlibpath_var=LD_LIBRARY_PATH
case $host_os in
freebsd2.*)
shlibpath_overrides_runpath=yes
;;
freebsd3.[[01]]* | freebsdelf3.[[01]]*)
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
;;
freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
;;
*) # from 4.6 on, and DragonFly
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
;;
esac
;;
gnu*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
;;
haiku*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
dynamic_linker="$host_os runtime_loader"
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
shlibpath_var=LIBRARY_PATH
shlibpath_overrides_runpath=yes
sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
hardcode_into_libs=yes
;;
hpux9* | hpux10* | hpux11*)
# Give a soname corresponding to the major version so that dld.sl refuses to
# link against other versions.
version_type=sunos
need_lib_prefix=no
need_version=no
case $host_cpu in
ia64*)
shrext_cmds='.so'
hardcode_into_libs=yes
dynamic_linker="$host_os dld.so"
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
if test "X$HPUX_IA64_MODE" = X32; then
sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
else
sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
fi
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
hppa*64*)
shrext_cmds='.sl'
hardcode_into_libs=yes
dynamic_linker="$host_os dld.sl"
shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
*)
shrext_cmds='.sl'
dynamic_linker="$host_os dld.sl"
shlibpath_var=SHLIB_PATH
shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
;;
esac
# HP-UX runs *really* slowly unless shared libraries are mode 555, ...
postinstall_cmds='chmod 555 $lib'
# or fails outright, so override atomically:
install_override_mode=555
;;
interix[[3-9]]*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
;;
irix5* | irix6* | nonstopux*)
case $host_os in
nonstopux*) version_type=nonstopux ;;
*)
if test "$lt_cv_prog_gnu_ld" = yes; then
version_type=linux # correct to gnu/linux during the next big refactor
else
version_type=irix
fi ;;
esac
need_lib_prefix=no
need_version=no
soname_spec='${libname}${release}${shared_ext}$major'
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
case $host_os in
irix5* | nonstopux*)
libsuff= shlibsuff=
;;
*)
case $LD in # libtool.m4 will add one of these switches to LD
*-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
libsuff= shlibsuff= libmagic=32-bit;;
*-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
libsuff=32 shlibsuff=N32 libmagic=N32;;
*-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
libsuff=64 shlibsuff=64 libmagic=64-bit;;
*) libsuff= shlibsuff= libmagic=never-match;;
esac
;;
esac
shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
shlibpath_overrides_runpath=no
sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
hardcode_into_libs=yes
;;
# No shared lib support for Linux oldld, aout, or coff.
linux*oldld* | linux*aout* | linux*coff*)
dynamic_linker=no
;;
# This must be glibc/ELF.
linux* | k*bsd*-gnu | kopensolaris*-gnu)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
# Some binutils ld are patched to set DT_RUNPATH
AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
[lt_cv_shlibpath_overrides_runpath=no
save_LDFLAGS=$LDFLAGS
save_libdir=$libdir
eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
[AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
[lt_cv_shlibpath_overrides_runpath=yes])])
LDFLAGS=$save_LDFLAGS
libdir=$save_libdir
])
shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
# This implies no fast_install, which is unacceptable.
# Some rework will be needed to allow for fast_install
# before this can be enabled.
hardcode_into_libs=yes
# Append ld.so.conf contents to the search path
if test -f /etc/ld.so.conf; then
lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
fi
# We used to test for /lib/ld.so.1 and disable shared libraries on
# powerpc, because MkLinux only supported shared libraries with the
# GNU dynamic linker. Since this was broken with cross compilers,
# most powerpc-linux boxes support dynamic linking these days and
# people can always --disable-shared, the test was removed, and we
# assume the GNU/Linux dynamic linker is in use.
dynamic_linker='GNU/Linux ld.so'
;;
netbsdelf*-gnu)
version_type=linux
need_lib_prefix=no
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
dynamic_linker='NetBSD ld.elf_so'
;;
netbsd*)
version_type=sunos
need_lib_prefix=no
need_version=no
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
dynamic_linker='NetBSD (a.out) ld.so'
else
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
dynamic_linker='NetBSD ld.elf_so'
fi
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
;;
newsos6)
version_type=linux # correct to gnu/linux during the next big refactor
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
;;
*nto* | *qnx*)
version_type=qnx
need_lib_prefix=no
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
dynamic_linker='ldqnx.so'
;;
openbsd*)
version_type=sunos
sys_lib_dlsearch_path_spec="/usr/lib"
need_lib_prefix=no
# Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
case $host_os in
openbsd3.3 | openbsd3.3.*) need_version=yes ;;
*) need_version=no ;;
esac
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
shlibpath_var=LD_LIBRARY_PATH
if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
case $host_os in
openbsd2.[[89]] | openbsd2.[[89]].*)
shlibpath_overrides_runpath=no
;;
*)
shlibpath_overrides_runpath=yes
;;
esac
else
shlibpath_overrides_runpath=yes
fi
;;
os2*)
libname_spec='$name'
shrext_cmds=".dll"
need_lib_prefix=no
library_names_spec='$libname${shared_ext} $libname.a'
dynamic_linker='OS/2 ld.exe'
shlibpath_var=LIBPATH
;;
osf3* | osf4* | osf5*)
version_type=osf
need_lib_prefix=no
need_version=no
soname_spec='${libname}${release}${shared_ext}$major'
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
shlibpath_var=LD_LIBRARY_PATH
sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
;;
rdos*)
dynamic_linker=no
;;
solaris*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
# ldd complains unless libraries are executable
postinstall_cmds='chmod +x $lib'
;;
sunos4*)
version_type=sunos
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
if test "$with_gnu_ld" = yes; then
need_lib_prefix=no
fi
need_version=yes
;;
sysv4 | sysv4.3*)
version_type=linux # correct to gnu/linux during the next big refactor
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
shlibpath_var=LD_LIBRARY_PATH
case $host_vendor in
sni)
shlibpath_overrides_runpath=no
need_lib_prefix=no
runpath_var=LD_RUN_PATH
;;
siemens)
need_lib_prefix=no
;;
motorola)
need_lib_prefix=no
need_version=no
shlibpath_overrides_runpath=no
sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
;;
esac
;;
sysv4*MP*)
if test -d /usr/nec ;then
version_type=linux # correct to gnu/linux during the next big refactor
library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
soname_spec='$libname${shared_ext}.$major'
shlibpath_var=LD_LIBRARY_PATH
fi
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
version_type=freebsd-elf
need_lib_prefix=no
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
if test "$with_gnu_ld" = yes; then
sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
else
sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
case $host_os in
sco3.2v5*)
sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
;;
esac
fi
sys_lib_dlsearch_path_spec='/usr/lib'
;;
tpf*)
# TPF is a cross-target only. Preferred cross-host = GNU/Linux.
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
;;
uts4*)
version_type=linux # correct to gnu/linux during the next big refactor
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
shlibpath_var=LD_LIBRARY_PATH
;;
*)
dynamic_linker=no
;;
esac
AC_MSG_RESULT([$dynamic_linker])
test "$dynamic_linker" = no && can_build_shared=no
variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
if test "$GCC" = yes; then
variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
fi
if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
fi
if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
fi
_LT_DECL([], [variables_saved_for_relink], [1],
[Variables whose values should be saved in libtool wrapper scripts and
restored at link time])
_LT_DECL([], [need_lib_prefix], [0],
[Do we need the "lib" prefix for modules?])
_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
_LT_DECL([], [version_type], [0], [Library versioning type])
_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable])
_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
_LT_DECL([], [shlibpath_overrides_runpath], [0],
[Is shlibpath searched before the hard-coded library search path?])
_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
_LT_DECL([], [library_names_spec], [1],
[[List of archive names. First name is the real one, the rest are links.
The last name is the one that the linker finds with -lNAME]])
_LT_DECL([], [soname_spec], [1],
[[The coded name of the library, if different from the real name]])
_LT_DECL([], [install_override_mode], [1],
[Permission mode override for installation of shared libraries])
_LT_DECL([], [postinstall_cmds], [2],
[Command to use after installation of a shared archive])
_LT_DECL([], [postuninstall_cmds], [2],
[Command to use after uninstallation of a shared archive])
_LT_DECL([], [finish_cmds], [2],
[Commands used to finish a libtool library installation in a directory])
_LT_DECL([], [finish_eval], [1],
[[As "finish_cmds", except a single script fragment to be evaled but
not shown]])
_LT_DECL([], [hardcode_into_libs], [0],
[Whether we should hardcode library paths into libraries])
_LT_DECL([], [sys_lib_search_path_spec], [2],
[Compile-time system search path for libraries])
_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
[Run-time system search path for libraries])
])# _LT_SYS_DYNAMIC_LINKER
# _LT_PATH_TOOL_PREFIX(TOOL)
# --------------------------
# find a file program which can recognize shared library
AC_DEFUN([_LT_PATH_TOOL_PREFIX],
[m4_require([_LT_DECL_EGREP])dnl
AC_MSG_CHECKING([for $1])
AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
[case $MAGIC_CMD in
[[\\/*] | ?:[\\/]*])
lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
;;
*)
lt_save_MAGIC_CMD="$MAGIC_CMD"
lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
dnl $ac_dummy forces splitting on constant user-supplied paths.
dnl POSIX.2 word splitting is done only on the output of word expansions,
dnl not every word. This closes a longstanding sh security hole.
ac_dummy="m4_if([$2], , $PATH, [$2])"
for ac_dir in $ac_dummy; do
IFS="$lt_save_ifs"
test -z "$ac_dir" && ac_dir=.
if test -f $ac_dir/$1; then
lt_cv_path_MAGIC_CMD="$ac_dir/$1"
if test -n "$file_magic_test_file"; then
case $deplibs_check_method in
"file_magic "*)
file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
$EGREP "$file_magic_regex" > /dev/null; then
:
else
cat <<_LT_EOF 1>&2
*** Warning: the command libtool uses to detect shared libraries,
*** $file_magic_cmd, produces output that libtool cannot recognize.
*** The result is that libtool may fail to recognize shared libraries
*** as such. This will affect the creation of libtool libraries that
*** depend on shared libraries, but programs linked with such libtool
*** libraries will work regardless of this problem. Nevertheless, you
*** may want to report the problem to your system manager and/or to
*** bug-libtool@gnu.org
_LT_EOF
fi ;;
esac
fi
break
fi
done
IFS="$lt_save_ifs"
MAGIC_CMD="$lt_save_MAGIC_CMD"
;;
esac])
MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
if test -n "$MAGIC_CMD"; then
AC_MSG_RESULT($MAGIC_CMD)
else
AC_MSG_RESULT(no)
fi
_LT_DECL([], [MAGIC_CMD], [0],
[Used to examine libraries when file_magic_cmd begins with "file"])dnl
])# _LT_PATH_TOOL_PREFIX
# Old name:
AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
# _LT_PATH_MAGIC
# --------------
# find a file program which can recognize a shared library
m4_defun([_LT_PATH_MAGIC],
[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
if test -z "$lt_cv_path_MAGIC_CMD"; then
if test -n "$ac_tool_prefix"; then
_LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
else
MAGIC_CMD=:
fi
fi
])# _LT_PATH_MAGIC
# LT_PATH_LD
# ----------
# find the pathname to the GNU or non-GNU linker
AC_DEFUN([LT_PATH_LD],
[AC_REQUIRE([AC_PROG_CC])dnl
AC_REQUIRE([AC_CANONICAL_HOST])dnl
AC_REQUIRE([AC_CANONICAL_BUILD])dnl
m4_require([_LT_DECL_SED])dnl
m4_require([_LT_DECL_EGREP])dnl
m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
AC_ARG_WITH([gnu-ld],
[AS_HELP_STRING([--with-gnu-ld],
[assume the C compiler uses GNU ld @<:@default=no@:>@])],
[test "$withval" = no || with_gnu_ld=yes],
[with_gnu_ld=no])dnl
ac_prog=ld
if test "$GCC" = yes; then
# Check if gcc -print-prog-name=ld gives a path.
AC_MSG_CHECKING([for ld used by $CC])
case $host in
*-*-mingw*)
# gcc leaves a trailing carriage return which upsets mingw
ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
*)
ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
esac
case $ac_prog in
# Accept absolute paths.
[[\\/]]* | ?:[[\\/]]*)
re_direlt='/[[^/]][[^/]]*/\.\./'
# Canonicalize the pathname of ld
ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
done
test -z "$LD" && LD="$ac_prog"
;;
"")
# If it fails, then pretend we aren't using GCC.
ac_prog=ld
;;
*)
# If it is relative, then search for the first ld in PATH.
with_gnu_ld=unknown
;;
esac
elif test "$with_gnu_ld" = yes; then
AC_MSG_CHECKING([for GNU ld])
else
AC_MSG_CHECKING([for non-GNU ld])
fi
AC_CACHE_VAL(lt_cv_path_LD,
[if test -z "$LD"; then
lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
for ac_dir in $PATH; do
IFS="$lt_save_ifs"
test -z "$ac_dir" && ac_dir=.
if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
lt_cv_path_LD="$ac_dir/$ac_prog"
# Check to see if the program is GNU ld. I'd rather use --version,
# but apparently some variants of GNU ld only accept -v.
# Break only if it was the GNU/non-GNU ld that we prefer.
case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then
lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
lt_cv_file_magic_cmd='func_win32_libid'
else
# Keep this pattern in sync with the one in func_win32_libid.
lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
lt_cv_file_magic_cmd='$OBJDUMP -f'
fi
;;
cegcc*)
# use the weaker test based on 'objdump'. See mingw*.
lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
lt_cv_file_magic_cmd='$OBJDUMP -f'
;;
darwin* | rhapsody*)
lt_cv_deplibs_check_method=pass_all
;;
freebsd* | dragonfly*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
case $host_cpu in
i*86 )
# Not sure whether the presence of OpenBSD here was a mistake.
# Let's accept both of them until this is cleared up.
lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
lt_cv_file_magic_cmd=/usr/bin/file
lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
;;
esac
else
lt_cv_deplibs_check_method=pass_all
fi
;;
gnu*)
lt_cv_deplibs_check_method=pass_all
;;
haiku*)
lt_cv_deplibs_check_method=pass_all
;;
hpux10.20* | hpux11*)
lt_cv_file_magic_cmd=/usr/bin/file
case $host_cpu in
ia64*)
lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
;;
hppa*64*)
[lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
;;
*)
lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
lt_cv_file_magic_test_file=/usr/lib/libc.sl
;;
esac
;;
interix[[3-9]]*)
# PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
;;
irix5* | irix6* | nonstopux*)
case $LD in
*-32|*"-32 ") libmagic=32-bit;;
*-n32|*"-n32 ") libmagic=N32;;
*-64|*"-64 ") libmagic=64-bit;;
*) libmagic=never-match;;
esac
lt_cv_deplibs_check_method=pass_all
;;
# This must be glibc/ELF.
linux* | k*bsd*-gnu | kopensolaris*-gnu)
lt_cv_deplibs_check_method=pass_all
;;
netbsd* | netbsdelf*-gnu)
if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
else
lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
fi
;;
newos6*)
lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
lt_cv_file_magic_cmd=/usr/bin/file
lt_cv_file_magic_test_file=/usr/lib/libnls.so
;;
*nto* | *qnx*)
lt_cv_deplibs_check_method=pass_all
;;
openbsd*)
if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
else
lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
fi
;;
osf3* | osf4* | osf5*)
lt_cv_deplibs_check_method=pass_all
;;
rdos*)
lt_cv_deplibs_check_method=pass_all
;;
solaris*)
lt_cv_deplibs_check_method=pass_all
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
lt_cv_deplibs_check_method=pass_all
;;
sysv4 | sysv4.3*)
case $host_vendor in
motorola)
lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
;;
ncr)
lt_cv_deplibs_check_method=pass_all
;;
sequent)
lt_cv_file_magic_cmd='/bin/file'
lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
;;
sni)
lt_cv_file_magic_cmd='/bin/file'
lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
lt_cv_file_magic_test_file=/lib/libc.so
;;
siemens)
lt_cv_deplibs_check_method=pass_all
;;
pc)
lt_cv_deplibs_check_method=pass_all
;;
esac
;;
tpf*)
lt_cv_deplibs_check_method=pass_all
;;
esac
])
file_magic_glob=
want_nocaseglob=no
if test "$build" = "$host"; then
case $host_os in
mingw* | pw32*)
if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
want_nocaseglob=yes
else
file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
fi
;;
esac
fi
file_magic_cmd=$lt_cv_file_magic_cmd
deplibs_check_method=$lt_cv_deplibs_check_method
test -z "$deplibs_check_method" && deplibs_check_method=unknown
_LT_DECL([], [deplibs_check_method], [1],
[Method to check whether dependent libraries are shared objects])
_LT_DECL([], [file_magic_cmd], [1],
[Command to use when deplibs_check_method = "file_magic"])
_LT_DECL([], [file_magic_glob], [1],
[How to find potential files when deplibs_check_method = "file_magic"])
_LT_DECL([], [want_nocaseglob], [1],
[Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
])# _LT_CHECK_MAGIC_METHOD
# LT_PATH_NM
# ----------
# find the pathname to a BSD- or MS-compatible name lister
AC_DEFUN([LT_PATH_NM],
[AC_REQUIRE([AC_PROG_CC])dnl
AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
[if test -n "$NM"; then
# Let the user override the test.
lt_cv_path_NM="$NM"
else
lt_nm_to_check="${ac_tool_prefix}nm"
if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
lt_nm_to_check="$lt_nm_to_check nm"
fi
for lt_tmp_nm in $lt_nm_to_check; do
lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
IFS="$lt_save_ifs"
test -z "$ac_dir" && ac_dir=.
tmp_nm="$ac_dir/$lt_tmp_nm"
if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
# Check to see if the nm accepts a BSD-compat flag.
# Adding the `sed 1q' prevents false positives on HP-UX, which says:
# nm: unknown option "B" ignored
# Tru64's nm complains that /dev/null is an invalid object file
case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
*/dev/null* | *'Invalid file or object type'*)
lt_cv_path_NM="$tmp_nm -B"
break
;;
*)
case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
*/dev/null*)
lt_cv_path_NM="$tmp_nm -p"
break
;;
*)
lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
continue # so that we can try to find one that supports BSD flags
;;
esac
;;
esac
fi
done
IFS="$lt_save_ifs"
done
: ${lt_cv_path_NM=no}
fi])
if test "$lt_cv_path_NM" != "no"; then
NM="$lt_cv_path_NM"
else
# Didn't find any BSD compatible name lister, look for dumpbin.
if test -n "$DUMPBIN"; then :
# Let the user override the test.
else
AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
*COFF*)
DUMPBIN="$DUMPBIN -symbols"
;;
*)
DUMPBIN=:
;;
esac
fi
AC_SUBST([DUMPBIN])
if test "$DUMPBIN" != ":"; then
NM="$DUMPBIN"
fi
fi
test -z "$NM" && NM=nm
AC_SUBST([NM])
_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
[lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
(eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&AS_MESSAGE_LOG_FD
(eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&AS_MESSAGE_LOG_FD
(eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
cat conftest.out >&AS_MESSAGE_LOG_FD
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
fi
rm -f conftest*])
])# LT_PATH_NM
# Old names:
AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_PROG_NM], [])
dnl AC_DEFUN([AC_PROG_NM], [])
# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
# --------------------------------
# how to determine the name of the shared library
# associated with a specific link library.
# -- PORTME fill in with the dynamic library characteristics
m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
[m4_require([_LT_DECL_EGREP])
m4_require([_LT_DECL_OBJDUMP])
m4_require([_LT_DECL_DLLTOOL])
AC_CACHE_CHECK([how to associate runtime and link libraries],
lt_cv_sharedlib_from_linklib_cmd,
[lt_cv_sharedlib_from_linklib_cmd='unknown'
case $host_os in
cygwin* | mingw* | pw32* | cegcc*)
# two different shell functions defined in ltmain.sh
# decide which to use based on capabilities of $DLLTOOL
case `$DLLTOOL --help 2>&1` in
*--identify-strict*)
lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
;;
*)
lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
;;
esac
;;
*)
# fallback: assume linklib IS sharedlib
lt_cv_sharedlib_from_linklib_cmd="$ECHO"
;;
esac
])
sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
[Command to associate shared and link libraries])
])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
# _LT_PATH_MANIFEST_TOOL
# ----------------------
# locate the manifest tool
m4_defun([_LT_PATH_MANIFEST_TOOL],
[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
[lt_cv_path_mainfest_tool=no
echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
$MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
cat conftest.err >&AS_MESSAGE_LOG_FD
if $GREP 'Manifest Tool' conftest.out > /dev/null; then
lt_cv_path_mainfest_tool=yes
fi
rm -f conftest*])
if test "x$lt_cv_path_mainfest_tool" != xyes; then
MANIFEST_TOOL=:
fi
_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
])# _LT_PATH_MANIFEST_TOOL
# LT_LIB_M
# --------
# check for math library
AC_DEFUN([LT_LIB_M],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
LIBM=
case $host in
*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
# These system don't have libm, or don't need it
;;
*-ncr-sysv4.3*)
AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
;;
*)
AC_CHECK_LIB(m, cos, LIBM="-lm")
;;
esac
AC_SUBST([LIBM])
])# LT_LIB_M
# Old name:
AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_CHECK_LIBM], [])
# _LT_COMPILER_NO_RTTI([TAGNAME])
# -------------------------------
m4_defun([_LT_COMPILER_NO_RTTI],
[m4_require([_LT_TAG_COMPILER])dnl
_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
if test "$GCC" = yes; then
case $cc_basename in
nvcc*)
_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
*)
_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
esac
_LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
lt_cv_prog_compiler_rtti_exceptions,
[-fno-rtti -fno-exceptions], [],
[_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
fi
_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
[Compiler flag to turn off builtin functions])
])# _LT_COMPILER_NO_RTTI
# _LT_CMD_GLOBAL_SYMBOLS
# ----------------------
m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
AC_REQUIRE([AC_PROG_CC])dnl
AC_REQUIRE([AC_PROG_AWK])dnl
AC_REQUIRE([LT_PATH_NM])dnl
AC_REQUIRE([LT_PATH_LD])dnl
m4_require([_LT_DECL_SED])dnl
m4_require([_LT_DECL_EGREP])dnl
m4_require([_LT_TAG_COMPILER])dnl
# Check for command to grab the raw symbol name followed by C symbol from nm.
AC_MSG_CHECKING([command to parse $NM output from $compiler object])
AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
[
# These are sane defaults that work on at least a few old systems.
# [They come from Ultrix. What could be older than Ultrix?!! ;)]
# Character class describing NM global symbol codes.
symcode='[[BCDEGRST]]'
# Regexp to match symbols that can be accessed directly from C.
sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
# Define system-specific variables.
case $host_os in
aix*)
symcode='[[BCDT]]'
;;
cygwin* | mingw* | pw32* | cegcc*)
symcode='[[ABCDGISTW]]'
;;
hpux*)
if test "$host_cpu" = ia64; then
symcode='[[ABCDEGRST]]'
fi
;;
irix* | nonstopux*)
symcode='[[BCDEGRST]]'
;;
osf*)
symcode='[[BCDEGQRST]]'
;;
solaris*)
symcode='[[BDRT]]'
;;
sco3.2v5*)
symcode='[[DT]]'
;;
sysv4.2uw2*)
symcode='[[DT]]'
;;
sysv5* | sco5v6* | unixware* | OpenUNIX*)
symcode='[[ABDT]]'
;;
sysv4)
symcode='[[DFNSTU]]'
;;
esac
# If we're using GNU nm, then use its standard symbol codes.
case `$NM -V 2>&1` in
*GNU* | *'with BFD'*)
symcode='[[ABCDGIRSTW]]' ;;
esac
# Transform an extracted symbol line into a proper C declaration.
# Some systems (esp. on ia64) link data and code symbols differently,
# so use this general approach.
lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
# Transform an extracted symbol line into symbol name and symbol address
lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'"
lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
# Handle CRLF in mingw tool chain
opt_cr=
case $build_os in
mingw*)
opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
;;
esac
# Try without a prefix underscore, then with it.
for ac_symprfx in "" "_"; do
# Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
symxfrm="\\1 $ac_symprfx\\2 \\2"
# Write the raw and C identifiers.
if test "$lt_cv_nm_interface" = "MS dumpbin"; then
# Fake it for dumpbin and say T for any non-static function
# and D for any global variable.
# Also find C++ and __fastcall symbols from MSVC++,
# which start with @ or ?.
lt_cv_sys_global_symbol_pipe="$AWK ['"\
" {last_section=section; section=\$ 3};"\
" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
" \$ 0!~/External *\|/{next};"\
" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
" {if(hide[section]) next};"\
" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
" s[1]~/^[@?]/{print s[1], s[1]; next};"\
" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
" ' prfx=^$ac_symprfx]"
else
lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
fi
lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
# Check to see that the pipe works correctly.
pipe_works=no
rm -f conftest*
cat > conftest.$ac_ext <<_LT_EOF
#ifdef __cplusplus
extern "C" {
#endif
char nm_test_var;
void nm_test_func(void);
void nm_test_func(void){}
#ifdef __cplusplus
}
#endif
int main(){nm_test_var='a';nm_test_func();return(0);}
_LT_EOF
if AC_TRY_EVAL(ac_compile); then
# Now try to grab the symbols.
nlist=conftest.nm
if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
# Try sorting and uniquifying the output.
if sort "$nlist" | uniq > "$nlist"T; then
mv -f "$nlist"T "$nlist"
else
rm -f "$nlist"T
fi
# Make sure that we snagged all the symbols we need.
if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
cat <<_LT_EOF > conftest.$ac_ext
/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
/* DATA imports from DLLs on WIN32 con't be const, because runtime
relocations are performed -- see ld's documentation on pseudo-relocs. */
# define LT@&t@_DLSYM_CONST
#elif defined(__osf__)
/* This system does not cope well with relocations in const data. */
# define LT@&t@_DLSYM_CONST
#else
# define LT@&t@_DLSYM_CONST const
#endif
#ifdef __cplusplus
extern "C" {
#endif
_LT_EOF
# Now generate the symbol file.
eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
cat <<_LT_EOF >> conftest.$ac_ext
/* The mapping between symbol names and symbols. */
LT@&t@_DLSYM_CONST struct {
const char *name;
void *address;
}
lt__PROGRAM__LTX_preloaded_symbols[[]] =
{
{ "@PROGRAM@", (void *) 0 },
_LT_EOF
$SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
cat <<\_LT_EOF >> conftest.$ac_ext
{0, (void *) 0}
};
/* This works around a problem in FreeBSD linker */
#ifdef FREEBSD_WORKAROUND
static const void *lt_preloaded_setup() {
return lt__PROGRAM__LTX_preloaded_symbols;
}
#endif
#ifdef __cplusplus
}
#endif
_LT_EOF
# Now try linking the two files.
mv conftest.$ac_objext conftstm.$ac_objext
lt_globsym_save_LIBS=$LIBS
lt_globsym_save_CFLAGS=$CFLAGS
LIBS="conftstm.$ac_objext"
CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
pipe_works=yes
fi
LIBS=$lt_globsym_save_LIBS
CFLAGS=$lt_globsym_save_CFLAGS
else
echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
fi
else
echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
fi
else
echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
fi
else
echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
cat conftest.$ac_ext >&5
fi
rm -rf conftest* conftst*
# Do not use the global_symbol_pipe unless it works.
if test "$pipe_works" = yes; then
break
else
lt_cv_sys_global_symbol_pipe=
fi
done
])
if test -z "$lt_cv_sys_global_symbol_pipe"; then
lt_cv_sys_global_symbol_to_cdecl=
fi
if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
AC_MSG_RESULT(failed)
else
AC_MSG_RESULT(ok)
fi
# Response file support.
if test "$lt_cv_nm_interface" = "MS dumpbin"; then
nm_file_list_spec='@'
elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
nm_file_list_spec='@'
fi
_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
[Take the output of nm and produce a listing of raw symbols and C names])
_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
[Transform the output of nm in a proper C declaration])
_LT_DECL([global_symbol_to_c_name_address],
[lt_cv_sys_global_symbol_to_c_name_address], [1],
[Transform the output of nm in a C name address pair])
_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
[lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
[Transform the output of nm in a C name address pair when lib prefix is needed])
_LT_DECL([], [nm_file_list_spec], [1],
[Specify filename containing input files for $NM])
]) # _LT_CMD_GLOBAL_SYMBOLS
# _LT_COMPILER_PIC([TAGNAME])
# ---------------------------
m4_defun([_LT_COMPILER_PIC],
[m4_require([_LT_TAG_COMPILER])dnl
_LT_TAGVAR(lt_prog_compiler_wl, $1)=
_LT_TAGVAR(lt_prog_compiler_pic, $1)=
_LT_TAGVAR(lt_prog_compiler_static, $1)=
m4_if([$1], [CXX], [
# C++ specific cases for pic, static, wl, etc.
if test "$GXX" = yes; then
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
case $host_os in
aix*)
# All AIX code is PIC.
if test "$host_cpu" = ia64; then
# AIX 5 now supports IA64 processor
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
fi
;;
amigaos*)
case $host_cpu in
powerpc)
# see comment about AmigaOS4 .so support
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
m68k)
# FIXME: we need at least 68020 code to build shared libraries, but
# adding the `-m68020' flag to GCC prevents building anything better,
# like `-m68040'.
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
;;
esac
;;
beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
# PIC is the default for these OSes.
;;
mingw* | cygwin* | os2* | pw32* | cegcc*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
# Although the cygwin gcc ignores -fPIC, still need this for old-style
# (--disable-auto-import) libraries
m4_if([$1], [GCJ], [],
[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
;;
darwin* | rhapsody*)
# PIC is the default on this platform
# Common symbols not allowed in MH_DYLIB files
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
;;
*djgpp*)
# DJGPP does not support shared libraries at all
_LT_TAGVAR(lt_prog_compiler_pic, $1)=
;;
haiku*)
# PIC is the default for Haiku.
# The "-static" flag exists, but is broken.
_LT_TAGVAR(lt_prog_compiler_static, $1)=
;;
interix[[3-9]]*)
# Interix 3.x gcc -fpic/-fPIC options generate broken code.
# Instead, we relocate shared libraries at runtime.
;;
sysv4*MP*)
if test -d /usr/nec; then
_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
fi
;;
hpux*)
# PIC is the default for 64-bit PA HP-UX, but not for 32-bit
# PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
# sets the default TLS model and affects inlining.
case $host_cpu in
hppa*64*)
;;
*)
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
esac
;;
*qnx* | *nto*)
# QNX uses GNU C++, but need to define -shared option too, otherwise
# it will coredump.
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
;;
*)
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
esac
else
case $host_os in
aix[[4-9]]*)
# All AIX code is PIC.
if test "$host_cpu" = ia64; then
# AIX 5 now supports IA64 processor
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
else
_LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
fi
;;
chorus*)
case $cc_basename in
cxch68*)
# Green Hills C++ Compiler
# _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
;;
esac
;;
mingw* | cygwin* | os2* | pw32* | cegcc*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
m4_if([$1], [GCJ], [],
[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
;;
dgux*)
case $cc_basename in
ec++*)
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
;;
ghcx*)
# Green Hills C++ Compiler
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
;;
*)
;;
esac
;;
freebsd* | dragonfly*)
# FreeBSD uses GNU C++
;;
hpux9* | hpux10* | hpux11*)
case $cc_basename in
CC*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
if test "$host_cpu" != ia64; then
_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
fi
;;
aCC*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
case $host_cpu in
hppa*64*|ia64*)
# +Z the default
;;
*)
_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
;;
esac
;;
*)
;;
esac
;;
interix*)
# This is c89, which is MS Visual C++ (no shared libs)
# Anyone wants to do a port?
;;
irix5* | irix6* | nonstopux*)
case $cc_basename in
CC*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
# CC pic flag -KPIC is the default.
;;
*)
;;
esac
;;
linux* | k*bsd*-gnu | kopensolaris*-gnu)
case $cc_basename in
KCC*)
# KAI C++ Compiler
_LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
ecpc* )
# old Intel C++ for x86_64 which still supported -KPIC.
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
;;
icpc* )
# Intel C++, used to be incompatible with GCC.
# ICC 10 doesn't accept -KPIC any more.
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
;;
pgCC* | pgcpp*)
# Portland Group C++ compiler
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
;;
cxx*)
# Compaq C++
# Make sure the PIC flag is empty. It appears that all Alpha
# Linux and Compaq Tru64 Unix objects are PIC.
_LT_TAGVAR(lt_prog_compiler_pic, $1)=
_LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
;;
xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
# IBM XL 8.0, 9.0 on PPC and BlueGene
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
;;
*)
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*)
# Sun C++ 5.9
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
;;
esac
;;
esac
;;
lynxos*)
;;
m88k*)
;;
mvs*)
case $cc_basename in
cxx*)
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
;;
*)
;;
esac
;;
netbsd* | netbsdelf*-gnu)
;;
*qnx* | *nto*)
# QNX uses GNU C++, but need to define -shared option too, otherwise
# it will coredump.
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
;;
osf3* | osf4* | osf5*)
case $cc_basename in
KCC*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
;;
RCC*)
# Rational C++ 2.4.1
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
;;
cxx*)
# Digital/Compaq C++
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
# Make sure the PIC flag is empty. It appears that all Alpha
# Linux and Compaq Tru64 Unix objects are PIC.
_LT_TAGVAR(lt_prog_compiler_pic, $1)=
_LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
;;
*)
;;
esac
;;
psos*)
;;
solaris*)
case $cc_basename in
CC* | sunCC*)
# Sun C++ 4.2, 5.x and Centerline C++
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
;;
gcx*)
# Green Hills C++ Compiler
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
;;
*)
;;
esac
;;
sunos4*)
case $cc_basename in
CC*)
# Sun C++ 4.x
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
;;
lcc*)
# Lucid
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
;;
*)
;;
esac
;;
sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
case $cc_basename in
CC*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
;;
esac
;;
tandem*)
case $cc_basename in
NCC*)
# NonStop-UX NCC 3.20
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
;;
*)
;;
esac
;;
vxworks*)
;;
*)
_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
;;
esac
fi
],
[
if test "$GCC" = yes; then
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
case $host_os in
aix*)
# All AIX code is PIC.
if test "$host_cpu" = ia64; then
# AIX 5 now supports IA64 processor
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
fi
;;
amigaos*)
case $host_cpu in
powerpc)
# see comment about AmigaOS4 .so support
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
m68k)
# FIXME: we need at least 68020 code to build shared libraries, but
# adding the `-m68020' flag to GCC prevents building anything better,
# like `-m68040'.
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
;;
esac
;;
beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
# PIC is the default for these OSes.
;;
mingw* | cygwin* | pw32* | os2* | cegcc*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
# Although the cygwin gcc ignores -fPIC, still need this for old-style
# (--disable-auto-import) libraries
m4_if([$1], [GCJ], [],
[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
;;
darwin* | rhapsody*)
# PIC is the default on this platform
# Common symbols not allowed in MH_DYLIB files
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
;;
haiku*)
# PIC is the default for Haiku.
# The "-static" flag exists, but is broken.
_LT_TAGVAR(lt_prog_compiler_static, $1)=
;;
hpux*)
# PIC is the default for 64-bit PA HP-UX, but not for 32-bit
# PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
# sets the default TLS model and affects inlining.
case $host_cpu in
hppa*64*)
# +Z the default
;;
*)
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
esac
;;
interix[[3-9]]*)
# Interix 3.x gcc -fpic/-fPIC options generate broken code.
# Instead, we relocate shared libraries at runtime.
;;
msdosdjgpp*)
# Just because we use GCC doesn't mean we suddenly get shared libraries
# on systems that don't support them.
_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
enable_shared=no
;;
*nto* | *qnx*)
# QNX uses GNU C++, but need to define -shared option too, otherwise
# it will coredump.
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
;;
sysv4*MP*)
if test -d /usr/nec; then
_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
fi
;;
*)
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
esac
case $cc_basename in
nvcc*) # Cuda Compiler Driver 2.2
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
_LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
fi
;;
esac
else
# PORTME Check for flag to pass linker flags through the system compiler.
case $host_os in
aix*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
if test "$host_cpu" = ia64; then
# AIX 5 now supports IA64 processor
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
else
_LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
fi
;;
mingw* | cygwin* | pw32* | os2* | cegcc*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
m4_if([$1], [GCJ], [],
[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
;;
hpux9* | hpux10* | hpux11*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
# PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
# not for PA HP-UX.
case $host_cpu in
hppa*64*|ia64*)
# +Z the default
;;
*)
_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
;;
esac
# Is there a better lt_prog_compiler_static that works with the bundled CC?
_LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
;;
irix5* | irix6* | nonstopux*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
# PIC (with -KPIC) is the default.
_LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
;;
linux* | k*bsd*-gnu | kopensolaris*-gnu)
case $cc_basename in
# old Intel for x86_64 which still supported -KPIC.
ecc*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
;;
# icc used to be incompatible with GCC.
# ICC 10 doesn't accept -KPIC any more.
icc* | ifort*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
;;
# Lahey Fortran 8.1.
lf95*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
_LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
;;
nagfor*)
# NAG Fortran compiler
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
;;
pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
# Portland Group compilers (*not* the Pentium gcc compiler,
# which looks to be a dead project)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
;;
ccc*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
# All Alpha code is PIC.
_LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
;;
xl* | bgxl* | bgf* | mpixl*)
# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
;;
*)
case `$CC -V 2>&1 | sed 5q` in
*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
# Sun Fortran 8.3 passes all unrecognized flags to the linker
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
_LT_TAGVAR(lt_prog_compiler_wl, $1)=''
;;
*Sun\ F* | *Sun*Fortran*)
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
;;
*Sun\ C*)
# Sun C 5.9
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
;;
*Intel*\ [[CF]]*Compiler*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
;;
*Portland\ Group*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
;;
esac
;;
esac
;;
newsos6)
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
;;
*nto* | *qnx*)
# QNX uses GNU C++, but need to define -shared option too, otherwise
# it will coredump.
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
;;
osf3* | osf4* | osf5*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
# All OSF/1 code is PIC.
_LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
;;
rdos*)
_LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
;;
solaris*)
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
case $cc_basename in
f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
esac
;;
sunos4*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
;;
sysv4 | sysv4.2uw2* | sysv4.3*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
;;
sysv4*MP*)
if test -d /usr/nec ;then
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
fi
;;
sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
;;
unicos*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
;;
uts4*)
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
;;
*)
_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
;;
esac
fi
])
case $host_os in
# For platforms which do not support PIC, -DPIC is meaningless:
*djgpp*)
_LT_TAGVAR(lt_prog_compiler_pic, $1)=
;;
*)
_LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
;;
esac
AC_CACHE_CHECK([for $compiler option to produce PIC],
[_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
[_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
#
# Check to make sure the PIC flag actually works.
#
if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
_LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
[_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
[$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
[case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
"" | " "*) ;;
*) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
esac],
[_LT_TAGVAR(lt_prog_compiler_pic, $1)=
_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
fi
_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
[Additional compiler flags for building library objects])
_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
[How to pass a linker flag through the compiler])
#
# Check to make sure the static flag actually works.
#
wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
_LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
$lt_tmp_static_flag,
[],
[_LT_TAGVAR(lt_prog_compiler_static, $1)=])
_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
[Compiler flag to prevent dynamic linking])
])# _LT_COMPILER_PIC
# _LT_LINKER_SHLIBS([TAGNAME])
# ----------------------------
# See if the linker supports building shared libraries.
m4_defun([_LT_LINKER_SHLIBS],
[AC_REQUIRE([LT_PATH_LD])dnl
AC_REQUIRE([LT_PATH_NM])dnl
m4_require([_LT_PATH_MANIFEST_TOOL])dnl
m4_require([_LT_FILEUTILS_DEFAULTS])dnl
m4_require([_LT_DECL_EGREP])dnl
m4_require([_LT_DECL_SED])dnl
m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
m4_require([_LT_TAG_COMPILER])dnl
AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
m4_if([$1], [CXX], [
_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
_LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
case $host_os in
aix[[4-9]]*)
# If we're using GNU nm, then we don't want the "-C" option.
# -C means demangle to AIX nm, but means don't demangle with GNU nm
# Also, AIX nm treats weak defined symbols like other global defined
# symbols, whereas GNU nm marks them as "W".
if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
_LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
else
_LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
fi
;;
pw32*)
_LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
;;
cygwin* | mingw* | cegcc*)
case $cc_basename in
cl*)
_LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
;;
*)
_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
_LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
;;
esac
;;
linux* | k*bsd*-gnu | gnu*)
_LT_TAGVAR(link_all_deplibs, $1)=no
;;
*)
_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
;;
esac
], [
runpath_var=
_LT_TAGVAR(allow_undefined_flag, $1)=
_LT_TAGVAR(always_export_symbols, $1)=no
_LT_TAGVAR(archive_cmds, $1)=
_LT_TAGVAR(archive_expsym_cmds, $1)=
_LT_TAGVAR(compiler_needs_object, $1)=no
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
_LT_TAGVAR(export_dynamic_flag_spec, $1)=
_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
_LT_TAGVAR(hardcode_automatic, $1)=no
_LT_TAGVAR(hardcode_direct, $1)=no
_LT_TAGVAR(hardcode_direct_absolute, $1)=no
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
_LT_TAGVAR(hardcode_libdir_separator, $1)=
_LT_TAGVAR(hardcode_minus_L, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
_LT_TAGVAR(inherit_rpath, $1)=no
_LT_TAGVAR(link_all_deplibs, $1)=unknown
_LT_TAGVAR(module_cmds, $1)=
_LT_TAGVAR(module_expsym_cmds, $1)=
_LT_TAGVAR(old_archive_from_new_cmds, $1)=
_LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
_LT_TAGVAR(thread_safe_flag_spec, $1)=
_LT_TAGVAR(whole_archive_flag_spec, $1)=
# include_expsyms should be a list of space-separated symbols to be *always*
# included in the symbol list
_LT_TAGVAR(include_expsyms, $1)=
# exclude_expsyms can be an extended regexp of symbols to exclude
# it will be wrapped by ` (' and `)$', so one must not match beginning or
# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
# as well as any symbol that contains `d'.
_LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
# platforms (ab)use it in PIC code, but their linkers get confused if
# the symbol is explicitly referenced. Since portable code cannot
# rely on this symbol name, it's probably fine to never include it in
# preloaded symbol tables.
# Exclude shared library initialization/finalization symbols.
dnl Note also adjust exclude_expsyms for C++ above.
extract_expsyms_cmds=
case $host_os in
cygwin* | mingw* | pw32* | cegcc*)
# FIXME: the MSVC++ port hasn't been tested in a loooong time
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++.
if test "$GCC" != yes; then
with_gnu_ld=no
fi
;;
interix*)
# we just hope/assume this is gcc and not c89 (= MSVC++)
with_gnu_ld=yes
;;
openbsd*)
with_gnu_ld=no
;;
linux* | k*bsd*-gnu | gnu*)
_LT_TAGVAR(link_all_deplibs, $1)=no
;;
esac
_LT_TAGVAR(ld_shlibs, $1)=yes
# On some targets, GNU ld is compatible enough with the native linker
# that we're better off using the native interface for both.
lt_use_gnu_ld_interface=no
if test "$with_gnu_ld" = yes; then
case $host_os in
aix*)
# The AIX port of GNU ld has always aspired to compatibility
# with the native linker. However, as the warning in the GNU ld
# block says, versions before 2.19.5* couldn't really create working
# shared libraries, regardless of the interface used.
case `$LD -v 2>&1` in
*\ \(GNU\ Binutils\)\ 2.19.5*) ;;
*\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
*\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
*)
lt_use_gnu_ld_interface=yes
;;
esac
;;
*)
lt_use_gnu_ld_interface=yes
;;
esac
fi
if test "$lt_use_gnu_ld_interface" = yes; then
# If archive_cmds runs LD, not CC, wlarc should be empty
wlarc='${wl}'
# Set some defaults for GNU ld with shared library support. These
# are reset later if shared libraries are not supported. Putting them
# here allows them to be overridden if necessary.
runpath_var=LD_RUN_PATH
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
# ancient GNU ld didn't support --whole-archive et. al.
if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
_LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
else
_LT_TAGVAR(whole_archive_flag_spec, $1)=
fi
supports_anon_versioning=no
case `$LD -v 2>&1` in
*GNU\ gold*) supports_anon_versioning=yes ;;
*\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
*\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
*\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
*\ 2.11.*) ;; # other 2.11 versions
*) supports_anon_versioning=yes ;;
esac
# See if GNU ld supports shared libraries.
case $host_os in
aix[[3-9]]*)
# On AIX/PPC, the GNU linker is very broken
if test "$host_cpu" != ia64; then
_LT_TAGVAR(ld_shlibs, $1)=no
cat <<_LT_EOF 1>&2
*** Warning: the GNU linker, at least up to release 2.19, is reported
*** to be unable to reliably create shared libraries on AIX.
*** Therefore, libtool is disabling shared libraries support. If you
*** really care for shared libraries, you may want to install binutils
*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
*** You will then need to restart the configuration process.
_LT_EOF
fi
;;
amigaos*)
case $host_cpu in
powerpc)
# see comment about AmigaOS4 .so support
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)=''
;;
m68k)
_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
_LT_TAGVAR(hardcode_minus_L, $1)=yes
;;
esac
;;
beos*)
if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
# Joseph Beckenbach says some releases of gcc
# support --undefined. This deserves some investigation. FIXME
_LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
cygwin* | mingw* | pw32* | cegcc*)
# _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
# as there is no search path for DLLs.
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
_LT_TAGVAR(always_export_symbols, $1)=no
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
_LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
# If the export-symbols file already is a .def file (1st line
# is EXPORTS), use it as is; otherwise, prepend...
_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
cp $export_symbols $output_objdir/$soname.def;
else
echo EXPORTS > $output_objdir/$soname.def;
cat $export_symbols >> $output_objdir/$soname.def;
fi~
$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
haiku*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
_LT_TAGVAR(link_all_deplibs, $1)=yes
;;
interix[[3-9]]*)
_LT_TAGVAR(hardcode_direct, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
# Instead, shared libraries are loaded at an image base (0x10000000 by
# default) and relocated if they conflict, which is a slow very memory
# consuming and fragmenting process. To avoid this, we pick a random,
# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
# time. Moving up from 0x10000000 also allows more sbrk(2) space.
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
;;
gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
tmp_diet=no
if test "$host_os" = linux-dietlibc; then
case $cc_basename in
diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
esac
fi
if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
&& test "$tmp_diet" = no
then
tmp_addflag=' $pic_flag'
tmp_sharedflag='-shared'
case $cc_basename,$host_cpu in
pgcc*) # Portland Group C compiler
_LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
tmp_addflag=' $pic_flag'
;;
pgf77* | pgf90* | pgf95* | pgfortran*)
# Portland Group f77 and f90 compilers
_LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
tmp_addflag=' $pic_flag -Mnomain' ;;
ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
tmp_addflag=' -i_dynamic' ;;
efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
tmp_addflag=' -i_dynamic -nofor_main' ;;
ifc* | ifort*) # Intel Fortran compiler
tmp_addflag=' -nofor_main' ;;
lf95*) # Lahey Fortran 8.1
_LT_TAGVAR(whole_archive_flag_spec, $1)=
tmp_sharedflag='--shared' ;;
xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
tmp_sharedflag='-qmkshrobj'
tmp_addflag= ;;
nvcc*) # Cuda Compiler Driver 2.2
_LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
_LT_TAGVAR(compiler_needs_object, $1)=yes
;;
esac
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*) # Sun C 5.9
_LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
_LT_TAGVAR(compiler_needs_object, $1)=yes
tmp_sharedflag='-G' ;;
*Sun\ F*) # Sun Fortran 8.3
tmp_sharedflag='-G' ;;
esac
_LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
if test "x$supports_anon_versioning" = xyes; then
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
echo "local: *; };" >> $output_objdir/$libname.ver~
$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
fi
case $cc_basename in
xlf* | bgf* | bgxlf* | mpixlf*)
# IBM XL Fortran 10.1 on PPC cannot create shared libs itself
_LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
_LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
if test "x$supports_anon_versioning" = xyes; then
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
echo "local: *; };" >> $output_objdir/$libname.ver~
$LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
fi
;;
esac
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
netbsd* | netbsdelf*-gnu)
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
wlarc=
else
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
fi
;;
solaris*)
if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
_LT_TAGVAR(ld_shlibs, $1)=no
cat <<_LT_EOF 1>&2
*** Warning: The releases 2.8.* of the GNU linker cannot reliably
*** create shared libraries on Solaris systems. Therefore, libtool
*** is disabling shared libraries support. We urge you to upgrade GNU
*** binutils to release 2.9.1 or newer. Another option is to modify
*** your PATH or compiler configuration so that the native linker is
*** used, and then restart.
_LT_EOF
elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
case `$LD -v 2>&1` in
*\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
_LT_TAGVAR(ld_shlibs, $1)=no
cat <<_LT_EOF 1>&2
*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
*** reliably create shared libraries on SCO systems. Therefore, libtool
*** is disabling shared libraries support. We urge you to upgrade GNU
*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
*** your PATH or compiler configuration so that the native linker is
*** used, and then restart.
_LT_EOF
;;
*)
# For security reasons, it is highly recommended that you always
# use absolute paths for naming shared libraries, and exclude the
# DT_RUNPATH tag from executables and libraries. But doing so
# requires that you compile everything twice, which is a pain.
if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
esac
;;
sunos4*)
_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
wlarc=
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
*)
if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
esac
if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
runpath_var=
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
_LT_TAGVAR(export_dynamic_flag_spec, $1)=
_LT_TAGVAR(whole_archive_flag_spec, $1)=
fi
else
# PORTME fill in a description of your system's linker (not GNU ld)
case $host_os in
aix3*)
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
_LT_TAGVAR(always_export_symbols, $1)=yes
_LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
# Note: this linker hardcodes the directories in LIBPATH if there
# are no directories specified by -L.
_LT_TAGVAR(hardcode_minus_L, $1)=yes
if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
# Neither direct hardcoding nor static linking is supported with a
# broken collect2.
_LT_TAGVAR(hardcode_direct, $1)=unsupported
fi
;;
aix[[4-9]]*)
if test "$host_cpu" = ia64; then
# On IA64, the linker does run time linking by default, so we don't
# have to do anything special.
aix_use_runtimelinking=no
exp_sym_flag='-Bexport'
no_entry_flag=""
else
# If we're using GNU nm, then we don't want the "-C" option.
# -C means demangle to AIX nm, but means don't demangle with GNU nm
# Also, AIX nm treats weak defined symbols like other global
# defined symbols, whereas GNU nm marks them as "W".
if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
_LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
else
_LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
fi
aix_use_runtimelinking=no
# Test if we are trying to use run time linking or normal
# AIX style linking. If -brtl is somewhere in LDFLAGS, we
# need to do runtime linking.
case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
for ld_flag in $LDFLAGS; do
if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
aix_use_runtimelinking=yes
break
fi
done
;;
esac
exp_sym_flag='-bexport'
no_entry_flag='-bnoentry'
fi
# When large executables or shared objects are built, AIX ld can
# have problems creating the table of contents. If linking a library
# or program results in "error TOC overflow" add -mminimal-toc to
# CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
# enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
_LT_TAGVAR(archive_cmds, $1)=''
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
_LT_TAGVAR(link_all_deplibs, $1)=yes
_LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
if test "$GCC" = yes; then
case $host_os in aix4.[[012]]|aix4.[[012]].*)
# We only want to do this on AIX 4.2 and lower, the check
# below for broken collect2 doesn't work under 4.3+
collect2name=`${CC} -print-prog-name=collect2`
if test -f "$collect2name" &&
strings "$collect2name" | $GREP resolve_lib_name >/dev/null
then
# We have reworked collect2
:
else
# We have old collect2
_LT_TAGVAR(hardcode_direct, $1)=unsupported
# It fails to find uninstalled libraries when the uninstalled
# path is not listed in the libpath. Setting hardcode_minus_L
# to unsupported forces relinking
_LT_TAGVAR(hardcode_minus_L, $1)=yes
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=
fi
;;
esac
shared_flag='-shared'
if test "$aix_use_runtimelinking" = yes; then
shared_flag="$shared_flag "'${wl}-G'
fi
_LT_TAGVAR(link_all_deplibs, $1)=no
else
# not using gcc
if test "$host_cpu" = ia64; then
# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
# chokes on -Wl,-G. The following line is correct:
shared_flag='-G'
else
if test "$aix_use_runtimelinking" = yes; then
shared_flag='${wl}-G'
else
shared_flag='${wl}-bM:SRE'
fi
fi
fi
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
# It seems that -bexpall does not export symbols beginning with
# underscore (_), so it is better to generate a list of symbols to export.
_LT_TAGVAR(always_export_symbols, $1)=yes
if test "$aix_use_runtimelinking" = yes; then
# Warning - without using the other runtime loading flags (-brtl),
# -berok will link without error, but may produce a broken library.
_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
# Determine the default libpath from the value encoded in an
# empty executable.
_LT_SYS_MODULE_PATH_AIX([$1])
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
else
if test "$host_cpu" = ia64; then
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
_LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
_LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
else
# Determine the default libpath from the value encoded in an
# empty executable.
_LT_SYS_MODULE_PATH_AIX([$1])
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
# Warning - without using the other run time loading flags,
# -berok will link without error, but may produce a broken library.
_LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
if test "$with_gnu_ld" = yes; then
# We only use this code for GNU lds that support --whole-archive.
_LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
else
# Exported symbols can be pulled into shared objects from archives
_LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
fi
_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
# This is similar to how AIX traditionally builds its shared libraries.
_LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
fi
fi
;;
amigaos*)
case $host_cpu in
powerpc)
# see comment about AmigaOS4 .so support
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)=''
;;
m68k)
_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
_LT_TAGVAR(hardcode_minus_L, $1)=yes
;;
esac
;;
bsdi[[45]]*)
_LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
;;
cygwin* | mingw* | pw32* | cegcc*)
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++.
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
case $cc_basename in
cl*)
# Native MSVC
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
_LT_TAGVAR(always_export_symbols, $1)=yes
_LT_TAGVAR(file_list_spec, $1)='@'
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
shrext_cmds=".dll"
# FIXME: Setting linknames here is a bad hack.
_LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
else
sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
fi~
$CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
linknames='
# The linker will not automatically build a static lib if we build a DLL.
# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
_LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
# Don't use ranlib
_LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
_LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
lt_tool_outputfile="@TOOL_OUTPUT@"~
case $lt_outputfile in
*.exe|*.EXE) ;;
*)
lt_outputfile="$lt_outputfile.exe"
lt_tool_outputfile="$lt_tool_outputfile.exe"
;;
esac~
if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
$MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
$RM "$lt_outputfile.manifest";
fi'
;;
*)
# Assume MSVC wrapper
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
shrext_cmds=".dll"
# FIXME: Setting linknames here is a bad hack.
_LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
# The linker will automatically build a .lib file if we build a DLL.
_LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
# FIXME: Should let the user specify the lib program.
_LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
;;
esac
;;
darwin* | rhapsody*)
_LT_DARWIN_LINKER_FEATURES($1)
;;
dgux*)
_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
# FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
# support. Future versions do this automatically, but an explicit c++rt0.o
# does not break anything, and helps significantly (at the cost of a little
# extra space).
freebsd2.2*)
_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
# Unfortunately, older versions of FreeBSD 2 do not have this feature.
freebsd2.*)
_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_minus_L, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
# FreeBSD 3 and greater uses gcc -shared to do shared libraries.
freebsd* | dragonfly*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
hpux9*)
if test "$GCC" = yes; then
_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
else
_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
fi
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(hardcode_direct, $1)=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
_LT_TAGVAR(hardcode_minus_L, $1)=yes
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
;;
hpux10*)
if test "$GCC" = yes && test "$with_gnu_ld" = no; then
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
else
_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
fi
if test "$with_gnu_ld" = no; then
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
_LT_TAGVAR(hardcode_minus_L, $1)=yes
fi
;;
hpux11*)
if test "$GCC" = yes && test "$with_gnu_ld" = no; then
case $host_cpu in
hppa*64*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
ia64*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
else
case $host_cpu in
hppa*64*)
_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
ia64*)
_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
m4_if($1, [], [
# Older versions of the 11.00 compiler do not understand -b yet
# (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
_LT_LINKER_OPTION([if $CC understands -b],
_LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
[_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
[_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
[_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
;;
esac
fi
if test "$with_gnu_ld" = no; then
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
case $host_cpu in
hppa*64*|ia64*)
_LT_TAGVAR(hardcode_direct, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
*)
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
_LT_TAGVAR(hardcode_minus_L, $1)=yes
;;
esac
fi
;;
irix5* | irix6* | nonstopux*)
if test "$GCC" = yes; then
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
# Try to use the -exported_symbol ld option, if it does not
# work, assume that -exports_file does not work either and
# implicitly export all symbols.
# This should be the same for all languages, so no per-tag cache variable.
AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
[lt_cv_irix_exported_symbol],
[save_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
AC_LINK_IFELSE(
[AC_LANG_SOURCE(
[AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
[C++], [[int foo (void) { return 0; }]],
[Fortran 77], [[
subroutine foo
end]],
[Fortran], [[
subroutine foo
end]])])],
[lt_cv_irix_exported_symbol=yes],
[lt_cv_irix_exported_symbol=no])
LDFLAGS="$save_LDFLAGS"])
if test "$lt_cv_irix_exported_symbol" = yes; then
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
fi
else
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
fi
_LT_TAGVAR(archive_cmds_need_lc, $1)='no'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(inherit_rpath, $1)=yes
_LT_TAGVAR(link_all_deplibs, $1)=yes
;;
netbsd* | netbsdelf*-gnu)
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
else
_LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
fi
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
newsos6)
_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
*nto* | *qnx*)
;;
openbsd*)
if test -f /usr/libexec/ld.so; then
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
else
case $host_os in
openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
;;
*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
;;
esac
fi
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
os2*)
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
_LT_TAGVAR(hardcode_minus_L, $1)=yes
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
_LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
_LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
;;
osf3*)
if test "$GCC" = yes; then
_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
else
_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
fi
_LT_TAGVAR(archive_cmds_need_lc, $1)='no'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
;;
osf4* | osf5*) # as osf3* with the addition of -msym flag
if test "$GCC" = yes; then
_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
else
_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
# Both c and cxx compiler support -rpath directly
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
fi
_LT_TAGVAR(archive_cmds_need_lc, $1)='no'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
;;
solaris*)
_LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
if test "$GCC" = yes; then
wlarc='${wl}'
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
else
case `$CC -V 2>&1` in
*"Compilers 5.0"*)
wlarc=''
_LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
;;
*)
wlarc='${wl}'
_LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
$CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
;;
esac
fi
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
case $host_os in
solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
*)
# The compiler driver will combine and reorder linker options,
# but understands `-z linker_flag'. GCC discards it without `$wl',
# but is careful enough not to reorder.
# Supported since Solaris 2.6 (maybe 2.5.1?)
if test "$GCC" = yes; then
_LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
else
_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
fi
;;
esac
_LT_TAGVAR(link_all_deplibs, $1)=yes
;;
sunos4*)
if test "x$host_vendor" = xsequent; then
# Use $CC to link under sequent, because it throws in some extra .o
# files that make .init and .fini sections work.
_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
else
_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
fi
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_minus_L, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
sysv4)
case $host_vendor in
sni)
_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
;;
siemens)
## LD is ld it makes a PLAMLIB
## CC just makes a GrossModule.
_LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
_LT_TAGVAR(hardcode_direct, $1)=no
;;
motorola)
_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
;;
esac
runpath_var='LD_RUN_PATH'
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
sysv4.3*)
_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
_LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
;;
sysv4*MP*)
if test -d /usr/nec; then
_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
runpath_var=LD_RUN_PATH
hardcode_runpath_var=yes
_LT_TAGVAR(ld_shlibs, $1)=yes
fi
;;
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
_LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
runpath_var='LD_RUN_PATH'
if test "$GCC" = yes; then
_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
else
_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
fi
;;
sysv5* | sco3.2v5* | sco5v6*)
# Note: We can NOT use -z defs as we might desire, because we do not
# link with -lc, and that would cause any symbols used from libc to
# always be unresolved, which means just about no library would
# ever link correctly. If we're not using GNU ld we use -z text
# though, which does catch some bad symbols but isn't as heavy-handed
# as -z defs.
_LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
_LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
_LT_TAGVAR(link_all_deplibs, $1)=yes
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
runpath_var='LD_RUN_PATH'
if test "$GCC" = yes; then
_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
else
_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
fi
;;
uts4*)
_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
*)
_LT_TAGVAR(ld_shlibs, $1)=no
;;
esac
if test x$host_vendor = xsni; then
case $host in
sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
;;
esac
fi
fi
])
AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
_LT_DECL([], [extract_expsyms_cmds], [2],
[The commands to extract the exported symbol list from a shared archive])
#
# Do we need to explicitly link libc?
#
case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
x|xyes)
# Assume -lc should be added
_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
if test "$enable_shared" = yes && test "$GCC" = yes; then
case $_LT_TAGVAR(archive_cmds, $1) in
*'~'*)
# FIXME: we may have to deal with multi-command sequences.
;;
'$CC '*)
# Test whether the compiler implicitly links with -lc since on some
# systems, -lgcc has to come before -lc. If gcc already passes -lc
# to ld, don't add -lc before -lgcc.
AC_CACHE_CHECK([whether -lc should be explicitly linked in],
[lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
[$RM conftest*
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
soname=conftest
lib=conftest
libobjs=conftest.$ac_objext
deplibs=
wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
compiler_flags=-v
linker_flags=-v
verstring=
output_objdir=.
libname=conftest
lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
_LT_TAGVAR(allow_undefined_flag, $1)=
if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
then
lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
else
lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
fi
_LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
else
cat conftest.err 1>&5
fi
$RM conftest*
])
_LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
;;
esac
fi
;;
esac
_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
[Whether or not to add -lc for building shared libraries])
_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
[enable_shared_with_static_runtimes], [0],
[Whether or not to disallow shared libs when runtime libs are static])
_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
[Compiler flag to allow reflexive dlopens])
_LT_TAGDECL([], [whole_archive_flag_spec], [1],
[Compiler flag to generate shared objects directly from archives])
_LT_TAGDECL([], [compiler_needs_object], [1],
[Whether the compiler copes with passing no objects directly])
_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
[Create an old-style archive from a shared archive])
_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
[Create a temporary old-style archive to link instead of a shared archive])
_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
_LT_TAGDECL([], [archive_expsym_cmds], [2])
_LT_TAGDECL([], [module_cmds], [2],
[Commands used to build a loadable module if different from building
a shared archive.])
_LT_TAGDECL([], [module_expsym_cmds], [2])
_LT_TAGDECL([], [with_gnu_ld], [1],
[Whether we are building with GNU ld or not])
_LT_TAGDECL([], [allow_undefined_flag], [1],
[Flag that allows shared libraries with undefined symbols to be built])
_LT_TAGDECL([], [no_undefined_flag], [1],
[Flag that enforces no undefined symbols])
_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
[Flag to hardcode $libdir into a binary during linking.
This must work even if $libdir does not exist])
_LT_TAGDECL([], [hardcode_libdir_separator], [1],
[Whether we need a single "-rpath" flag with a separated argument])
_LT_TAGDECL([], [hardcode_direct], [0],
[Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
DIR into the resulting binary])
_LT_TAGDECL([], [hardcode_direct_absolute], [0],
[Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
DIR into the resulting binary and the resulting library dependency is
"absolute", i.e impossible to change by setting ${shlibpath_var} if the
library is relocated])
_LT_TAGDECL([], [hardcode_minus_L], [0],
[Set to "yes" if using the -LDIR flag during linking hardcodes DIR
into the resulting binary])
_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
[Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
into the resulting binary])
_LT_TAGDECL([], [hardcode_automatic], [0],
[Set to "yes" if building a shared library automatically hardcodes DIR
into the library and all subsequent libraries and executables linked
against it])
_LT_TAGDECL([], [inherit_rpath], [0],
[Set to yes if linker adds runtime paths of dependent libraries
to runtime path list])
_LT_TAGDECL([], [link_all_deplibs], [0],
[Whether libtool must link a program against all its dependency libraries])
_LT_TAGDECL([], [always_export_symbols], [0],
[Set to "yes" if exported symbols are required])
_LT_TAGDECL([], [export_symbols_cmds], [2],
[The commands to list exported symbols])
_LT_TAGDECL([], [exclude_expsyms], [1],
[Symbols that should not be listed in the preloaded symbols])
_LT_TAGDECL([], [include_expsyms], [1],
[Symbols that must always be exported])
_LT_TAGDECL([], [prelink_cmds], [2],
[Commands necessary for linking programs (against libraries) with templates])
_LT_TAGDECL([], [postlink_cmds], [2],
[Commands necessary for finishing linking programs])
_LT_TAGDECL([], [file_list_spec], [1],
[Specify filename containing input files])
dnl FIXME: Not yet implemented
dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
dnl [Compiler flag to generate thread safe objects])
])# _LT_LINKER_SHLIBS
# _LT_LANG_C_CONFIG([TAG])
# ------------------------
# Ensure that the configuration variables for a C compiler are suitably
# defined. These variables are subsequently used by _LT_CONFIG to write
# the compiler configuration to `libtool'.
m4_defun([_LT_LANG_C_CONFIG],
[m4_require([_LT_DECL_EGREP])dnl
lt_save_CC="$CC"
AC_LANG_PUSH(C)
# Source file extension for C test sources.
ac_ext=c
# Object file extension for compiled C test sources.
objext=o
_LT_TAGVAR(objext, $1)=$objext
# Code to be used in simple compile tests
lt_simple_compile_test_code="int some_variable = 0;"
# Code to be used in simple link tests
lt_simple_link_test_code='int main(){return(0);}'
_LT_TAG_COMPILER
# Save the default compiler, since it gets overwritten when the other
# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
compiler_DEFAULT=$CC
# save warnings/boilerplate of simple test code
_LT_COMPILER_BOILERPLATE
_LT_LINKER_BOILERPLATE
## CAVEAT EMPTOR:
## There is no encapsulation within the following macros, do not change
## the running order or otherwise move them around unless you know exactly
## what you are doing...
if test -n "$compiler"; then
_LT_COMPILER_NO_RTTI($1)
_LT_COMPILER_PIC($1)
_LT_COMPILER_C_O($1)
_LT_COMPILER_FILE_LOCKS($1)
_LT_LINKER_SHLIBS($1)
_LT_SYS_DYNAMIC_LINKER($1)
_LT_LINKER_HARDCODE_LIBPATH($1)
LT_SYS_DLOPEN_SELF
_LT_CMD_STRIPLIB
# Report which library types will actually be built
AC_MSG_CHECKING([if libtool supports shared libraries])
AC_MSG_RESULT([$can_build_shared])
AC_MSG_CHECKING([whether to build shared libraries])
test "$can_build_shared" = "no" && enable_shared=no
# On AIX, shared libraries and static libraries use the same namespace, and
# are all built from PIC.
case $host_os in
aix3*)
test "$enable_shared" = yes && enable_static=no
if test -n "$RANLIB"; then
archive_cmds="$archive_cmds~\$RANLIB \$lib"
postinstall_cmds='$RANLIB $lib'
fi
;;
aix[[4-9]]*)
if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
test "$enable_shared" = yes && enable_static=no
fi
;;
esac
AC_MSG_RESULT([$enable_shared])
AC_MSG_CHECKING([whether to build static libraries])
# Make sure either enable_shared or enable_static is yes.
test "$enable_shared" = yes || enable_static=yes
AC_MSG_RESULT([$enable_static])
_LT_CONFIG($1)
fi
AC_LANG_POP
CC="$lt_save_CC"
])# _LT_LANG_C_CONFIG
# _LT_LANG_CXX_CONFIG([TAG])
# --------------------------
# Ensure that the configuration variables for a C++ compiler are suitably
# defined. These variables are subsequently used by _LT_CONFIG to write
# the compiler configuration to `libtool'.
m4_defun([_LT_LANG_CXX_CONFIG],
[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
m4_require([_LT_DECL_EGREP])dnl
m4_require([_LT_PATH_MANIFEST_TOOL])dnl
if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
(test "X$CXX" != "Xg++"))) ; then
AC_PROG_CXXCPP
else
_lt_caught_CXX_error=yes
fi
AC_LANG_PUSH(C++)
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(allow_undefined_flag, $1)=
_LT_TAGVAR(always_export_symbols, $1)=no
_LT_TAGVAR(archive_expsym_cmds, $1)=
_LT_TAGVAR(compiler_needs_object, $1)=no
_LT_TAGVAR(export_dynamic_flag_spec, $1)=
_LT_TAGVAR(hardcode_direct, $1)=no
_LT_TAGVAR(hardcode_direct_absolute, $1)=no
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
_LT_TAGVAR(hardcode_libdir_separator, $1)=
_LT_TAGVAR(hardcode_minus_L, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
_LT_TAGVAR(hardcode_automatic, $1)=no
_LT_TAGVAR(inherit_rpath, $1)=no
_LT_TAGVAR(module_cmds, $1)=
_LT_TAGVAR(module_expsym_cmds, $1)=
_LT_TAGVAR(link_all_deplibs, $1)=unknown
_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
_LT_TAGVAR(reload_flag, $1)=$reload_flag
_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
_LT_TAGVAR(no_undefined_flag, $1)=
_LT_TAGVAR(whole_archive_flag_spec, $1)=
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
# Source file extension for C++ test sources.
ac_ext=cpp
# Object file extension for compiled C++ test sources.
objext=o
_LT_TAGVAR(objext, $1)=$objext
# No sense in running all these tests if we already determined that
# the CXX compiler isn't working. Some variables (like enable_shared)
# are currently assumed to apply to all compilers on this platform,
# and will be corrupted by setting them based on a non-working compiler.
if test "$_lt_caught_CXX_error" != yes; then
# Code to be used in simple compile tests
lt_simple_compile_test_code="int some_variable = 0;"
# Code to be used in simple link tests
lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
_LT_TAG_COMPILER
# save warnings/boilerplate of simple test code
_LT_COMPILER_BOILERPLATE
_LT_LINKER_BOILERPLATE
# Allow CC to be a program name with arguments.
lt_save_CC=$CC
lt_save_CFLAGS=$CFLAGS
lt_save_LD=$LD
lt_save_GCC=$GCC
GCC=$GXX
lt_save_with_gnu_ld=$with_gnu_ld
lt_save_path_LD=$lt_cv_path_LD
if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
else
$as_unset lt_cv_prog_gnu_ld
fi
if test -n "${lt_cv_path_LDCXX+set}"; then
lt_cv_path_LD=$lt_cv_path_LDCXX
else
$as_unset lt_cv_path_LD
fi
test -z "${LDCXX+set}" || LD=$LDCXX
CC=${CXX-"c++"}
CFLAGS=$CXXFLAGS
compiler=$CC
_LT_TAGVAR(compiler, $1)=$CC
_LT_CC_BASENAME([$compiler])
if test -n "$compiler"; then
# We don't want -fno-exception when compiling C++ code, so set the
# no_builtin_flag separately
if test "$GXX" = yes; then
_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
else
_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
fi
if test "$GXX" = yes; then
# Set up default GNU C++ configuration
LT_PATH_LD
# Check if GNU C++ uses GNU ld as the underlying linker, since the
# archiving commands below assume that GNU ld is being used.
if test "$with_gnu_ld" = yes; then
_LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
# If archive_cmds runs LD, not CC, wlarc should be empty
# XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
# investigate it a little bit more. (MM)
wlarc='${wl}'
# ancient GNU ld didn't support --whole-archive et. al.
if eval "`$CC -print-prog-name=ld` --help 2>&1" |
$GREP 'no-whole-archive' > /dev/null; then
_LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
else
_LT_TAGVAR(whole_archive_flag_spec, $1)=
fi
else
with_gnu_ld=no
wlarc=
# A generic and very simple default shared library creation
# command for GNU C++ for the case where it uses the native
# linker, instead of GNU ld. If possible, this setting should
# overridden to take advantage of the native linker features on
# the platform it is being used on.
_LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
fi
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
else
GXX=no
with_gnu_ld=no
wlarc=
fi
# PORTME: fill in a description of your system's C++ link characteristics
AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
_LT_TAGVAR(ld_shlibs, $1)=yes
case $host_os in
aix3*)
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
aix[[4-9]]*)
if test "$host_cpu" = ia64; then
# On IA64, the linker does run time linking by default, so we don't
# have to do anything special.
aix_use_runtimelinking=no
exp_sym_flag='-Bexport'
no_entry_flag=""
else
aix_use_runtimelinking=no
# Test if we are trying to use run time linking or normal
# AIX style linking. If -brtl is somewhere in LDFLAGS, we
# need to do runtime linking.
case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
for ld_flag in $LDFLAGS; do
case $ld_flag in
*-brtl*)
aix_use_runtimelinking=yes
break
;;
esac
done
;;
esac
exp_sym_flag='-bexport'
no_entry_flag='-bnoentry'
fi
# When large executables or shared objects are built, AIX ld can
# have problems creating the table of contents. If linking a library
# or program results in "error TOC overflow" add -mminimal-toc to
# CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
# enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
_LT_TAGVAR(archive_cmds, $1)=''
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
_LT_TAGVAR(link_all_deplibs, $1)=yes
_LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
if test "$GXX" = yes; then
case $host_os in aix4.[[012]]|aix4.[[012]].*)
# We only want to do this on AIX 4.2 and lower, the check
# below for broken collect2 doesn't work under 4.3+
collect2name=`${CC} -print-prog-name=collect2`
if test -f "$collect2name" &&
strings "$collect2name" | $GREP resolve_lib_name >/dev/null
then
# We have reworked collect2
:
else
# We have old collect2
_LT_TAGVAR(hardcode_direct, $1)=unsupported
# It fails to find uninstalled libraries when the uninstalled
# path is not listed in the libpath. Setting hardcode_minus_L
# to unsupported forces relinking
_LT_TAGVAR(hardcode_minus_L, $1)=yes
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=
fi
esac
shared_flag='-shared'
if test "$aix_use_runtimelinking" = yes; then
shared_flag="$shared_flag "'${wl}-G'
fi
else
# not using gcc
if test "$host_cpu" = ia64; then
# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
# chokes on -Wl,-G. The following line is correct:
shared_flag='-G'
else
if test "$aix_use_runtimelinking" = yes; then
shared_flag='${wl}-G'
else
shared_flag='${wl}-bM:SRE'
fi
fi
fi
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
# It seems that -bexpall does not export symbols beginning with
# underscore (_), so it is better to generate a list of symbols to
# export.
_LT_TAGVAR(always_export_symbols, $1)=yes
if test "$aix_use_runtimelinking" = yes; then
# Warning - without using the other runtime loading flags (-brtl),
# -berok will link without error, but may produce a broken library.
_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
# Determine the default libpath from the value encoded in an empty
# executable.
_LT_SYS_MODULE_PATH_AIX([$1])
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
else
if test "$host_cpu" = ia64; then
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
_LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
_LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
else
# Determine the default libpath from the value encoded in an
# empty executable.
_LT_SYS_MODULE_PATH_AIX([$1])
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
# Warning - without using the other run time loading flags,
# -berok will link without error, but may produce a broken library.
_LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
if test "$with_gnu_ld" = yes; then
# We only use this code for GNU lds that support --whole-archive.
_LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
else
# Exported symbols can be pulled into shared objects from archives
_LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
fi
_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
# This is similar to how AIX traditionally builds its shared
# libraries.
_LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
fi
fi
;;
beos*)
if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
# Joseph Beckenbach says some releases of gcc
# support --undefined. This deserves some investigation. FIXME
_LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
chorus*)
case $cc_basename in
*)
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
esac
;;
cygwin* | mingw* | pw32* | cegcc*)
case $GXX,$cc_basename in
,cl* | no,cl*)
# Native MSVC
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
_LT_TAGVAR(always_export_symbols, $1)=yes
_LT_TAGVAR(file_list_spec, $1)='@'
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
shrext_cmds=".dll"
# FIXME: Setting linknames here is a bad hack.
_LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
$SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
else
$SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
fi~
$CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
linknames='
# The linker will not automatically build a static lib if we build a DLL.
# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
# Don't use ranlib
_LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
_LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
lt_tool_outputfile="@TOOL_OUTPUT@"~
case $lt_outputfile in
*.exe|*.EXE) ;;
*)
lt_outputfile="$lt_outputfile.exe"
lt_tool_outputfile="$lt_tool_outputfile.exe"
;;
esac~
func_to_tool_file "$lt_outputfile"~
if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
$MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
$RM "$lt_outputfile.manifest";
fi'
;;
*)
# g++
# _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
# as there is no search path for DLLs.
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
_LT_TAGVAR(always_export_symbols, $1)=no
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
_LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
# If the export-symbols file already is a .def file (1st line
# is EXPORTS), use it as is; otherwise, prepend...
_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
cp $export_symbols $output_objdir/$soname.def;
else
echo EXPORTS > $output_objdir/$soname.def;
cat $export_symbols >> $output_objdir/$soname.def;
fi~
$CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
esac
;;
darwin* | rhapsody*)
_LT_DARWIN_LINKER_FEATURES($1)
;;
dgux*)
case $cc_basename in
ec++*)
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
ghcx*)
# Green Hills C++ Compiler
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
*)
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
esac
;;
freebsd2.*)
# C++ shared libraries reported to be fairly broken before
# switch to ELF
_LT_TAGVAR(ld_shlibs, $1)=no
;;
freebsd-elf*)
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
;;
freebsd* | dragonfly*)
# FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
# conventions
_LT_TAGVAR(ld_shlibs, $1)=yes
;;
gnu*)
;;
haiku*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
_LT_TAGVAR(link_all_deplibs, $1)=yes
;;
hpux9*)
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
# but as the default
# location of the library.
case $cc_basename in
CC*)
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
aCC*)
_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
#
# There doesn't appear to be a way to prevent this compiler from
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
;;
*)
if test "$GXX" = yes; then
_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
else
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
esac
;;
hpux10*|hpux11*)
if test $with_gnu_ld = no; then
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
case $host_cpu in
hppa*64*|ia64*)
;;
*)
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
;;
esac
fi
case $host_cpu in
hppa*64*|ia64*)
_LT_TAGVAR(hardcode_direct, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
*)
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
_LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
# but as the default
# location of the library.
;;
esac
case $cc_basename in
CC*)
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
aCC*)
case $host_cpu in
hppa*64*)
_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
ia64*)
_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
*)
_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
esac
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
#
# There doesn't appear to be a way to prevent this compiler from
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
;;
*)
if test "$GXX" = yes; then
if test $with_gnu_ld = no; then
case $host_cpu in
hppa*64*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
ia64*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
esac
fi
else
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
esac
;;
interix[[3-9]]*)
_LT_TAGVAR(hardcode_direct, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
# Instead, shared libraries are loaded at an image base (0x10000000 by
# default) and relocated if they conflict, which is a slow very memory
# consuming and fragmenting process. To avoid this, we pick a random,
# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
# time. Moving up from 0x10000000 also allows more sbrk(2) space.
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
;;
irix5* | irix6*)
case $cc_basename in
CC*)
# SGI C++
_LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
# Archives containing C++ object files must be created using
# "CC -ar", where "CC" is the IRIX C++ compiler. This is
# necessary to make sure instantiated templates are included
# in the archive.
_LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
;;
*)
if test "$GXX" = yes; then
if test "$with_gnu_ld" = no; then
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
else
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
fi
fi
_LT_TAGVAR(link_all_deplibs, $1)=yes
;;
esac
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(inherit_rpath, $1)=yes
;;
linux* | k*bsd*-gnu | kopensolaris*-gnu)
case $cc_basename in
KCC*)
# Kuck and Associates, Inc. (KAI) C++ Compiler
# KCC will only create a shared library if the output file
# ends with ".so" (or ".sl" for HP-UX), so rename the library
# to its proper name (with version) after linking.
_LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
#
# There doesn't appear to be a way to prevent this compiler from
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
# Archives containing C++ object files must be created using
# "CC -Bstatic", where "CC" is the KAI C++ compiler.
_LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
;;
icpc* | ecpc* )
# Intel C++
with_gnu_ld=yes
# version 8.0 and above of icpc choke on multiply defined symbols
# if we add $predep_objects and $postdep_objects, however 7.1 and
# earlier do not add the objects themselves.
case `$CC -V 2>&1` in
*"Version 7."*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
;;
*) # Version 8.0 or newer
tmp_idyn=
case $host_cpu in
ia64*) tmp_idyn=' -i_dynamic';;
esac
_LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
;;
esac
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
_LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
;;
pgCC* | pgcpp*)
# Portland Group C++ compiler
case `$CC -V` in
*pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
_LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
rm -rf $tpldir~
$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
_LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
rm -rf $tpldir~
$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
$RANLIB $oldlib'
_LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
rm -rf $tpldir~
$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
rm -rf $tpldir~
$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
;;
*) # Version 6 and above use weak symbols
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
;;
esac
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
_LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
;;
cxx*)
# Compaq C++
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
runpath_var=LD_RUN_PATH
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
#
# There doesn't appear to be a way to prevent this compiler from
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
;;
xl* | mpixl* | bgxl*)
# IBM XL 8.0 on PPC, with GNU ld
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
_LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
if test "x$supports_anon_versioning" = xyes; then
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
echo "local: *; };" >> $output_objdir/$libname.ver~
$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
fi
;;
*)
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*)
# Sun C++ 5.9
_LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
_LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
_LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
_LT_TAGVAR(compiler_needs_object, $1)=yes
# Not sure whether something based on
# $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
# would be better.
output_verbose_link_cmd='func_echo_all'
# Archives containing C++ object files must be created using
# "CC -xar", where "CC" is the Sun C++ compiler. This is
# necessary to make sure instantiated templates are included
# in the archive.
_LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
;;
esac
;;
esac
;;
lynxos*)
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
m88k*)
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
mvs*)
case $cc_basename in
cxx*)
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
*)
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
esac
;;
netbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
wlarc=
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
fi
# Workaround some broken pre-1.5 toolchains
output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
;;
*nto* | *qnx*)
_LT_TAGVAR(ld_shlibs, $1)=yes
;;
openbsd2*)
# C++ shared libraries are fairly broken
_LT_TAGVAR(ld_shlibs, $1)=no
;;
openbsd*)
if test -f /usr/libexec/ld.so; then
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
_LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
fi
output_verbose_link_cmd=func_echo_all
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
osf3* | osf4* | osf5*)
case $cc_basename in
KCC*)
# Kuck and Associates, Inc. (KAI) C++ Compiler
# KCC will only create a shared library if the output file
# ends with ".so" (or ".sl" for HP-UX), so rename the library
# to its proper name (with version) after linking.
_LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
# Archives containing C++ object files must be created using
# the KAI C++ compiler.
case $host in
osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
esac
;;
RCC*)
# Rational C++ 2.4.1
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
cxx*)
case $host in
osf3*)
_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
;;
*)
_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
echo "-hidden">> $lib.exp~
$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
$RM $lib.exp'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
;;
esac
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
#
# There doesn't appear to be a way to prevent this compiler from
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
;;
*)
if test "$GXX" = yes && test "$with_gnu_ld" = no; then
_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
case $host in
osf3*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
;;
*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
;;
esac
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
else
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
esac
;;
psos*)
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
sunos4*)
case $cc_basename in
CC*)
# Sun C++ 4.x
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
lcc*)
# Lucid
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
*)
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
esac
;;
solaris*)
case $cc_basename in
CC* | sunCC*)
# Sun C++ 4.2, 5.x and Centerline C++
_LT_TAGVAR(archive_cmds_need_lc,$1)=yes
_LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
_LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
$CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
case $host_os in
solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
*)
# The compiler driver will combine and reorder linker options,
# but understands `-z linker_flag'.
# Supported since Solaris 2.6 (maybe 2.5.1?)
_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
;;
esac
_LT_TAGVAR(link_all_deplibs, $1)=yes
output_verbose_link_cmd='func_echo_all'
# Archives containing C++ object files must be created using
# "CC -xar", where "CC" is the Sun C++ compiler. This is
# necessary to make sure instantiated templates are included
# in the archive.
_LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
;;
gcx*)
# Green Hills C++ Compiler
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
# The C++ compiler must be used to create the archive.
_LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
;;
*)
# GNU C++ compiler with Solaris linker
if test "$GXX" = yes && test "$with_gnu_ld" = no; then
_LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
if $CC --version | $GREP -v '^2\.7' > /dev/null; then
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
$CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
else
# g++ 2.7 appears to require `-G' NOT `-shared' on this
# platform.
_LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
$CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
fi
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
case $host_os in
solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
*)
_LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
;;
esac
fi
;;
esac
;;
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
_LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
runpath_var='LD_RUN_PATH'
case $cc_basename in
CC*)
_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
;;
sysv5* | sco3.2v5* | sco5v6*)
# Note: We can NOT use -z defs as we might desire, because we do not
# link with -lc, and that would cause any symbols used from libc to
# always be unresolved, which means just about no library would
# ever link correctly. If we're not using GNU ld we use -z text
# though, which does catch some bad symbols but isn't as heavy-handed
# as -z defs.
_LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
_LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
_LT_TAGVAR(link_all_deplibs, $1)=yes
_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
runpath_var='LD_RUN_PATH'
case $cc_basename in
CC*)
_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
'"$_LT_TAGVAR(old_archive_cmds, $1)"
_LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
'"$_LT_TAGVAR(reload_cmds, $1)"
;;
*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
;;
tandem*)
case $cc_basename in
NCC*)
# NonStop-UX NCC 3.20
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
*)
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
esac
;;
vxworks*)
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
*)
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
;;
esac
AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
_LT_TAGVAR(GCC, $1)="$GXX"
_LT_TAGVAR(LD, $1)="$LD"
## CAVEAT EMPTOR:
## There is no encapsulation within the following macros, do not change
## the running order or otherwise move them around unless you know exactly
## what you are doing...
_LT_SYS_HIDDEN_LIBDEPS($1)
_LT_COMPILER_PIC($1)
_LT_COMPILER_C_O($1)
_LT_COMPILER_FILE_LOCKS($1)
_LT_LINKER_SHLIBS($1)
_LT_SYS_DYNAMIC_LINKER($1)
_LT_LINKER_HARDCODE_LIBPATH($1)
_LT_CONFIG($1)
fi # test -n "$compiler"
CC=$lt_save_CC
CFLAGS=$lt_save_CFLAGS
LDCXX=$LD
LD=$lt_save_LD
GCC=$lt_save_GCC
with_gnu_ld=$lt_save_with_gnu_ld
lt_cv_path_LDCXX=$lt_cv_path_LD
lt_cv_path_LD=$lt_save_path_LD
lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
fi # test "$_lt_caught_CXX_error" != yes
AC_LANG_POP
])# _LT_LANG_CXX_CONFIG
# _LT_FUNC_STRIPNAME_CNF
# ----------------------
# func_stripname_cnf prefix suffix name
# strip PREFIX and SUFFIX off of NAME.
# PREFIX and SUFFIX must not contain globbing or regex special
# characters, hashes, percent signs, but SUFFIX may contain a leading
# dot (in which case that matches only a dot).
#
# This function is identical to the (non-XSI) version of func_stripname,
# except this one can be used by m4 code that may be executed by configure,
# rather than the libtool script.
m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
AC_REQUIRE([_LT_DECL_SED])
AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
func_stripname_cnf ()
{
case ${2} in
.*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
esac
} # func_stripname_cnf
])# _LT_FUNC_STRIPNAME_CNF
# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
# ---------------------------------
# Figure out "hidden" library dependencies from verbose
# compiler output when linking a shared library.
# Parse the compiler output and extract the necessary
# objects, libraries and library flags.
m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
# Dependencies to place before and after the object being linked:
_LT_TAGVAR(predep_objects, $1)=
_LT_TAGVAR(postdep_objects, $1)=
_LT_TAGVAR(predeps, $1)=
_LT_TAGVAR(postdeps, $1)=
_LT_TAGVAR(compiler_lib_search_path, $1)=
dnl we can't use the lt_simple_compile_test_code here,
dnl because it contains code intended for an executable,
dnl not a library. It's possible we should let each
dnl tag define a new lt_????_link_test_code variable,
dnl but it's only used here...
m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
int a;
void foo (void) { a = 0; }
_LT_EOF
], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
class Foo
{
public:
Foo (void) { a = 0; }
private:
int a;
};
_LT_EOF
], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
subroutine foo
implicit none
integer*4 a
a=0
return
end
_LT_EOF
], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
subroutine foo
implicit none
integer a
a=0
return
end
_LT_EOF
], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
public class foo {
private int a;
public void bar (void) {
a = 0;
}
};
_LT_EOF
], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
package foo
func foo() {
}
_LT_EOF
])
_lt_libdeps_save_CFLAGS=$CFLAGS
case "$CC $CFLAGS " in #(
*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
esac
dnl Parse the compiler output and extract the necessary
dnl objects, libraries and library flags.
if AC_TRY_EVAL(ac_compile); then
# Parse the compiler output and extract the necessary
# objects, libraries and library flags.
# Sentinel used to keep track of whether or not we are before
# the conftest object file.
pre_test_object_deps_done=no
for p in `eval "$output_verbose_link_cmd"`; do
case ${prev}${p} in
-L* | -R* | -l*)
# Some compilers place space between "-{L,R}" and the path.
# Remove the space.
if test $p = "-L" ||
test $p = "-R"; then
prev=$p
continue
fi
# Expand the sysroot to ease extracting the directories later.
if test -z "$prev"; then
case $p in
-L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
-R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
-l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
esac
fi
case $p in
=*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
esac
if test "$pre_test_object_deps_done" = no; then
case ${prev} in
-L | -R)
# Internal compiler library paths should come after those
# provided the user. The postdeps already come after the
# user supplied libs so there is no need to process them.
if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
_LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
else
_LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
fi
;;
# The "-l" case would never come before the object being
# linked, so don't bother handling this case.
esac
else
if test -z "$_LT_TAGVAR(postdeps, $1)"; then
_LT_TAGVAR(postdeps, $1)="${prev}${p}"
else
_LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
fi
fi
prev=
;;
*.lto.$objext) ;; # Ignore GCC LTO objects
*.$objext)
# This assumes that the test object file only shows up
# once in the compiler output.
if test "$p" = "conftest.$objext"; then
pre_test_object_deps_done=yes
continue
fi
if test "$pre_test_object_deps_done" = no; then
if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
_LT_TAGVAR(predep_objects, $1)="$p"
else
_LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
fi
else
if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
_LT_TAGVAR(postdep_objects, $1)="$p"
else
_LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
fi
fi
;;
*) ;; # Ignore the rest.
esac
done
# Clean up.
rm -f a.out a.exe
else
echo "libtool.m4: error: problem compiling $1 test program"
fi
$RM -f confest.$objext
CFLAGS=$_lt_libdeps_save_CFLAGS
# PORTME: override above test on systems where it is broken
m4_if([$1], [CXX],
[case $host_os in
interix[[3-9]]*)
# Interix 3.5 installs completely hosed .la files for C++, so rather than
# hack all around it, let's just trust "g++" to DTRT.
_LT_TAGVAR(predep_objects,$1)=
_LT_TAGVAR(postdep_objects,$1)=
_LT_TAGVAR(postdeps,$1)=
;;
linux*)
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*)
# Sun C++ 5.9
# The more standards-conforming stlport4 library is
# incompatible with the Cstd library. Avoid specifying
# it if it's in CXXFLAGS. Ignore libCrun as
# -library=stlport4 depends on it.
case " $CXX $CXXFLAGS " in
*" -library=stlport4 "*)
solaris_use_stlport4=yes
;;
esac
if test "$solaris_use_stlport4" != yes; then
_LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
fi
;;
esac
;;
solaris*)
case $cc_basename in
CC* | sunCC*)
# The more standards-conforming stlport4 library is
# incompatible with the Cstd library. Avoid specifying
# it if it's in CXXFLAGS. Ignore libCrun as
# -library=stlport4 depends on it.
case " $CXX $CXXFLAGS " in
*" -library=stlport4 "*)
solaris_use_stlport4=yes
;;
esac
# Adding this requires a known-good setup of shared libraries for
# Sun compiler versions before 5.6, else PIC objects from an old
# archive will be linked into the output, leading to subtle bugs.
if test "$solaris_use_stlport4" != yes; then
_LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
fi
;;
esac
;;
esac
])
case " $_LT_TAGVAR(postdeps, $1) " in
*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
esac
_LT_TAGVAR(compiler_lib_search_dirs, $1)=
if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
_LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
fi
_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
[The directories searched by this compiler when creating a shared library])
_LT_TAGDECL([], [predep_objects], [1],
[Dependencies to place before and after the objects being linked to
create a shared library])
_LT_TAGDECL([], [postdep_objects], [1])
_LT_TAGDECL([], [predeps], [1])
_LT_TAGDECL([], [postdeps], [1])
_LT_TAGDECL([], [compiler_lib_search_path], [1],
[The library search path used internally by the compiler when linking
a shared library])
])# _LT_SYS_HIDDEN_LIBDEPS
# _LT_LANG_F77_CONFIG([TAG])
# --------------------------
# Ensure that the configuration variables for a Fortran 77 compiler are
# suitably defined. These variables are subsequently used by _LT_CONFIG
# to write the compiler configuration to `libtool'.
m4_defun([_LT_LANG_F77_CONFIG],
[AC_LANG_PUSH(Fortran 77)
if test -z "$F77" || test "X$F77" = "Xno"; then
_lt_disable_F77=yes
fi
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(allow_undefined_flag, $1)=
_LT_TAGVAR(always_export_symbols, $1)=no
_LT_TAGVAR(archive_expsym_cmds, $1)=
_LT_TAGVAR(export_dynamic_flag_spec, $1)=
_LT_TAGVAR(hardcode_direct, $1)=no
_LT_TAGVAR(hardcode_direct_absolute, $1)=no
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
_LT_TAGVAR(hardcode_libdir_separator, $1)=
_LT_TAGVAR(hardcode_minus_L, $1)=no
_LT_TAGVAR(hardcode_automatic, $1)=no
_LT_TAGVAR(inherit_rpath, $1)=no
_LT_TAGVAR(module_cmds, $1)=
_LT_TAGVAR(module_expsym_cmds, $1)=
_LT_TAGVAR(link_all_deplibs, $1)=unknown
_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
_LT_TAGVAR(reload_flag, $1)=$reload_flag
_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
_LT_TAGVAR(no_undefined_flag, $1)=
_LT_TAGVAR(whole_archive_flag_spec, $1)=
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
# Source file extension for f77 test sources.
ac_ext=f
# Object file extension for compiled f77 test sources.
objext=o
_LT_TAGVAR(objext, $1)=$objext
# No sense in running all these tests if we already determined that
# the F77 compiler isn't working. Some variables (like enable_shared)
# are currently assumed to apply to all compilers on this platform,
# and will be corrupted by setting them based on a non-working compiler.
if test "$_lt_disable_F77" != yes; then
# Code to be used in simple compile tests
lt_simple_compile_test_code="\
subroutine t
return
end
"
# Code to be used in simple link tests
lt_simple_link_test_code="\
program t
end
"
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
_LT_TAG_COMPILER
# save warnings/boilerplate of simple test code
_LT_COMPILER_BOILERPLATE
_LT_LINKER_BOILERPLATE
# Allow CC to be a program name with arguments.
lt_save_CC="$CC"
lt_save_GCC=$GCC
lt_save_CFLAGS=$CFLAGS
CC=${F77-"f77"}
CFLAGS=$FFLAGS
compiler=$CC
_LT_TAGVAR(compiler, $1)=$CC
_LT_CC_BASENAME([$compiler])
GCC=$G77
if test -n "$compiler"; then
AC_MSG_CHECKING([if libtool supports shared libraries])
AC_MSG_RESULT([$can_build_shared])
AC_MSG_CHECKING([whether to build shared libraries])
test "$can_build_shared" = "no" && enable_shared=no
# On AIX, shared libraries and static libraries use the same namespace, and
# are all built from PIC.
case $host_os in
aix3*)
test "$enable_shared" = yes && enable_static=no
if test -n "$RANLIB"; then
archive_cmds="$archive_cmds~\$RANLIB \$lib"
postinstall_cmds='$RANLIB $lib'
fi
;;
aix[[4-9]]*)
if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
test "$enable_shared" = yes && enable_static=no
fi
;;
esac
AC_MSG_RESULT([$enable_shared])
AC_MSG_CHECKING([whether to build static libraries])
# Make sure either enable_shared or enable_static is yes.
test "$enable_shared" = yes || enable_static=yes
AC_MSG_RESULT([$enable_static])
_LT_TAGVAR(GCC, $1)="$G77"
_LT_TAGVAR(LD, $1)="$LD"
## CAVEAT EMPTOR:
## There is no encapsulation within the following macros, do not change
## the running order or otherwise move them around unless you know exactly
## what you are doing...
_LT_COMPILER_PIC($1)
_LT_COMPILER_C_O($1)
_LT_COMPILER_FILE_LOCKS($1)
_LT_LINKER_SHLIBS($1)
_LT_SYS_DYNAMIC_LINKER($1)
_LT_LINKER_HARDCODE_LIBPATH($1)
_LT_CONFIG($1)
fi # test -n "$compiler"
GCC=$lt_save_GCC
CC="$lt_save_CC"
CFLAGS="$lt_save_CFLAGS"
fi # test "$_lt_disable_F77" != yes
AC_LANG_POP
])# _LT_LANG_F77_CONFIG
# _LT_LANG_FC_CONFIG([TAG])
# -------------------------
# Ensure that the configuration variables for a Fortran compiler are
# suitably defined. These variables are subsequently used by _LT_CONFIG
# to write the compiler configuration to `libtool'.
m4_defun([_LT_LANG_FC_CONFIG],
[AC_LANG_PUSH(Fortran)
if test -z "$FC" || test "X$FC" = "Xno"; then
_lt_disable_FC=yes
fi
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(allow_undefined_flag, $1)=
_LT_TAGVAR(always_export_symbols, $1)=no
_LT_TAGVAR(archive_expsym_cmds, $1)=
_LT_TAGVAR(export_dynamic_flag_spec, $1)=
_LT_TAGVAR(hardcode_direct, $1)=no
_LT_TAGVAR(hardcode_direct_absolute, $1)=no
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
_LT_TAGVAR(hardcode_libdir_separator, $1)=
_LT_TAGVAR(hardcode_minus_L, $1)=no
_LT_TAGVAR(hardcode_automatic, $1)=no
_LT_TAGVAR(inherit_rpath, $1)=no
_LT_TAGVAR(module_cmds, $1)=
_LT_TAGVAR(module_expsym_cmds, $1)=
_LT_TAGVAR(link_all_deplibs, $1)=unknown
_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
_LT_TAGVAR(reload_flag, $1)=$reload_flag
_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
_LT_TAGVAR(no_undefined_flag, $1)=
_LT_TAGVAR(whole_archive_flag_spec, $1)=
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
# Source file extension for fc test sources.
ac_ext=${ac_fc_srcext-f}
# Object file extension for compiled fc test sources.
objext=o
_LT_TAGVAR(objext, $1)=$objext
# No sense in running all these tests if we already determined that
# the FC compiler isn't working. Some variables (like enable_shared)
# are currently assumed to apply to all compilers on this platform,
# and will be corrupted by setting them based on a non-working compiler.
if test "$_lt_disable_FC" != yes; then
# Code to be used in simple compile tests
lt_simple_compile_test_code="\
subroutine t
return
end
"
# Code to be used in simple link tests
lt_simple_link_test_code="\
program t
end
"
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
_LT_TAG_COMPILER
# save warnings/boilerplate of simple test code
_LT_COMPILER_BOILERPLATE
_LT_LINKER_BOILERPLATE
# Allow CC to be a program name with arguments.
lt_save_CC="$CC"
lt_save_GCC=$GCC
lt_save_CFLAGS=$CFLAGS
CC=${FC-"f95"}
CFLAGS=$FCFLAGS
compiler=$CC
GCC=$ac_cv_fc_compiler_gnu
_LT_TAGVAR(compiler, $1)=$CC
_LT_CC_BASENAME([$compiler])
if test -n "$compiler"; then
AC_MSG_CHECKING([if libtool supports shared libraries])
AC_MSG_RESULT([$can_build_shared])
AC_MSG_CHECKING([whether to build shared libraries])
test "$can_build_shared" = "no" && enable_shared=no
# On AIX, shared libraries and static libraries use the same namespace, and
# are all built from PIC.
case $host_os in
aix3*)
test "$enable_shared" = yes && enable_static=no
if test -n "$RANLIB"; then
archive_cmds="$archive_cmds~\$RANLIB \$lib"
postinstall_cmds='$RANLIB $lib'
fi
;;
aix[[4-9]]*)
if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
test "$enable_shared" = yes && enable_static=no
fi
;;
esac
AC_MSG_RESULT([$enable_shared])
AC_MSG_CHECKING([whether to build static libraries])
# Make sure either enable_shared or enable_static is yes.
test "$enable_shared" = yes || enable_static=yes
AC_MSG_RESULT([$enable_static])
_LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
_LT_TAGVAR(LD, $1)="$LD"
## CAVEAT EMPTOR:
## There is no encapsulation within the following macros, do not change
## the running order or otherwise move them around unless you know exactly
## what you are doing...
_LT_SYS_HIDDEN_LIBDEPS($1)
_LT_COMPILER_PIC($1)
_LT_COMPILER_C_O($1)
_LT_COMPILER_FILE_LOCKS($1)
_LT_LINKER_SHLIBS($1)
_LT_SYS_DYNAMIC_LINKER($1)
_LT_LINKER_HARDCODE_LIBPATH($1)
_LT_CONFIG($1)
fi # test -n "$compiler"
GCC=$lt_save_GCC
CC=$lt_save_CC
CFLAGS=$lt_save_CFLAGS
fi # test "$_lt_disable_FC" != yes
AC_LANG_POP
])# _LT_LANG_FC_CONFIG
# _LT_LANG_GCJ_CONFIG([TAG])
# --------------------------
# Ensure that the configuration variables for the GNU Java Compiler compiler
# are suitably defined. These variables are subsequently used by _LT_CONFIG
# to write the compiler configuration to `libtool'.
m4_defun([_LT_LANG_GCJ_CONFIG],
[AC_REQUIRE([LT_PROG_GCJ])dnl
AC_LANG_SAVE
# Source file extension for Java test sources.
ac_ext=java
# Object file extension for compiled Java test sources.
objext=o
_LT_TAGVAR(objext, $1)=$objext
# Code to be used in simple compile tests
lt_simple_compile_test_code="class foo {}"
# Code to be used in simple link tests
lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
_LT_TAG_COMPILER
# save warnings/boilerplate of simple test code
_LT_COMPILER_BOILERPLATE
_LT_LINKER_BOILERPLATE
# Allow CC to be a program name with arguments.
lt_save_CC=$CC
lt_save_CFLAGS=$CFLAGS
lt_save_GCC=$GCC
GCC=yes
CC=${GCJ-"gcj"}
CFLAGS=$GCJFLAGS
compiler=$CC
_LT_TAGVAR(compiler, $1)=$CC
_LT_TAGVAR(LD, $1)="$LD"
_LT_CC_BASENAME([$compiler])
# GCJ did not exist at the time GCC didn't implicitly link libc in.
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
_LT_TAGVAR(reload_flag, $1)=$reload_flag
_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
## CAVEAT EMPTOR:
## There is no encapsulation within the following macros, do not change
## the running order or otherwise move them around unless you know exactly
## what you are doing...
if test -n "$compiler"; then
_LT_COMPILER_NO_RTTI($1)
_LT_COMPILER_PIC($1)
_LT_COMPILER_C_O($1)
_LT_COMPILER_FILE_LOCKS($1)
_LT_LINKER_SHLIBS($1)
_LT_LINKER_HARDCODE_LIBPATH($1)
_LT_CONFIG($1)
fi
AC_LANG_RESTORE
GCC=$lt_save_GCC
CC=$lt_save_CC
CFLAGS=$lt_save_CFLAGS
])# _LT_LANG_GCJ_CONFIG
# _LT_LANG_GO_CONFIG([TAG])
# --------------------------
# Ensure that the configuration variables for the GNU Go compiler
# are suitably defined. These variables are subsequently used by _LT_CONFIG
# to write the compiler configuration to `libtool'.
m4_defun([_LT_LANG_GO_CONFIG],
[AC_REQUIRE([LT_PROG_GO])dnl
AC_LANG_SAVE
# Source file extension for Go test sources.
ac_ext=go
# Object file extension for compiled Go test sources.
objext=o
_LT_TAGVAR(objext, $1)=$objext
# Code to be used in simple compile tests
lt_simple_compile_test_code="package main; func main() { }"
# Code to be used in simple link tests
lt_simple_link_test_code='package main; func main() { }'
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
_LT_TAG_COMPILER
# save warnings/boilerplate of simple test code
_LT_COMPILER_BOILERPLATE
_LT_LINKER_BOILERPLATE
# Allow CC to be a program name with arguments.
lt_save_CC=$CC
lt_save_CFLAGS=$CFLAGS
lt_save_GCC=$GCC
GCC=yes
CC=${GOC-"gccgo"}
CFLAGS=$GOFLAGS
compiler=$CC
_LT_TAGVAR(compiler, $1)=$CC
_LT_TAGVAR(LD, $1)="$LD"
_LT_CC_BASENAME([$compiler])
# Go did not exist at the time GCC didn't implicitly link libc in.
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
_LT_TAGVAR(reload_flag, $1)=$reload_flag
_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
## CAVEAT EMPTOR:
## There is no encapsulation within the following macros, do not change
## the running order or otherwise move them around unless you know exactly
## what you are doing...
if test -n "$compiler"; then
_LT_COMPILER_NO_RTTI($1)
_LT_COMPILER_PIC($1)
_LT_COMPILER_C_O($1)
_LT_COMPILER_FILE_LOCKS($1)
_LT_LINKER_SHLIBS($1)
_LT_LINKER_HARDCODE_LIBPATH($1)
_LT_CONFIG($1)
fi
AC_LANG_RESTORE
GCC=$lt_save_GCC
CC=$lt_save_CC
CFLAGS=$lt_save_CFLAGS
])# _LT_LANG_GO_CONFIG
# _LT_LANG_RC_CONFIG([TAG])
# -------------------------
# Ensure that the configuration variables for the Windows resource compiler
# are suitably defined. These variables are subsequently used by _LT_CONFIG
# to write the compiler configuration to `libtool'.
m4_defun([_LT_LANG_RC_CONFIG],
[AC_REQUIRE([LT_PROG_RC])dnl
AC_LANG_SAVE
# Source file extension for RC test sources.
ac_ext=rc
# Object file extension for compiled RC test sources.
objext=o
_LT_TAGVAR(objext, $1)=$objext
# Code to be used in simple compile tests
lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
# Code to be used in simple link tests
lt_simple_link_test_code="$lt_simple_compile_test_code"
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
_LT_TAG_COMPILER
# save warnings/boilerplate of simple test code
_LT_COMPILER_BOILERPLATE
_LT_LINKER_BOILERPLATE
# Allow CC to be a program name with arguments.
lt_save_CC="$CC"
lt_save_CFLAGS=$CFLAGS
lt_save_GCC=$GCC
GCC=
CC=${RC-"windres"}
CFLAGS=
compiler=$CC
_LT_TAGVAR(compiler, $1)=$CC
_LT_CC_BASENAME([$compiler])
_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
if test -n "$compiler"; then
:
_LT_CONFIG($1)
fi
GCC=$lt_save_GCC
AC_LANG_RESTORE
CC=$lt_save_CC
CFLAGS=$lt_save_CFLAGS
])# _LT_LANG_RC_CONFIG
# LT_PROG_GCJ
# -----------
AC_DEFUN([LT_PROG_GCJ],
[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
[m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
[AC_CHECK_TOOL(GCJ, gcj,)
test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
AC_SUBST(GCJFLAGS)])])[]dnl
])
# Old name:
AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
# LT_PROG_GO
# ----------
AC_DEFUN([LT_PROG_GO],
[AC_CHECK_TOOL(GOC, gccgo,)
])
# LT_PROG_RC
# ----------
AC_DEFUN([LT_PROG_RC],
[AC_CHECK_TOOL(RC, windres,)
])
# Old name:
AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([LT_AC_PROG_RC], [])
# _LT_DECL_EGREP
# --------------
# If we don't have a new enough Autoconf to choose the best grep
# available, choose the one first in the user's PATH.
m4_defun([_LT_DECL_EGREP],
[AC_REQUIRE([AC_PROG_EGREP])dnl
AC_REQUIRE([AC_PROG_FGREP])dnl
test -z "$GREP" && GREP=grep
_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
_LT_DECL([], [EGREP], [1], [An ERE matcher])
_LT_DECL([], [FGREP], [1], [A literal string matcher])
dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
AC_SUBST([GREP])
])
# _LT_DECL_OBJDUMP
# --------------
# If we don't have a new enough Autoconf to choose the best objdump
# available, choose the one first in the user's PATH.
m4_defun([_LT_DECL_OBJDUMP],
[AC_CHECK_TOOL(OBJDUMP, objdump, false)
test -z "$OBJDUMP" && OBJDUMP=objdump
_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
AC_SUBST([OBJDUMP])
])
# _LT_DECL_DLLTOOL
# ----------------
# Ensure DLLTOOL variable is set.
m4_defun([_LT_DECL_DLLTOOL],
[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
test -z "$DLLTOOL" && DLLTOOL=dlltool
_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
AC_SUBST([DLLTOOL])
])
# _LT_DECL_SED
# ------------
# Check for a fully-functional sed program, that truncates
# as few characters as possible. Prefer GNU sed if found.
m4_defun([_LT_DECL_SED],
[AC_PROG_SED
test -z "$SED" && SED=sed
Xsed="$SED -e 1s/^X//"
_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
[Sed that helps us avoid accidentally triggering echo(1) options like -n])
])# _LT_DECL_SED
m4_ifndef([AC_PROG_SED], [
############################################################
# NOTE: This macro has been submitted for inclusion into #
# GNU Autoconf as AC_PROG_SED. When it is available in #
# a released version of Autoconf we should remove this #
# macro and use it instead. #
############################################################
m4_defun([AC_PROG_SED],
[AC_MSG_CHECKING([for a sed that does not truncate output])
AC_CACHE_VAL(lt_cv_path_SED,
[# Loop through the user's path and test for sed and gsed.
# Then use that list of sed's as ones to test for truncation.
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for lt_ac_prog in sed gsed; do
for ac_exec_ext in '' $ac_executable_extensions; do
if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
fi
done
done
done
IFS=$as_save_IFS
lt_ac_max=0
lt_ac_count=0
# Add /usr/xpg4/bin/sed as it is typically found on Solaris
# along with /bin/sed that truncates output.
for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
test ! -f $lt_ac_sed && continue
cat /dev/null > conftest.in
lt_ac_count=0
echo $ECHO_N "0123456789$ECHO_C" >conftest.in
# Check for GNU sed and select it if it is found.
if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
lt_cv_path_SED=$lt_ac_sed
break
fi
while true; do
cat conftest.in conftest.in >conftest.tmp
mv conftest.tmp conftest.in
cp conftest.in conftest.nl
echo >>conftest.nl
$lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
cmp -s conftest.out conftest.nl || break
# 10000 chars as input seems more than enough
test $lt_ac_count -gt 10 && break
lt_ac_count=`expr $lt_ac_count + 1`
if test $lt_ac_count -gt $lt_ac_max; then
lt_ac_max=$lt_ac_count
lt_cv_path_SED=$lt_ac_sed
fi
done
done
])
SED=$lt_cv_path_SED
AC_SUBST([SED])
AC_MSG_RESULT([$SED])
])#AC_PROG_SED
])#m4_ifndef
# Old name:
AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([LT_AC_PROG_SED], [])
# _LT_CHECK_SHELL_FEATURES
# ------------------------
# Find out whether the shell is Bourne or XSI compatible,
# or has some other useful features.
m4_defun([_LT_CHECK_SHELL_FEATURES],
[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
# Try some XSI features
xsi_shell=no
( _lt_dummy="a/b/c"
test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
= c,a/b,b/c, \
&& eval 'test $(( 1 + 1 )) -eq 2 \
&& test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
&& xsi_shell=yes
AC_MSG_RESULT([$xsi_shell])
_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
AC_MSG_CHECKING([whether the shell understands "+="])
lt_shell_append=no
( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
>/dev/null 2>&1 \
&& lt_shell_append=yes
AC_MSG_RESULT([$lt_shell_append])
_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
lt_unset=unset
else
lt_unset=false
fi
_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
# test EBCDIC or ASCII
case `echo X|tr X '\101'` in
A) # ASCII based system
# \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
lt_SP2NL='tr \040 \012'
lt_NL2SP='tr \015\012 \040\040'
;;
*) # EBCDIC based system
lt_SP2NL='tr \100 \n'
lt_NL2SP='tr \r\n \100\100'
;;
esac
_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
])# _LT_CHECK_SHELL_FEATURES
# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
# ------------------------------------------------------
# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
m4_defun([_LT_PROG_FUNCTION_REPLACE],
[dnl {
sed -e '/^$1 ()$/,/^} # $1 /c\
$1 ()\
{\
m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1])
} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
&& mv -f "$cfgfile.tmp" "$cfgfile" \
|| (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
test 0 -eq $? || _lt_function_replace_fail=:
])
# _LT_PROG_REPLACE_SHELLFNS
# -------------------------
# Replace existing portable implementations of several shell functions with
# equivalent extended shell implementations where those features are available..
m4_defun([_LT_PROG_REPLACE_SHELLFNS],
[if test x"$xsi_shell" = xyes; then
_LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
case ${1} in
*/*) func_dirname_result="${1%/*}${2}" ;;
* ) func_dirname_result="${3}" ;;
esac])
_LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
func_basename_result="${1##*/}"])
_LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
case ${1} in
*/*) func_dirname_result="${1%/*}${2}" ;;
* ) func_dirname_result="${3}" ;;
esac
func_basename_result="${1##*/}"])
_LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
# pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
# positional parameters, so assign one to ordinary parameter first.
func_stripname_result=${3}
func_stripname_result=${func_stripname_result#"${1}"}
func_stripname_result=${func_stripname_result%"${2}"}])
_LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
func_split_long_opt_name=${1%%=*}
func_split_long_opt_arg=${1#*=}])
_LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
func_split_short_opt_arg=${1#??}
func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
_LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
case ${1} in
*.lo) func_lo2o_result=${1%.lo}.${objext} ;;
*) func_lo2o_result=${1} ;;
esac])
_LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo])
_LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))])
_LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}])
fi
if test x"$lt_shell_append" = xyes; then
_LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"])
_LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
func_quote_for_eval "${2}"
dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
# Save a `func_append' function call where possible by direct use of '+='
sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
&& mv -f "$cfgfile.tmp" "$cfgfile" \
|| (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
test 0 -eq $? || _lt_function_replace_fail=:
else
# Save a `func_append' function call even when '+=' is not available
sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
&& mv -f "$cfgfile.tmp" "$cfgfile" \
|| (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
test 0 -eq $? || _lt_function_replace_fail=:
fi
if test x"$_lt_function_replace_fail" = x":"; then
AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
fi
])
# _LT_PATH_CONVERSION_FUNCTIONS
# -----------------------------
# Determine which file name conversion functions should be used by
# func_to_host_file (and, implicitly, by func_to_host_path). These are needed
# for certain cross-compile configurations and native mingw.
m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
AC_REQUIRE([AC_CANONICAL_BUILD])dnl
AC_MSG_CHECKING([how to convert $build file names to $host format])
AC_CACHE_VAL(lt_cv_to_host_file_cmd,
[case $host in
*-*-mingw* )
case $build in
*-*-mingw* ) # actually msys
lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
;;
*-*-cygwin* )
lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
;;
* ) # otherwise, assume *nix
lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
;;
esac
;;
*-*-cygwin* )
case $build in
*-*-mingw* ) # actually msys
lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
;;
*-*-cygwin* )
lt_cv_to_host_file_cmd=func_convert_file_noop
;;
* ) # otherwise, assume *nix
lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
;;
esac
;;
* ) # unhandled hosts (and "normal" native builds)
lt_cv_to_host_file_cmd=func_convert_file_noop
;;
esac
])
to_host_file_cmd=$lt_cv_to_host_file_cmd
AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
[0], [convert $build file names to $host format])dnl
AC_MSG_CHECKING([how to convert $build file names to toolchain format])
AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
[#assume ordinary cross tools, or native build.
lt_cv_to_tool_file_cmd=func_convert_file_noop
case $host in
*-*-mingw* )
case $build in
*-*-mingw* ) # actually msys
lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
;;
esac
;;
esac
])
to_tool_file_cmd=$lt_cv_to_tool_file_cmd
AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
[0], [convert $build files to toolchain format])dnl
])# _LT_PATH_CONVERSION_FUNCTIONS
nanomsg-0.8-beta/m4/ltoptions.m40000644000175000017500000003007312623652607017467 0ustar00travistravis00000000000000# Helper functions for option handling. -*- Autoconf -*-
#
# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
# Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 7 ltoptions.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
# ------------------------------------------
m4_define([_LT_MANGLE_OPTION],
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
# ---------------------------------------
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
# saved as a flag.
m4_define([_LT_SET_OPTION],
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
_LT_MANGLE_DEFUN([$1], [$2]),
[m4_warning([Unknown $1 option `$2'])])[]dnl
])
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
# ------------------------------------------------------------
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
m4_define([_LT_IF_OPTION],
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
# -------------------------------------------------------
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
# are set.
m4_define([_LT_UNLESS_OPTIONS],
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
[m4_define([$0_found])])])[]dnl
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
])[]dnl
])
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
# ----------------------------------------
# OPTION-LIST is a space-separated list of Libtool options associated
# with MACRO-NAME. If any OPTION has a matching handler declared with
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
# the unknown option and exit.
m4_defun([_LT_SET_OPTIONS],
[# Set options
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[_LT_SET_OPTION([$1], _LT_Option)])
m4_if([$1],[LT_INIT],[
dnl
dnl Simply set some default values (i.e off) if boolean options were not
dnl specified:
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
])
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
])
dnl
dnl If no reference was made to various pairs of opposing options, then
dnl we run the default mode handler for the pair. For example, if neither
dnl `shared' nor `disable-shared' was passed, we enable building of shared
dnl archives by default:
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
[_LT_ENABLE_FAST_INSTALL])
])
])# _LT_SET_OPTIONS
## --------------------------------- ##
## Macros to handle LT_INIT options. ##
## --------------------------------- ##
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
# -----------------------------------------
m4_define([_LT_MANGLE_DEFUN],
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
# -----------------------------------------------
m4_define([LT_OPTION_DEFINE],
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
])# LT_OPTION_DEFINE
# dlopen
# ------
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
])
AU_DEFUN([AC_LIBTOOL_DLOPEN],
[_LT_SET_OPTION([LT_INIT], [dlopen])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `dlopen' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
# win32-dll
# ---------
# Declare package support for building win32 dll's.
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
[enable_win32_dll=yes
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
AC_CHECK_TOOL(AS, as, false)
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
AC_CHECK_TOOL(OBJDUMP, objdump, false)
;;
esac
test -z "$AS" && AS=as
_LT_DECL([], [AS], [1], [Assembler program])dnl
test -z "$DLLTOOL" && DLLTOOL=dlltool
_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
test -z "$OBJDUMP" && OBJDUMP=objdump
_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
])# win32-dll
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
_LT_SET_OPTION([LT_INIT], [win32-dll])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `win32-dll' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
# _LT_ENABLE_SHARED([DEFAULT])
# ----------------------------
# implement the --enable-shared flag, and supports the `shared' and
# `disable-shared' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_SHARED],
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([shared],
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_shared=yes ;;
no) enable_shared=no ;;
*)
enable_shared=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_shared=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
_LT_DECL([build_libtool_libs], [enable_shared], [0],
[Whether or not to build shared libraries])
])# _LT_ENABLE_SHARED
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
# Old names:
AC_DEFUN([AC_ENABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
])
AC_DEFUN([AC_DISABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], [disable-shared])
])
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
# _LT_ENABLE_STATIC([DEFAULT])
# ----------------------------
# implement the --enable-static flag, and support the `static' and
# `disable-static' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_STATIC],
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([static],
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_static=yes ;;
no) enable_static=no ;;
*)
enable_static=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_static=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
_LT_DECL([build_old_libs], [enable_static], [0],
[Whether or not to build static libraries])
])# _LT_ENABLE_STATIC
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
# Old names:
AC_DEFUN([AC_ENABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
])
AC_DEFUN([AC_DISABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], [disable-static])
])
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
# ----------------------------------
# implement the --enable-fast-install flag, and support the `fast-install'
# and `disable-fast-install' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_FAST_INSTALL],
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([fast-install],
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_fast_install=yes ;;
no) enable_fast_install=no ;;
*)
enable_fast_install=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_fast_install=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
_LT_DECL([fast_install], [enable_fast_install], [0],
[Whether or not to optimize for fast installation])dnl
])# _LT_ENABLE_FAST_INSTALL
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
# Old names:
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the `fast-install' option into LT_INIT's first parameter.])
])
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the `disable-fast-install' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
# _LT_WITH_PIC([MODE])
# --------------------
# implement the --with-pic flag, and support the `pic-only' and `no-pic'
# LT_INIT options.
# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
m4_define([_LT_WITH_PIC],
[AC_ARG_WITH([pic],
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
[lt_p=${PACKAGE-default}
case $withval in
yes|no) pic_mode=$withval ;;
*)
pic_mode=default
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for lt_pkg in $withval; do
IFS="$lt_save_ifs"
if test "X$lt_pkg" = "X$lt_p"; then
pic_mode=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[pic_mode=default])
test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
])# _LT_WITH_PIC
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
# Old name:
AU_DEFUN([AC_LIBTOOL_PICMODE],
[_LT_SET_OPTION([LT_INIT], [pic-only])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `pic-only' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
## ----------------- ##
## LTDL_INIT Options ##
## ----------------- ##
m4_define([_LTDL_MODE], [])
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
[m4_define([_LTDL_MODE], [nonrecursive])])
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
[m4_define([_LTDL_MODE], [recursive])])
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
[m4_define([_LTDL_MODE], [subproject])])
m4_define([_LTDL_TYPE], [])
LT_OPTION_DEFINE([LTDL_INIT], [installable],
[m4_define([_LTDL_TYPE], [installable])])
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
[m4_define([_LTDL_TYPE], [convenience])])
nanomsg-0.8-beta/m4/ltsugar.m40000644000175000017500000001042412623652607017113 0ustar00travistravis00000000000000# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
#
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 6 ltsugar.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
# lt_join(SEP, ARG1, [ARG2...])
# -----------------------------
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
# associated separator.
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
# versions in m4sugar had bugs.
m4_define([lt_join],
[m4_if([$#], [1], [],
[$#], [2], [[$2]],
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
m4_define([_lt_join],
[m4_if([$#$2], [2], [],
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
# lt_car(LIST)
# lt_cdr(LIST)
# ------------
# Manipulate m4 lists.
# These macros are necessary as long as will still need to support
# Autoconf-2.59 which quotes differently.
m4_define([lt_car], [[$1]])
m4_define([lt_cdr],
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
[$#], 1, [],
[m4_dquote(m4_shift($@))])])
m4_define([lt_unquote], $1)
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
# ------------------------------------------
# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
# Note that neither SEPARATOR nor STRING are expanded; they are appended
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
# than defined and empty).
#
# This macro is needed until we can rely on Autoconf 2.62, since earlier
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
m4_define([lt_append],
[m4_define([$1],
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
# ----------------------------------------------------------
# Produce a SEP delimited list of all paired combinations of elements of
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
# has the form PREFIXmINFIXSUFFIXn.
# Needed until we can rely on m4_combine added in Autoconf 2.62.
m4_define([lt_combine],
[m4_if(m4_eval([$# > 3]), [1],
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
[[m4_foreach([_Lt_prefix], [$2],
[m4_foreach([_Lt_suffix],
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
# -----------------------------------------------------------------------
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
m4_define([lt_if_append_uniq],
[m4_ifdef([$1],
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
[lt_append([$1], [$2], [$3])$4],
[$5])],
[lt_append([$1], [$2], [$3])$4])])
# lt_dict_add(DICT, KEY, VALUE)
# -----------------------------
m4_define([lt_dict_add],
[m4_define([$1($2)], [$3])])
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
# --------------------------------------------
m4_define([lt_dict_add_subkey],
[m4_define([$1($2:$3)], [$4])])
# lt_dict_fetch(DICT, KEY, [SUBKEY])
# ----------------------------------
m4_define([lt_dict_fetch],
[m4_ifval([$3],
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
# -----------------------------------------------------------------
m4_define([lt_if_dict_fetch],
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
[$5],
[$6])])
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
# --------------------------------------------------------------
m4_define([lt_dict_filter],
[m4_if([$5], [], [],
[lt_join(m4_quote(m4_default([$4], [[, ]])),
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
])
nanomsg-0.8-beta/m4/ltversion.m40000644000175000017500000000126212623652607017457 0ustar00travistravis00000000000000# ltversion.m4 -- version numbers -*- Autoconf -*-
#
# Copyright (C) 2004 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# @configure_input@
# serial 3337 ltversion.m4
# This file is part of GNU Libtool
m4_define([LT_PACKAGE_VERSION], [2.4.2])
m4_define([LT_PACKAGE_REVISION], [1.3337])
AC_DEFUN([LTVERSION_VERSION],
[macro_version='2.4.2'
macro_revision='1.3337'
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
_LT_DECL(, macro_revision, 0)
])
nanomsg-0.8-beta/m4/lt~obsolete.m40000644000175000017500000001375612623652607020017 0ustar00travistravis00000000000000# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
#
# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004.
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 5 lt~obsolete.m4
# These exist entirely to fool aclocal when bootstrapping libtool.
#
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
# which have later been changed to m4_define as they aren't part of the
# exported API, or moved to Autoconf or Automake where they belong.
#
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
# using a macro with the same name in our local m4/libtool.m4 it'll
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
# and doesn't know about Autoconf macros at all.)
#
# So we provide this file, which has a silly filename so it's always
# included after everything else. This provides aclocal with the
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
# because those macros already exist, or will be overwritten later.
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
#
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
# Yes, that means every name once taken will need to remain here until
# we give up compatibility with versions before 1.7, at which point
# we need to keep only those names which we still refer to.
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
nanomsg-0.8-beta/perf/0000775000175000017500000000000012623652617015606 5ustar00travistravis00000000000000nanomsg-0.8-beta/perf/inproc_lat.c0000664000175000017500000000661012623652600020077 0ustar00travistravis00000000000000/*
Copyright (c) 2012 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../src/nn.h"
#include "../src/pair.h"
#include "../src/utils/attr.h"
#include "../src/utils/err.c"
#include "../src/utils/thread.c"
#include "../src/utils/sleep.c"
#include "../src/utils/stopwatch.c"
#include
#include
#include
#include
static size_t message_size;
static int roundtrip_count;
void worker (NN_UNUSED void *arg)
{
int rc;
int s;
int i;
char *buf;
s = nn_socket (AF_SP, NN_PAIR);
assert (s != -1);
rc = nn_connect (s, "inproc://inproc_lat");
assert (rc >= 0);
buf = malloc (message_size);
assert (buf);
for (i = 0; i != roundtrip_count; i++) {
rc = nn_recv (s, buf, message_size, 0);
assert (rc == (int)message_size);
rc = nn_send (s, buf, message_size, 0);
assert (rc == (int)message_size);
}
free (buf);
rc = nn_close (s);
assert (rc == 0);
}
int main (int argc, char *argv [])
{
int rc;
int s;
int i;
char *buf;
struct nn_thread thread;
struct nn_stopwatch stopwatch;
uint64_t elapsed;
double latency;
if (argc != 3) {
printf ("usage: inproc_lat \n");
return 1;
}
message_size = atoi (argv [1]);
roundtrip_count = atoi (argv [2]);
s = nn_socket (AF_SP, NN_PAIR);
assert (s != -1);
rc = nn_bind (s, "inproc://inproc_lat");
assert (rc >= 0);
buf = malloc (message_size);
assert (buf);
memset (buf, 111, message_size);
/* Wait a bit till the worker thread blocks in nn_recv(). */
nn_thread_init (&thread, worker, NULL);
nn_sleep (100);
nn_stopwatch_init (&stopwatch);
for (i = 0; i != roundtrip_count; i++) {
rc = nn_send (s, buf, message_size, 0);
assert (rc == (int)message_size);
rc = nn_recv (s, buf, message_size, 0);
assert (rc == (int)message_size);
}
elapsed = nn_stopwatch_term (&stopwatch);
latency = (double) elapsed / (roundtrip_count * 2);
printf ("message size: %d [B]\n", (int) message_size);
printf ("roundtrip count: %d\n", (int) roundtrip_count);
printf ("average latency: %.3f [us]\n", (double) latency);
nn_thread_term (&thread);
free (buf);
rc = nn_close (s);
assert (rc == 0);
return 0;
}
nanomsg-0.8-beta/perf/inproc_thr.c0000664000175000017500000000677612623652600020131 0ustar00travistravis00000000000000/*
Copyright (c) 2012 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../src/nn.h"
#include "../src/pair.h"
#include "../src/utils/attr.h"
#include "../src/utils/err.c"
#include "../src/utils/thread.c"
#include "../src/utils/stopwatch.c"
#include
#include
#include
#include
static size_t message_size;
static int message_count;
void worker (NN_UNUSED void *arg)
{
int rc;
int s;
int i;
char *buf;
s = nn_socket (AF_SP, NN_PAIR);
assert (s != -1);
rc = nn_connect (s, "inproc://inproc_thr");
assert (rc >= 0);
buf = malloc (message_size);
assert (buf);
memset (buf, 111, message_size);
rc = nn_send (s, NULL, 0, 0);
assert (rc == 0);
for (i = 0; i != message_count; i++) {
rc = nn_send (s, buf, message_size, 0);
assert (rc == (int)message_size);
}
free (buf);
rc = nn_close (s);
assert (rc == 0);
}
int main (int argc, char *argv [])
{
int rc;
int s;
int i;
char *buf;
struct nn_thread thread;
struct nn_stopwatch stopwatch;
uint64_t elapsed;
unsigned long throughput;
double megabits;
if (argc != 3) {
printf ("usage: thread_thr \n");
return 1;
}
message_size = atoi (argv [1]);
message_count = atoi (argv [2]);
s = nn_socket (AF_SP, NN_PAIR);
assert (s != -1);
rc = nn_bind (s, "inproc://inproc_thr");
assert (rc >= 0);
buf = malloc (message_size);
assert (buf);
nn_thread_init (&thread, worker, NULL);
/* First message is used to start the stopwatch. */
rc = nn_recv (s, buf, message_size, 0);
assert (rc == 0);
nn_stopwatch_init (&stopwatch);
for (i = 0; i != message_count; i++) {
rc = nn_recv (s, buf, message_size, 0);
assert (rc == (int)message_size);
}
elapsed = nn_stopwatch_term (&stopwatch);
nn_thread_term (&thread);
free (buf);
rc = nn_close (s);
assert (rc == 0);
if (elapsed == 0)
elapsed = 1;
throughput = (unsigned long)
((double) message_count / (double) elapsed * 1000000);
megabits = (double) (throughput * message_size * 8) / 1000000;
printf ("message size: %d [B]\n", (int) message_size);
printf ("message count: %d\n", (int) message_count);
printf ("mean throughput: %d [msg/s]\n", (int) throughput);
printf ("mean throughput: %.3f [Mb/s]\n", (double) megabits);
return 0;
}
nanomsg-0.8-beta/perf/local_lat.c0000664000175000017500000000427012623652600017677 0ustar00travistravis00000000000000/*
Copyright (c) 2012 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../src/nn.h"
#include "../src/tcp.h"
#include "../src/pair.h"
#include
#include
#include
#include
int main (int argc, char *argv [])
{
const char *bind_to;
size_t sz;
int rts;
char *buf;
int nbytes;
int s;
int rc;
int i;
int opt;
if (argc != 4) {
printf ("usage: local_lat \n");
return 1;
}
bind_to = argv [1];
sz = atoi (argv [2]);
rts = atoi (argv [3]);
s = nn_socket (AF_SP, NN_PAIR);
assert (s != -1);
opt = 1;
rc = nn_setsockopt (s, NN_TCP, NN_TCP_NODELAY, &opt, sizeof (opt));
assert (rc == 0);
rc = nn_bind (s, bind_to);
assert (rc >= 0);
buf = malloc (sz);
assert (buf);
memset (buf, 111, sz);
for (i = 0; i != rts; i++) {
nbytes = nn_recv (s, buf, sz, 0);
assert (nbytes == (int)sz);
nbytes = nn_send (s, buf, sz, 0);
assert (nbytes == (int)sz);
}
free (buf);
rc = nn_close (s);
assert (rc == 0);
return 0;
}
nanomsg-0.8-beta/perf/local_thr.c0000664000175000017500000000502012623652600017706 0ustar00travistravis00000000000000/*
Copyright (c) 2012 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../src/nn.h"
#include "../src/pair.h"
#include
#include
#include
#include "../src/utils/stopwatch.c"
int main (int argc, char *argv [])
{
const char *bind_to;
size_t sz;
int count;
char *buf;
int nbytes;
int s;
int rc;
int i;
struct nn_stopwatch sw;
uint64_t total;
uint64_t thr;
double mbs;
if (argc != 4) {
printf ("usage: local_thr \n");
return 1;
}
bind_to = argv [1];
sz = atoi (argv [2]);
count = atoi (argv [3]);
s = nn_socket (AF_SP, NN_PAIR);
assert (s != -1);
rc = nn_bind (s, bind_to);
assert (rc >= 0);
buf = malloc (sz);
assert (buf);
nbytes = nn_recv (s, buf, sz, 0);
assert (nbytes == 0);
nn_stopwatch_init (&sw);
for (i = 0; i != count; i++) {
nbytes = nn_recv (s, buf, sz, 0);
assert (nbytes == (int)sz);
}
total = nn_stopwatch_term (&sw);
if (total == 0)
total = 1;
thr = (uint64_t) ((double) count / (double) total * 1000000);
mbs = (double) (thr * sz * 8) / 1000000;
printf ("message size: %d [B]\n", (int) sz);
printf ("message count: %d\n", (int) count);
printf ("throughput: %d [msg/s]\n", (int) thr);
printf ("throughput: %.3f [Mb/s]\n", (double) mbs);
free (buf);
rc = nn_close (s);
assert (rc == 0);
return 0;
}
nanomsg-0.8-beta/perf/remote_lat.c0000664000175000017500000000506412623652600020102 0ustar00travistravis00000000000000/*
Copyright (c) 2012 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../src/nn.h"
#include "../src/tcp.h"
#include "../src/pair.h"
#include
#include
#include
#include
#include "../src/utils/stopwatch.c"
int main (int argc, char *argv [])
{
const char *connect_to;
size_t sz;
int rts;
char *buf;
int nbytes;
int s;
int rc;
int i;
int opt;
struct nn_stopwatch sw;
uint64_t total;
double lat;
if (argc != 4) {
printf ("usage: remote_lat \n");
return 1;
}
connect_to = argv [1];
sz = atoi (argv [2]);
rts = atoi (argv [3]);
s = nn_socket (AF_SP, NN_PAIR);
assert (s != -1);
opt = 1;
rc = nn_setsockopt (s, NN_TCP, NN_TCP_NODELAY, &opt, sizeof (opt));
assert (rc == 0);
rc = nn_connect (s, connect_to);
assert (rc >= 0);
buf = malloc (sz);
assert (buf);
memset (buf, 111, sz);
nn_stopwatch_init (&sw);
for (i = 0; i != rts; i++) {
nbytes = nn_send (s, buf, sz, 0);
assert (nbytes == (int)sz);
nbytes = nn_recv (s, buf, sz, 0);
assert (nbytes == (int)sz);
}
total = nn_stopwatch_term (&sw);
lat = (double) total / (rts * 2);
printf ("message size: %d [B]\n", (int) sz);
printf ("roundtrip count: %d\n", (int) rts);
printf ("average latency: %.3f [us]\n", (double) lat);
free (buf);
rc = nn_close (s);
assert (rc == 0);
return 0;
}
nanomsg-0.8-beta/perf/remote_thr.c0000664000175000017500000000405712623652600020120 0ustar00travistravis00000000000000/*
Copyright (c) 2012 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../src/nn.h"
#include "../src/pair.h"
#include
#include
#include
#include
int main (int argc, char *argv [])
{
const char *connect_to;
size_t sz;
int count;
char *buf;
int nbytes;
int s;
int rc;
int i;
if (argc != 4) {
printf ("usage: remote_thr \n");
return 1;
}
connect_to = argv [1];
sz = atoi (argv [2]);
count = atoi (argv [3]);
s = nn_socket (AF_SP, NN_PAIR);
assert (s != -1);
rc = nn_connect (s, connect_to);
assert (rc >= 0);
buf = malloc (sz);
assert (buf);
memset (buf, 111, sz);
nbytes = nn_send (s, buf, 0, 0);
assert (nbytes == 0);
for (i = 0; i != count; i++) {
nbytes = nn_send (s, buf, sz, 0);
assert (nbytes == (int)sz);
}
free (buf);
rc = nn_close (s);
assert (rc == 0);
return 0;
}
nanomsg-0.8-beta/src/0000775000175000017500000000000012623652617015441 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/aio/0000775000175000017500000000000012623652617016211 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/aio/ctx.h0000664000175000017500000000372512623652600017157 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_CTX_INCLUDED
#define NN_CTX_INCLUDED
#include "../utils/mutex.h"
#include "../utils/queue.h"
#include "worker.h"
#include "pool.h"
#include "fsm.h"
/* AIO context for objects using AIO subsystem. */
typedef void (*nn_ctx_onleave) (struct nn_ctx *self);
struct nn_ctx {
struct nn_mutex sync;
struct nn_pool *pool;
struct nn_queue events;
struct nn_queue eventsto;
nn_ctx_onleave onleave;
};
void nn_ctx_init (struct nn_ctx *self, struct nn_pool *pool,
nn_ctx_onleave onleave);
void nn_ctx_term (struct nn_ctx *self);
void nn_ctx_enter (struct nn_ctx *self);
void nn_ctx_leave (struct nn_ctx *self);
struct nn_worker *nn_ctx_choose_worker (struct nn_ctx *self);
void nn_ctx_raise (struct nn_ctx *self, struct nn_fsm_event *event);
void nn_ctx_raiseto (struct nn_ctx *self, struct nn_fsm_event *event);
#endif
nanomsg-0.8-beta/src/aio/ctx.c0000664000175000017500000000660412623652600017151 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "ctx.h"
#include "../utils/err.h"
#include "../utils/cont.h"
#include "../utils/fast.h"
void nn_ctx_init (struct nn_ctx *self, struct nn_pool *pool,
nn_ctx_onleave onleave)
{
nn_mutex_init (&self->sync);
self->pool = pool;
nn_queue_init (&self->events);
nn_queue_init (&self->eventsto);
self->onleave = onleave;
}
void nn_ctx_term (struct nn_ctx *self)
{
nn_queue_term (&self->eventsto);
nn_queue_term (&self->events);
nn_mutex_term (&self->sync);
}
void nn_ctx_enter (struct nn_ctx *self)
{
nn_mutex_lock (&self->sync);
}
void nn_ctx_leave (struct nn_ctx *self)
{
struct nn_queue_item *item;
struct nn_fsm_event *event;
struct nn_queue eventsto;
/* Process any queued events before leaving the context. */
while (1) {
item = nn_queue_pop (&self->events);
event = nn_cont (item, struct nn_fsm_event, item);
if (!event)
break;
nn_fsm_event_process (event);
}
/* Notify the owner that we are leaving the context. */
if (nn_fast (self->onleave != NULL))
self->onleave (self);
/* Shortcut in the case there are no external events. */
if (nn_queue_empty (&self->eventsto)) {
nn_mutex_unlock (&self->sync);
return;
}
/* Make a copy of the queue of the external events so that it does not
get corrupted once we unlock the context. */
eventsto = self->eventsto;
nn_queue_init (&self->eventsto);
nn_mutex_unlock (&self->sync);
/* Process any queued external events. Before processing each event
lock the context it belongs to. */
while (1) {
item = nn_queue_pop (&eventsto);
event = nn_cont (item, struct nn_fsm_event, item);
if (!event)
break;
nn_ctx_enter (event->fsm->ctx);
nn_fsm_event_process (event);
nn_ctx_leave (event->fsm->ctx);
}
nn_queue_term (&eventsto);
}
struct nn_worker *nn_ctx_choose_worker (struct nn_ctx *self)
{
return nn_pool_choose_worker (self->pool);
}
void nn_ctx_raise (struct nn_ctx *self, struct nn_fsm_event *event)
{
nn_queue_push (&self->events, &event->item);
}
void nn_ctx_raiseto (struct nn_ctx *self, struct nn_fsm_event *event)
{
nn_queue_push (&self->eventsto, &event->item);
}
nanomsg-0.8-beta/src/aio/fsm.h0000664000175000017500000001004312623652600017135 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_FSM_INCLUDED
#define NN_FSM_INCLUDED
#include "../utils/queue.h"
/* Base class for state machines. */
struct nn_ctx;
struct nn_fsm;
struct nn_worker;
struct nn_fsm_event {
struct nn_fsm *fsm;
int src;
void *srcptr;
int type;
struct nn_queue_item item;
};
void nn_fsm_event_init (struct nn_fsm_event *self);
void nn_fsm_event_term (struct nn_fsm_event *self);
int nn_fsm_event_active (struct nn_fsm_event *self);
void nn_fsm_event_process (struct nn_fsm_event *self);
/* Special source for actions. It's negative not to clash with user-defined
sources. */
#define NN_FSM_ACTION -2
/* Actions generated by fsm object. The values are negative not to clash
with user-defined actions. */
#define NN_FSM_START -2
#define NN_FSM_STOP -3
/* Virtual function to be implemented by the derived class to handle the
incoming events. */
typedef void (*nn_fsm_fn) (struct nn_fsm *self, int src, int type,
void *srcptr);
struct nn_fsm_owner {
int src;
struct nn_fsm *fsm;
};
struct nn_fsm {
nn_fsm_fn fn;
nn_fsm_fn shutdown_fn;
int state;
int src;
void *srcptr;
struct nn_fsm *owner;
struct nn_ctx *ctx;
struct nn_fsm_event stopped;
};
void nn_fsm_init_root (struct nn_fsm *self, nn_fsm_fn fn,
nn_fsm_fn shutdown_fn, struct nn_ctx *ctx);
void nn_fsm_init (struct nn_fsm *self, nn_fsm_fn fn,
nn_fsm_fn shutdown_fn,
int src, void *srcptr, struct nn_fsm *owner);
void nn_fsm_term (struct nn_fsm *self);
int nn_fsm_isidle (struct nn_fsm *self);
void nn_fsm_start (struct nn_fsm *self);
void nn_fsm_stop (struct nn_fsm *self);
void nn_fsm_stopped (struct nn_fsm *self, int type);
void nn_fsm_stopped_noevent (struct nn_fsm *self);
/* Replaces current owner of the fsm by the owner speicified by 'owner'
parameter. The parameter will hold the old owner afrer the call. */
void nn_fsm_swap_owner (struct nn_fsm *self, struct nn_fsm_owner *owner);
struct nn_worker *nn_fsm_choose_worker (struct nn_fsm *self);
/* Using this function state machine can trigger an action on itself. */
void nn_fsm_action (struct nn_fsm *self, int type);
/* Send event from the state machine to its owner. */
void nn_fsm_raise (struct nn_fsm *self, struct nn_fsm_event *event, int type);
/* Send event to the specified state machine. It's caller's responsibility
to ensure that the destination state machine will still exist when the
event is delivered.
NOTE: This function is a hack to make inproc transport work in the most
efficient manner. Do not use it outside of inproc transport! */
void nn_fsm_raiseto (struct nn_fsm *self, struct nn_fsm *dst,
struct nn_fsm_event *event, int src, int type, void *srcptr);
/* This function is very lowlevel action feeding
Used in worker threads and timers, shouldn't be used by others
use nn_fsm_action/nn_fsm_raise/nn_fsm_raiseto instread*/
void nn_fsm_feed (struct nn_fsm *self, int src, int type, void *srcptr);
#endif
nanomsg-0.8-beta/src/aio/fsm.c0000664000175000017500000001167312623652600017142 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "fsm.h"
#include "ctx.h"
#include "../utils/err.h"
#include
#define NN_FSM_STATE_IDLE 1
#define NN_FSM_STATE_ACTIVE 2
#define NN_FSM_STATE_STOPPING 3
void nn_fsm_event_init (struct nn_fsm_event *self)
{
self->fsm = NULL;
self->src = -1;
self->srcptr = NULL;
self->type = -1;
nn_queue_item_init (&self->item);
}
void nn_fsm_event_term (struct nn_fsm_event *self)
{
nn_queue_item_term (&self->item);
}
int nn_fsm_event_active (struct nn_fsm_event *self)
{
return nn_queue_item_isinqueue (&self->item);
}
void nn_fsm_event_process (struct nn_fsm_event *self)
{
int src;
int type;
void *srcptr;
src = self->src;
type = self->type;
srcptr = self->srcptr;
self->src = -1;
self->type = -1;
self->srcptr = NULL;
nn_fsm_feed (self->fsm, src, type, srcptr);
}
void nn_fsm_feed (struct nn_fsm *self, int src, int type, void *srcptr)
{
if (nn_slow (self->state != NN_FSM_STATE_STOPPING)) {
self->fn (self, src, type, srcptr);
} else {
self->shutdown_fn (self, src, type, srcptr);
}
}
void nn_fsm_init_root (struct nn_fsm *self, nn_fsm_fn fn,
nn_fsm_fn shutdown_fn, struct nn_ctx *ctx)
{
self->fn = fn;
self->shutdown_fn = shutdown_fn;
self->state = NN_FSM_STATE_IDLE;
self->src = -1;
self->srcptr = NULL;
self->owner = NULL;
self->ctx = ctx;
nn_fsm_event_init (&self->stopped);
}
void nn_fsm_init (struct nn_fsm *self, nn_fsm_fn fn,
nn_fsm_fn shutdown_fn, int src, void *srcptr, struct nn_fsm *owner)
{
self->fn = fn;
self->shutdown_fn = shutdown_fn;
self->state = NN_FSM_STATE_IDLE;
self->src = src;
self->srcptr = srcptr;
self->owner = owner;
self->ctx = owner->ctx;
nn_fsm_event_init (&self->stopped);
}
void nn_fsm_term (struct nn_fsm *self)
{
nn_assert (nn_fsm_isidle (self));
nn_fsm_event_term (&self->stopped);
}
void nn_fsm_start (struct nn_fsm *self)
{
nn_assert (nn_fsm_isidle (self));
self->fn (self, NN_FSM_ACTION, NN_FSM_START, NULL);
self->state = NN_FSM_STATE_ACTIVE;
}
int nn_fsm_isidle (struct nn_fsm *self)
{
return self->state == NN_FSM_STATE_IDLE &&
!nn_fsm_event_active (&self->stopped) ? 1 : 0;
}
void nn_fsm_stop (struct nn_fsm *self)
{
/* If stopping of the state machine was already requested, do nothing. */
if (self->state != NN_FSM_STATE_ACTIVE)
return;
self->state = NN_FSM_STATE_STOPPING;
self->shutdown_fn (self, NN_FSM_ACTION, NN_FSM_STOP, NULL);
}
void nn_fsm_stopped (struct nn_fsm *self, int type)
{
nn_assert_state (self, NN_FSM_STATE_STOPPING);
nn_fsm_raise (self, &self->stopped, type);
self->state = NN_FSM_STATE_IDLE;
}
void nn_fsm_stopped_noevent (struct nn_fsm *self)
{
nn_assert_state (self, NN_FSM_STATE_STOPPING);
self->state = NN_FSM_STATE_IDLE;
}
void nn_fsm_swap_owner (struct nn_fsm *self, struct nn_fsm_owner *owner)
{
int oldsrc;
struct nn_fsm *oldowner;
oldsrc = self->src;
oldowner = self->owner;
self->src = owner->src;
self->owner = owner->fsm;
owner->src = oldsrc;
owner->fsm = oldowner;
}
struct nn_worker *nn_fsm_choose_worker (struct nn_fsm *self)
{
return nn_ctx_choose_worker (self->ctx);
}
void nn_fsm_action (struct nn_fsm *self, int type)
{
nn_assert (type > 0);
nn_fsm_feed (self, NN_FSM_ACTION, type, NULL);
}
void nn_fsm_raise (struct nn_fsm *self, struct nn_fsm_event *event, int type)
{
event->fsm = self->owner;
event->src = self->src;
event->srcptr = self->srcptr;
event->type = type;
nn_ctx_raise (self->ctx, event);
}
void nn_fsm_raiseto (struct nn_fsm *self, struct nn_fsm *dst,
struct nn_fsm_event *event, int src, int type, void *srcptr)
{
event->fsm = dst;
event->src = src;
event->srcptr = srcptr;
event->type = type;
nn_ctx_raiseto (self->ctx, event);
}
nanomsg-0.8-beta/src/aio/poller.h0000664000175000017500000000424112623652600017650 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_POLLER_INCLUDED
#define NN_POLLER_INCLUDED
#if !defined NN_HAVE_WINDOWS
#define NN_POLLER_IN 1
#define NN_POLLER_OUT 2
#define NN_POLLER_ERR 3
#if defined NN_USE_POLL
#include "poller_poll.h"
#elif defined NN_USE_EPOLL
#include "poller_epoll.h"
#elif defined NN_USE_KQUEUE
#include "poller_kqueue.h"
#endif
int nn_poller_init (struct nn_poller *self);
void nn_poller_term (struct nn_poller *self);
void nn_poller_add (struct nn_poller *self, int fd,
struct nn_poller_hndl *hndl);
void nn_poller_rm (struct nn_poller *self, struct nn_poller_hndl *hndl);
void nn_poller_set_in (struct nn_poller *self, struct nn_poller_hndl *hndl);
void nn_poller_reset_in (struct nn_poller *self, struct nn_poller_hndl *hndl);
void nn_poller_set_out (struct nn_poller *self, struct nn_poller_hndl *hndl);
void nn_poller_reset_out (struct nn_poller *self, struct nn_poller_hndl *hndl);
int nn_poller_wait (struct nn_poller *self, int timeout);
int nn_poller_event (struct nn_poller *self, int *event,
struct nn_poller_hndl **hndl);
#endif
#endif
nanomsg-0.8-beta/src/aio/poller.c0000664000175000017500000000254412623652600017647 0ustar00travistravis00000000000000/*
Copyright (c) 2012 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "poller.h"
#if !defined NN_HAVE_WINDOWS
#if defined NN_USE_POLL
#include "poller_poll.inc"
#elif defined NN_USE_EPOLL
#include "poller_epoll.inc"
#elif defined NN_USE_KQUEUE
#include "poller_kqueue.inc"
#endif
#endif
nanomsg-0.8-beta/src/aio/poller_epoll.h0000664000175000017500000000321312623652600021041 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include
#include
#include
#define NN_POLLER_HAVE_ASYNC_ADD 1
#define NN_POLLER_MAX_EVENTS 32
struct nn_poller_hndl {
int fd;
uint32_t events;
};
struct nn_poller {
/* Current pollset. */
int ep;
/* Number of events being processed at the moment. */
int nevents;
/* Index of the event being processed at the moment. */
int index;
/* Events being processed at the moment. */
struct epoll_event events [NN_POLLER_MAX_EVENTS];
};
nanomsg-0.8-beta/src/aio/poller_epoll.inc0000664000175000017500000001442512623652600021372 0ustar00travistravis00000000000000/*
Copyright (c) 2012 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../utils/fast.h"
#include "../utils/err.h"
#include "../utils/closefd.h"
#include
#include
#include
int nn_poller_init (struct nn_poller *self)
{
#ifndef EPOLL_CLOEXEC
int rc;
#endif
#ifdef EPOLL_CLOEXEC
self->ep = epoll_create1 (EPOLL_CLOEXEC);
#else
/* Size parameter is unused, we can safely set it to 1. */
self->ep = epoll_create (1);
rc = fcntl (self->ep, F_SETFD, FD_CLOEXEC);
errno_assert (rc != -1);
#endif
if (self->ep == -1) {
if (errno == ENFILE || errno == EMFILE)
return -EMFILE;
errno_assert (0);
}
self->nevents = 0;
self->index = 0;
return 0;
}
void nn_poller_term (struct nn_poller *self)
{
nn_closefd (self->ep);
}
void nn_poller_add (struct nn_poller *self, int fd,
struct nn_poller_hndl *hndl)
{
int rc;
struct epoll_event ev;
/* Initialise the handle and add the file descriptor to the pollset. */
hndl->fd = fd;
hndl->events = 0;
memset (&ev, 0, sizeof (ev));
ev.events = 0;
ev.data.ptr = (void*) hndl;
epoll_ctl (self->ep, EPOLL_CTL_ADD, fd, &ev);
}
void nn_poller_rm (struct nn_poller *self, struct nn_poller_hndl *hndl)
{
int i;
/* Remove the file descriptor from the pollset. */
epoll_ctl (self->ep, EPOLL_CTL_DEL, hndl->fd, NULL);
/* Invalidate any subsequent events on this file descriptor. */
for (i = self->index; i != self->nevents; ++i)
if (self->events [i].data.ptr == hndl)
self->events [i].events = 0;
}
void nn_poller_set_in (struct nn_poller *self, struct nn_poller_hndl *hndl)
{
struct epoll_event ev;
/* If already polling for IN, do nothing. */
if (nn_slow (hndl->events & EPOLLIN))
return;
/* Start polling for IN. */
hndl->events |= EPOLLIN;
memset (&ev, 0, sizeof (ev));
ev.events = hndl->events;
ev.data.ptr = (void*) hndl;
epoll_ctl (self->ep, EPOLL_CTL_MOD, hndl->fd, &ev);
}
void nn_poller_reset_in (struct nn_poller *self, struct nn_poller_hndl *hndl)
{
int i;
struct epoll_event ev;
/* If not polling for IN, do nothing. */
if (nn_slow (!(hndl->events & EPOLLIN)))
return;
/* Stop polling for IN. */
hndl->events &= ~EPOLLIN;
memset (&ev, 0, sizeof (ev));
ev.events = hndl->events;
ev.data.ptr = (void*) hndl;
epoll_ctl (self->ep, EPOLL_CTL_MOD, hndl->fd, &ev);
/* Invalidate any subsequent IN events on this file descriptor. */
for (i = self->index; i != self->nevents; ++i)
if (self->events [i].data.ptr == hndl)
self->events [i].events &= ~EPOLLIN;
}
void nn_poller_set_out (struct nn_poller *self, struct nn_poller_hndl *hndl)
{
struct epoll_event ev;
int fd = hndl->fd;
/* If already polling for OUT, do nothing. */
if (nn_slow (hndl->events & EPOLLOUT))
return;
/* Start polling for OUT. */
hndl->events |= EPOLLOUT;
memset (&ev, 0, sizeof (ev));
ev.events = hndl->events;
ev.data.ptr = (void*) hndl;
epoll_ctl (self->ep, EPOLL_CTL_MOD, fd, &ev);
}
void nn_poller_reset_out (struct nn_poller *self, struct nn_poller_hndl *hndl)
{
int i;
struct epoll_event ev;
/* If not polling for OUT, do nothing. */
if (nn_slow (!(hndl->events & EPOLLOUT)))
return;
/* Stop polling for OUT. */
hndl->events &= ~EPOLLOUT;
memset (&ev, 0, sizeof (ev));
ev.events = hndl->events;
ev.data.ptr = (void*) hndl;
epoll_ctl (self->ep, EPOLL_CTL_MOD, hndl->fd, &ev);
/* Invalidate any subsequent OUT events on this file descriptor. */
for (i = self->index; i != self->nevents; ++i)
if (self->events [i].data.ptr == hndl)
self->events [i].events &= ~EPOLLOUT;
}
int nn_poller_wait (struct nn_poller *self, int timeout)
{
int nevents;
/* Clear all existing events. */
self->nevents = 0;
self->index = 0;
/* Wait for new events. */
while (1) {
nevents = epoll_wait (self->ep, self->events,
NN_POLLER_MAX_EVENTS, timeout);
if (nn_slow (nevents == -1 && errno == EINTR))
continue;
break;
}
errno_assert (self->nevents != -1);
self->nevents = nevents;
return 0;
}
int nn_poller_event (struct nn_poller *self, int *event,
struct nn_poller_hndl **hndl)
{
/* Skip over empty events. */
while (self->index < self->nevents) {
if (self->events [self->index].events != 0)
break;
++self->index;
}
/* If there is no stored event, let the caller know. */
if (nn_slow (self->index >= self->nevents))
return -EAGAIN;
/* Return next event to the caller. Remove the event from the set. */
*hndl = (struct nn_poller_hndl*) self->events [self->index].data.ptr;
if (nn_fast (self->events [self->index].events & EPOLLIN)) {
*event = NN_POLLER_IN;
self->events [self->index].events &= ~EPOLLIN;
return 0;
}
else if (nn_fast (self->events [self->index].events & EPOLLOUT)) {
*event = NN_POLLER_OUT;
self->events [self->index].events &= ~EPOLLOUT;
return 0;
}
else {
*event = NN_POLLER_ERR;
++self->index;
return 0;
}
}
nanomsg-0.8-beta/src/aio/poller_kqueue.h0000664000175000017500000000320412623652600021225 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include
#include
#include
#define NN_POLLER_MAX_EVENTS 32
#define NN_POLLER_EVENT_IN 1
#define NN_POLLER_EVENT_OUT 2
struct nn_poller_hndl {
int fd;
int events;
};
struct nn_poller {
/* Current pollset. */
int kq;
/* Number of events being processed at the moment. */
int nevents;
/* Index of the event being processed at the moment. */
int index;
/* Cached events. */
struct kevent events [NN_POLLER_MAX_EVENTS];
};
nanomsg-0.8-beta/src/aio/poller_kqueue.inc0000664000175000017500000001434012623652600021552 0ustar00travistravis00000000000000/*
Copyright (c) 2012 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../utils/attr.h"
#include "../utils/fast.h"
#include "../utils/err.h"
#include "../utils/closefd.h"
#include
/* NetBSD has different definition of udata. */
#if defined NN_HAVE_NETBSD
#define nn_poller_udata intptr_t
#else
#define nn_poller_udata void*
#endif
int nn_poller_init (struct nn_poller *self)
{
self->kq = kqueue ();
if (self->kq == -1) {
if (errno == ENFILE || errno == EMFILE)
return -EMFILE;
errno_assert (0);
}
self->nevents = 0;
self->index = 0;
return 0;
}
void nn_poller_term (struct nn_poller *self)
{
nn_closefd (self->kq);
}
void nn_poller_add (NN_UNUSED struct nn_poller *self, int fd,
struct nn_poller_hndl *hndl)
{
/* Initialise the handle. */
hndl->fd = fd;
hndl->events = 0;
}
void nn_poller_rm (struct nn_poller *self, struct nn_poller_hndl *hndl)
{
int rc;
struct kevent ev;
int i;
if (hndl->events & NN_POLLER_EVENT_IN) {
EV_SET (&ev, hndl->fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
kevent (self->kq, &ev, 1, NULL, 0, NULL);
}
if (hndl->events & NN_POLLER_EVENT_OUT) {
EV_SET (&ev, hndl->fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
kevent (self->kq, &ev, 1, NULL, 0, NULL);
}
/* Invalidate any subsequent events on this file descriptor. */
for (i = self->index; i != self->nevents; ++i)
if (self->events [i].ident == (unsigned) hndl->fd)
self->events [i].udata = (nn_poller_udata) NULL;
}
void nn_poller_set_in (struct nn_poller *self, struct nn_poller_hndl *hndl)
{
int rc;
struct kevent ev;
int fd = hndl->fd;
if (!(hndl->events & NN_POLLER_EVENT_IN)) {
EV_SET (&ev, hndl->fd, EVFILT_READ, EV_ADD, 0, 0,
(nn_poller_udata) hndl);
rc = kevent (self->kq, &ev, 1, NULL, 0, NULL);
if (rc != -1)
hndl->events |= NN_POLLER_EVENT_IN;
}
}
void nn_poller_reset_in (struct nn_poller *self, struct nn_poller_hndl *hndl)
{
int rc;
struct kevent ev;
int i;
if (hndl->events & NN_POLLER_EVENT_IN) {
EV_SET (&ev, hndl->fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
rc = kevent (self->kq, &ev, 1, NULL, 0, NULL);
hndl->events &= ~NN_POLLER_EVENT_IN;
}
/* Invalidate any subsequent IN events on this file descriptor. */
for (i = self->index; i != self->nevents; ++i)
if (self->events [i].ident == (unsigned) hndl->fd &&
self->events [i].filter == EVFILT_READ)
self->events [i].udata = (nn_poller_udata) NULL;
}
void nn_poller_set_out (struct nn_poller *self, struct nn_poller_hndl *hndl)
{
int rc;
struct kevent ev;
int fd = hndl->fd;
if (!(hndl->events & NN_POLLER_EVENT_OUT)) {
EV_SET (&ev, fd, EVFILT_WRITE, EV_ADD, 0, 0, (nn_poller_udata) hndl);
rc = kevent (self->kq, &ev, 1, NULL, 0, NULL);
if (rc != -1)
hndl->events |= NN_POLLER_EVENT_OUT;
}
}
void nn_poller_reset_out (struct nn_poller *self, struct nn_poller_hndl *hndl)
{
int rc;
struct kevent ev;
int i;
int fd = hndl->fd;
if (hndl->events & NN_POLLER_EVENT_OUT) {
EV_SET (&ev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
rc = kevent (self->kq, &ev, 1, NULL, 0, NULL);
if (rc != -1) {
hndl->events &= ~NN_POLLER_EVENT_OUT;
}
}
/* Invalidate any subsequent OUT events on this file descriptor. */
for (i = self->index; i != self->nevents; ++i)
if (self->events [i].ident == (unsigned) hndl->fd &&
self->events [i].filter == EVFILT_WRITE)
self->events [i].udata = (nn_poller_udata) NULL;
}
int nn_poller_wait (struct nn_poller *self, int timeout)
{
struct timespec ts;
int nevents;
/* Clear all existing events. */
self->nevents = 0;
self->index = 0;
/* Wait for new events. */
#if defined NN_IGNORE_EINTR
again:
#endif
ts.tv_sec = timeout / 1000;
ts.tv_nsec = (timeout % 1000) * 1000000;
nevents = kevent (self->kq, NULL, 0, &self->events [0],
NN_POLLER_MAX_EVENTS, timeout >= 0 ? &ts : NULL);
if (nevents == -1 && errno == EINTR)
#if defined NN_IGNORE_EINTR
goto again;
#else
return -EINTR;
#endif
errno_assert (nevents != -1);
self->nevents = nevents;
return 0;
}
int nn_poller_event (struct nn_poller *self, int *event,
struct nn_poller_hndl **hndl)
{
/* Skip over empty events. */
while (self->index < self->nevents) {
if (self->events [self->index].udata)
break;
++self->index;
}
/* If there is no stored event, let the caller know. */
if (nn_slow (self->index >= self->nevents))
return -EAGAIN;
/* Return next event to the caller. Remove the event from the set. */
*hndl = (struct nn_poller_hndl*) self->events [self->index].udata;
if (self->events [self->index].flags & EV_EOF)
*event = NN_POLLER_ERR;
else if (self->events [self->index].filter == EVFILT_WRITE)
*event = NN_POLLER_OUT;
else if (self->events [self->index].filter == EVFILT_READ)
*event = NN_POLLER_IN;
else
nn_assert (0);
++self->index;
return 0;
}
nanomsg-0.8-beta/src/aio/poller_poll.h0000664000175000017500000000366312623652600020705 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include
#define NN_POLLER_HAVE_ASYNC_ADD 0
struct nn_poller_hndl {
int index;
};
struct nn_poller {
/* Actual number of elements in the pollset. */
int size;
/* Index of the event being processed at the moment. */
int index;
/* Number of allocated elements in the pollset. */
int capacity;
/* The pollset. */
struct pollfd *pollset;
/* List of handles associated with elements in the pollset. Either points
to the handle associated with the file descriptor (hndl) or is part
of the list of removed pollitems (removed). */
struct nn_hndls_item {
struct nn_poller_hndl *hndl;
int prev;
int next;
} *hndls;
/* List of removed pollitems, linked by indices. -1 means empty list. */
int removed;
};
nanomsg-0.8-beta/src/aio/poller_poll.inc0000664000175000017500000001434112623652600021222 0ustar00travistravis00000000000000/*
Copyright (c) 2012 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../utils/alloc.h"
#include "../utils/err.h"
#define NN_POLLER_GRANULARITY 16
int nn_poller_init (struct nn_poller *self)
{
self->size = 0;
self->index = 0;
self->capacity = NN_POLLER_GRANULARITY;
self->pollset =
nn_alloc (sizeof (struct pollfd) * NN_POLLER_GRANULARITY,
"pollset");
alloc_assert (self->pollset);
self->hndls =
nn_alloc (sizeof (struct nn_hndls_item) * NN_POLLER_GRANULARITY,
"hndlset");
alloc_assert (self->hndls);
self->removed = -1;
return 0;
}
void nn_poller_term (struct nn_poller *self)
{
nn_free (self->pollset);
nn_free (self->hndls);
}
void nn_poller_add (struct nn_poller *self, int fd,
struct nn_poller_hndl *hndl)
{
int rc;
/* If the capacity is too low to accommodate the next item, resize it. */
if (nn_slow (self->size >= self->capacity)) {
self->capacity *= 2;
self->pollset = nn_realloc (self->pollset,
sizeof (struct pollfd) * self->capacity);
alloc_assert (self->pollset);
self->hndls = nn_realloc (self->hndls,
sizeof (struct nn_hndls_item) * self->capacity);
alloc_assert (self->hndls);
}
/* Add the fd to the pollset. */
self->pollset [self->size].fd = fd;
self->pollset [self->size].events = 0;
self->pollset [self->size].revents = 0;
hndl->index = self->size;
self->hndls [self->size].hndl = hndl;
++self->size;
}
void nn_poller_rm (struct nn_poller *self, struct nn_poller_hndl *hndl)
{
/* No more events will be reported on this fd. */
self->pollset [hndl->index].revents = 0;
/* Add the fd into the list of removed fds. */
if (self->removed != -1)
self->hndls [self->removed].prev = hndl->index;
self->hndls [hndl->index].hndl = NULL;
self->hndls [hndl->index].prev = -1;
self->hndls [hndl->index].next = self->removed;
self->removed = hndl->index;
}
void nn_poller_set_in (struct nn_poller *self, struct nn_poller_hndl *hndl)
{
self->pollset [hndl->index].events |= POLLIN;
}
void nn_poller_reset_in (struct nn_poller *self, struct nn_poller_hndl *hndl)
{
self->pollset [hndl->index].events &= ~POLLIN;
self->pollset [hndl->index].revents &= ~POLLIN;
}
void nn_poller_set_out (struct nn_poller *self, struct nn_poller_hndl *hndl)
{
self->pollset [hndl->index].events |= POLLOUT;
}
void nn_poller_reset_out (struct nn_poller *self, struct nn_poller_hndl *hndl)
{
self->pollset [hndl->index].events &= ~POLLOUT;
self->pollset [hndl->index].revents &= ~POLLOUT;
}
int nn_poller_wait (struct nn_poller *self, int timeout)
{
int rc;
int i;
/* First, get rid of removed fds. */
while (self->removed != -1) {
/* Remove the fd from the list of removed fds. */
i = self->removed;
self->removed = self->hndls [i].next;
/* Replace the removed fd by the one at the end of the pollset. */
--self->size;
if (i != self->size) {
self->pollset [i] = self->pollset [self->size];
if (self->hndls [i].next != -1)
self->hndls [self->hndls [i].next].prev = -1;
self->hndls [i] = self->hndls [self->size];
if (self->hndls [i].hndl)
self->hndls [i].hndl->index = i;
}
/* The fd from the end of the pollset may have been on removed fds
list itself. If so, adjust the removed list. */
if (nn_slow (!self->hndls [i].hndl)) {
if (self->hndls [i].prev != -1)
self->hndls [self->hndls [i].prev].next = i;
if (self->hndls [i].next != -1)
self->hndls [self->hndls [i].next].prev = i;
if (self->removed == self->size)
self->removed = i;
}
}
self->index = 0;
/* Wait for new events. */
#if defined NN_IGNORE_EINTR
again:
#endif
rc = poll (self->pollset, self->size, timeout);
if (nn_slow (rc < 0 && errno == EINTR))
#if defined NN_IGNORE_EINTR
goto again;
#else
return -EINTR;
#endif
errno_assert (rc >= 0);
return 0;
}
int nn_poller_event (struct nn_poller *self, int *event,
struct nn_poller_hndl **hndl)
{
int rc;
/* Skip over empty events. This will also skip over removed fds as they
have their revents nullified. */
while (self->index < self->size) {
if (self->pollset [self->index].revents != 0)
break;
++self->index;
}
/* If there is no available event, let the caller know. */
if (nn_slow (self->index >= self->size))
return -EAGAIN;
/* Return next event to the caller. Remove the event from revents. */
*hndl = self->hndls [self->index].hndl;
if (nn_fast (self->pollset [self->index].revents & POLLIN)) {
*event = NN_POLLER_IN;
self->pollset [self->index].revents &= ~POLLIN;
return 0;
}
else if (nn_fast (self->pollset [self->index].revents & POLLOUT)) {
*event = NN_POLLER_OUT;
self->pollset [self->index].revents &= ~POLLOUT;
return 0;
}
else {
*event = NN_POLLER_ERR;
++self->index;
return 0;
}
}
nanomsg-0.8-beta/src/aio/pool.h0000664000175000017500000000266112623652600017330 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_POOL_INCLUDED
#define NN_POOL_INCLUDED
#include "worker.h"
/* Worker thread pool. */
struct nn_pool {
struct nn_worker worker;
};
int nn_pool_init (struct nn_pool *self);
void nn_pool_term (struct nn_pool *self);
struct nn_worker *nn_pool_choose_worker (struct nn_pool *self);
#endif
nanomsg-0.8-beta/src/aio/pool.c0000664000175000017500000000301112623652600017311 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "pool.h"
/* TODO: The dummy implementation of a thread pool. As for now there's only
one worker thread created. */
int nn_pool_init (struct nn_pool *self)
{
return nn_worker_init (&self->worker);
}
void nn_pool_term (struct nn_pool *self)
{
nn_worker_term (&self->worker);
}
struct nn_worker *nn_pool_choose_worker (struct nn_pool *self)
{
return &self->worker;
}
nanomsg-0.8-beta/src/aio/timer.h0000664000175000017500000000343312623652600017475 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_TIMER_INCLUDED
#define NN_TIMER_INCLUDED
#include "fsm.h"
#include "worker.h"
#define NN_TIMER_TIMEOUT 1
#define NN_TIMER_STOPPED 2
struct nn_timer {
struct nn_fsm fsm;
int state;
struct nn_worker_task start_task;
struct nn_worker_task stop_task;
struct nn_worker_timer wtimer;
struct nn_fsm_event done;
struct nn_worker *worker;
int timeout;
};
void nn_timer_init (struct nn_timer *self, int src, struct nn_fsm *owner);
void nn_timer_term (struct nn_timer *self);
int nn_timer_isidle (struct nn_timer *self);
void nn_timer_start (struct nn_timer *self, int timeout);
void nn_timer_stop (struct nn_timer *self);
#endif
nanomsg-0.8-beta/src/aio/timer.c0000664000175000017500000001406412623652600017472 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "timer.h"
#include "../utils/cont.h"
#include "../utils/fast.h"
#include "../utils/err.h"
#include "../utils/attr.h"
/* Timer state reflects the state as seen by the user thread. It says nothing
about the state of affairs in the worker thread. */
#define NN_TIMER_STATE_IDLE 1
#define NN_TIMER_STATE_ACTIVE 2
#define NN_TIMER_STATE_STOPPING 3
#define NN_TIMER_SRC_START_TASK 1
#define NN_TIMER_SRC_STOP_TASK 2
/* Private functions. */
static void nn_timer_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_timer_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
void nn_timer_init (struct nn_timer *self, int src, struct nn_fsm *owner)
{
nn_fsm_init (&self->fsm, nn_timer_handler, nn_timer_shutdown,
src, self, owner);
self->state = NN_TIMER_STATE_IDLE;
nn_worker_task_init (&self->start_task, NN_TIMER_SRC_START_TASK,
&self->fsm);
nn_worker_task_init (&self->stop_task, NN_TIMER_SRC_STOP_TASK, &self->fsm);
nn_worker_timer_init (&self->wtimer, &self->fsm);
nn_fsm_event_init (&self->done);
self->worker = nn_fsm_choose_worker (&self->fsm);
self->timeout = -1;
}
void nn_timer_term (struct nn_timer *self)
{
nn_assert_state (self, NN_TIMER_STATE_IDLE);
nn_fsm_event_term (&self->done);
nn_worker_timer_term (&self->wtimer);
nn_worker_task_term (&self->stop_task);
nn_worker_task_term (&self->start_task);
nn_fsm_term (&self->fsm);
}
int nn_timer_isidle (struct nn_timer *self)
{
return nn_fsm_isidle (&self->fsm);
}
void nn_timer_start (struct nn_timer *self, int timeout)
{
/* Negative timeout make no sense. */
nn_assert (timeout >= 0);
self->timeout = timeout;
nn_fsm_start (&self->fsm);
}
void nn_timer_stop (struct nn_timer *self)
{
nn_fsm_stop (&self->fsm);
}
static void nn_timer_shutdown (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_timer *timer;
timer = nn_cont (self, struct nn_timer, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
timer->state = NN_TIMER_STATE_STOPPING;
nn_worker_execute (timer->worker, &timer->stop_task);
return;
}
if (nn_slow (timer->state == NN_TIMER_STATE_STOPPING)) {
if (src != NN_TIMER_SRC_STOP_TASK)
return;
nn_assert (type == NN_WORKER_TASK_EXECUTE);
nn_worker_rm_timer (timer->worker, &timer->wtimer);
timer->state = NN_TIMER_STATE_IDLE;
nn_fsm_stopped (&timer->fsm, NN_TIMER_STOPPED);
return;
}
nn_fsm_bad_state(timer->state, src, type);
}
static void nn_timer_handler (struct nn_fsm *self, int src, int type,
void *srcptr)
{
struct nn_timer *timer;
timer = nn_cont (self, struct nn_timer, fsm);
switch (timer->state) {
/******************************************************************************/
/* IDLE state. */
/******************************************************************************/
case NN_TIMER_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
/* Send start event to the worker thread. */
timer->state = NN_TIMER_STATE_ACTIVE;
nn_worker_execute (timer->worker, &timer->start_task);
return;
default:
nn_fsm_bad_action (timer->state, src, type);
}
default:
nn_fsm_bad_source (timer->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/******************************************************************************/
case NN_TIMER_STATE_ACTIVE:
if (src == NN_TIMER_SRC_START_TASK) {
nn_assert (type == NN_WORKER_TASK_EXECUTE);
nn_assert (timer->timeout >= 0);
nn_worker_add_timer (timer->worker, timer->timeout,
&timer->wtimer);
timer->timeout = -1;
return;
}
if (srcptr == &timer->wtimer) {
switch (type) {
case NN_WORKER_TIMER_TIMEOUT:
/* Notify the user about the timeout. */
nn_assert (timer->timeout == -1);
nn_fsm_raise (&timer->fsm, &timer->done, NN_TIMER_TIMEOUT);
return;
default:
nn_fsm_bad_action (timer->state, src, type);
}
}
nn_fsm_bad_source (timer->state, src, type);
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (timer->state, src, type);
}
}
nanomsg-0.8-beta/src/aio/timerset.h0000664000175000017500000000415412623652600020212 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_TIMERSET_INCLUDED
#define NN_TIMERSET_INCLUDED
#include "../utils/clock.h"
#include "../utils/list.h"
/* This class stores a list of timeouts and reports the next one to expire
along with the time till it happens. */
struct nn_timerset_hndl {
struct nn_list_item list;
uint64_t timeout;
};
struct nn_timerset {
struct nn_clock clock;
struct nn_list timeouts;
};
void nn_timerset_init (struct nn_timerset *self);
void nn_timerset_term (struct nn_timerset *self);
int nn_timerset_add (struct nn_timerset *self, int timeout,
struct nn_timerset_hndl *hndl);
int nn_timerset_rm (struct nn_timerset *self, struct nn_timerset_hndl *hndl);
int nn_timerset_timeout (struct nn_timerset *self);
int nn_timerset_event (struct nn_timerset *self, struct nn_timerset_hndl **hndl);
void nn_timerset_hndl_init (struct nn_timerset_hndl *self);
void nn_timerset_hndl_term (struct nn_timerset_hndl *self);
int nn_timerset_hndl_isactive (struct nn_timerset_hndl *self);
#endif
nanomsg-0.8-beta/src/aio/timerset.c0000664000175000017500000001022712623652600020203 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "timerset.h"
#include "../utils/fast.h"
#include "../utils/cont.h"
#include "../utils/err.h"
void nn_timerset_init (struct nn_timerset *self)
{
nn_clock_init (&self->clock);
nn_list_init (&self->timeouts);
}
void nn_timerset_term (struct nn_timerset *self)
{
nn_list_term (&self->timeouts);
nn_clock_term (&self->clock);
}
int nn_timerset_add (struct nn_timerset *self, int timeout,
struct nn_timerset_hndl *hndl)
{
struct nn_list_item *it;
struct nn_timerset_hndl *ith;
int first;
/* Compute the instant when the timeout will be due. */
hndl->timeout = nn_clock_now (&self->clock) + timeout;
/* Insert it into the ordered list of timeouts. */
for (it = nn_list_begin (&self->timeouts);
it != nn_list_end (&self->timeouts);
it = nn_list_next (&self->timeouts, it)) {
ith = nn_cont (it, struct nn_timerset_hndl, list);
if (hndl->timeout < ith->timeout)
break;
}
/* If the new timeout happens to be the first one to expire, let the user
know that the current waiting interval has to be changed. */
first = nn_list_begin (&self->timeouts) == it ? 1 : 0;
nn_list_insert (&self->timeouts, &hndl->list, it);
return first;
}
int nn_timerset_rm (struct nn_timerset *self, struct nn_timerset_hndl *hndl)
{
int first;
/* Ignore if handle is not in the timeouts list. */
if (!nn_list_item_isinlist (&hndl->list))
return 0;
/* If it was the first timeout that was removed, the actual waiting time
may have changed. We'll thus return 1 to let the user know. */
first = nn_list_begin (&self->timeouts) == &hndl->list ? 1 : 0;
nn_list_erase (&self->timeouts, &hndl->list);
return first;
}
int nn_timerset_timeout (struct nn_timerset *self)
{
int timeout;
if (nn_fast (nn_list_empty (&self->timeouts)))
return -1;
timeout = (int) (nn_cont (nn_list_begin (&self->timeouts),
struct nn_timerset_hndl, list)->timeout - nn_clock_now (&self->clock));
return timeout < 0 ? 0 : timeout;
}
int nn_timerset_event (struct nn_timerset *self, struct nn_timerset_hndl **hndl)
{
struct nn_timerset_hndl *first;
/* If there's no timeout, there's no event to report. */
if (nn_fast (nn_list_empty (&self->timeouts)))
return -EAGAIN;
/* If no timeout have expired yet, there's no event to return. */
first = nn_cont (nn_list_begin (&self->timeouts),
struct nn_timerset_hndl, list);
if (first->timeout > nn_clock_now (&self->clock))
return -EAGAIN;
/* Return the first timeout and remove it from the list of active
timeouts. */
nn_list_erase (&self->timeouts, &first->list);
*hndl = first;
return 0;
}
void nn_timerset_hndl_init (struct nn_timerset_hndl *self)
{
nn_list_item_init (&self->list);
}
void nn_timerset_hndl_term (struct nn_timerset_hndl *self)
{
nn_list_item_term (&self->list);
}
int nn_timerset_hndl_isactive (struct nn_timerset_hndl *self)
{
return nn_list_item_isinlist (&self->list);
}
nanomsg-0.8-beta/src/aio/usock.h0000664000175000017500000000716112623652600017503 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_USOCK_INCLUDED
#define NN_USOCK_INCLUDED
/* Import the definition of nn_iovec. */
#include "../nn.h"
/* OS-level sockets. */
/* Event types generated by nn_usock. */
#define NN_USOCK_CONNECTED 1
#define NN_USOCK_ACCEPTED 2
#define NN_USOCK_SENT 3
#define NN_USOCK_RECEIVED 4
#define NN_USOCK_ERROR 5
#define NN_USOCK_ACCEPT_ERROR 6
#define NN_USOCK_STOPPED 7
#define NN_USOCK_SHUTDOWN 8
/* Maximum number of iovecs that can be passed to nn_usock_send function. */
#define NN_USOCK_MAX_IOVCNT 3
/* Size of the buffer used for batch-reads of inbound data. To keep the
performance optimal make sure that this value is larger than network MTU. */
#define NN_USOCK_BATCH_SIZE 2048
#if defined NN_HAVE_WINDOWS
#include "usock_win.h"
#else
#include "usock_posix.h"
#endif
void nn_usock_init (struct nn_usock *self, int src, struct nn_fsm *owner);
void nn_usock_term (struct nn_usock *self);
int nn_usock_isidle (struct nn_usock *self);
int nn_usock_start (struct nn_usock *self,
int domain, int type, int protocol);
void nn_usock_start_fd (struct nn_usock *self, int fd);
void nn_usock_stop (struct nn_usock *self);
void nn_usock_swap_owner (struct nn_usock *self, struct nn_fsm_owner *owner);
int nn_usock_setsockopt (struct nn_usock *self, int level, int optname,
const void *optval, size_t optlen);
int nn_usock_bind (struct nn_usock *self, const struct sockaddr *addr,
size_t addrlen);
int nn_usock_listen (struct nn_usock *self, int backlog);
/* Accept a new connection from a listener. When done, NN_USOCK_ACCEPTED
event will be delivered to the accepted socket. To cancel the operation,
stop the socket being accepted. Listening socket should not be stopped
while accepting a new socket is underway. */
void nn_usock_accept (struct nn_usock *self, struct nn_usock *listener);
/* When all the tuning is done on the accepted socket, call this function
to activate standard data transfer phase. */
void nn_usock_activate (struct nn_usock *self);
/* Start connecting. Prior to this call the socket has to be bound to a local
address. When connecting is done NN_USOCK_CONNECTED event will be reaised.
If connecting fails NN_USOCK_ERROR event will be raised. */
void nn_usock_connect (struct nn_usock *self, const struct sockaddr *addr,
size_t addrlen);
void nn_usock_send (struct nn_usock *self, const struct nn_iovec *iov,
int iovcnt);
void nn_usock_recv (struct nn_usock *self, void *buf, size_t len, int *fd);
int nn_usock_geterrno (struct nn_usock *self);
#endif
nanomsg-0.8-beta/src/aio/usock.c0000664000175000017500000000247412623652600017500 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "usock.h"
#if defined NN_HAVE_WINDOWS
#include "usock_win.inc"
#else
#include "usock_posix.inc"
#endif
int nn_usock_geterrno (struct nn_usock *self) {
return self->errnum;
}
nanomsg-0.8-beta/src/aio/usock_posix.h0000664000175000017500000000614512623652600020726 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "fsm.h"
#include "worker.h"
#include
#include
#include
struct nn_usock {
/* State machine base class. */
struct nn_fsm fsm;
int state;
/* The worker thread the usock is associated with. */
struct nn_worker *worker;
/* The underlying OS socket and handle that represents it in the poller. */
int s;
struct nn_worker_fd wfd;
/* Members related to receiving data. */
struct {
/* The buffer being filled in at the moment. */
uint8_t *buf;
size_t len;
/* Buffer for batch-reading inbound data. */
uint8_t *batch;
/* Size of the batch buffer. */
size_t batch_len;
/* Current position in the batch buffer. The data preceding this
position were already received by the user. The data that follow
will be received in the future. */
size_t batch_pos;
/* File descriptor received via SCM_RIGHTS, if any. */
int *pfd;
} in;
/* Members related to sending data. */
struct {
/* msghdr being sent at the moment. */
struct msghdr hdr;
/* List of buffers being sent at the moment. Referenced from 'hdr'. */
struct iovec iov [NN_USOCK_MAX_IOVCNT];
} out;
/* Asynchronous tasks for the worker. */
struct nn_worker_task task_connecting;
struct nn_worker_task task_connected;
struct nn_worker_task task_accept;
struct nn_worker_task task_send;
struct nn_worker_task task_recv;
struct nn_worker_task task_stop;
/* Events raised by the usock. */
struct nn_fsm_event event_established;
struct nn_fsm_event event_sent;
struct nn_fsm_event event_received;
struct nn_fsm_event event_error;
/* In ACCEPTING state points to the socket being accepted.
In BEING_ACCEPTED state points to the listener socket. */
struct nn_usock *asock;
/* Errno remembered in NN_USOCK_ERROR state */
int errnum;
};
nanomsg-0.8-beta/src/aio/usock_posix.inc0000664000175000017500000012106412623652600021246 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Copyright 2015 Garrett D'Amore
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../utils/alloc.h"
#include "../utils/closefd.h"
#include "../utils/cont.h"
#include "../utils/fast.h"
#include "../utils/err.h"
#include "../utils/attr.h"
#include
#include
#include
#include
#define NN_USOCK_STATE_IDLE 1
#define NN_USOCK_STATE_STARTING 2
#define NN_USOCK_STATE_BEING_ACCEPTED 3
#define NN_USOCK_STATE_ACCEPTED 4
#define NN_USOCK_STATE_CONNECTING 5
#define NN_USOCK_STATE_ACTIVE 6
#define NN_USOCK_STATE_REMOVING_FD 7
#define NN_USOCK_STATE_DONE 8
#define NN_USOCK_STATE_LISTENING 9
#define NN_USOCK_STATE_ACCEPTING 10
#define NN_USOCK_STATE_CANCELLING 11
#define NN_USOCK_STATE_STOPPING 12
#define NN_USOCK_STATE_STOPPING_ACCEPT 13
#define NN_USOCK_STATE_ACCEPTING_ERROR 14
#define NN_USOCK_ACTION_ACCEPT 1
#define NN_USOCK_ACTION_BEING_ACCEPTED 2
#define NN_USOCK_ACTION_CANCEL 3
#define NN_USOCK_ACTION_LISTEN 4
#define NN_USOCK_ACTION_CONNECT 5
#define NN_USOCK_ACTION_ACTIVATE 6
#define NN_USOCK_ACTION_DONE 7
#define NN_USOCK_ACTION_ERROR 8
#define NN_USOCK_ACTION_STARTED 9
#define NN_USOCK_SRC_FD 1
#define NN_USOCK_SRC_TASK_CONNECTING 2
#define NN_USOCK_SRC_TASK_CONNECTED 3
#define NN_USOCK_SRC_TASK_ACCEPT 4
#define NN_USOCK_SRC_TASK_SEND 5
#define NN_USOCK_SRC_TASK_RECV 6
#define NN_USOCK_SRC_TASK_STOP 7
/* Private functions. */
static void nn_usock_init_from_fd (struct nn_usock *self, int s);
static int nn_usock_send_raw (struct nn_usock *self, struct msghdr *hdr);
static int nn_usock_recv_raw (struct nn_usock *self, void *buf, size_t *len);
static int nn_usock_geterr (struct nn_usock *self);
static void nn_usock_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_usock_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
void nn_usock_init (struct nn_usock *self, int src, struct nn_fsm *owner)
{
/* Initalise the state machine. */
nn_fsm_init (&self->fsm, nn_usock_handler, nn_usock_shutdown,
src, self, owner);
self->state = NN_USOCK_STATE_IDLE;
/* Choose a worker thread to handle this socket. */
self->worker = nn_fsm_choose_worker (&self->fsm);
/* Actual file descriptor will be generated during 'start' step. */
self->s = -1;
self->errnum = 0;
self->in.buf = NULL;
self->in.len = 0;
self->in.batch = NULL;
self->in.batch_len = 0;
self->in.batch_pos = 0;
self->in.pfd = NULL;
memset (&self->out.hdr, 0, sizeof (struct msghdr));
/* Initialise tasks for the worker thread. */
nn_worker_fd_init (&self->wfd, NN_USOCK_SRC_FD, &self->fsm);
nn_worker_task_init (&self->task_connecting, NN_USOCK_SRC_TASK_CONNECTING,
&self->fsm);
nn_worker_task_init (&self->task_connected, NN_USOCK_SRC_TASK_CONNECTED,
&self->fsm);
nn_worker_task_init (&self->task_accept, NN_USOCK_SRC_TASK_ACCEPT,
&self->fsm);
nn_worker_task_init (&self->task_send, NN_USOCK_SRC_TASK_SEND, &self->fsm);
nn_worker_task_init (&self->task_recv, NN_USOCK_SRC_TASK_RECV, &self->fsm);
nn_worker_task_init (&self->task_stop, NN_USOCK_SRC_TASK_STOP, &self->fsm);
/* Intialise events raised by usock. */
nn_fsm_event_init (&self->event_established);
nn_fsm_event_init (&self->event_sent);
nn_fsm_event_init (&self->event_received);
nn_fsm_event_init (&self->event_error);
/* accepting is not going on at the moment. */
self->asock = NULL;
}
void nn_usock_term (struct nn_usock *self)
{
nn_assert_state (self, NN_USOCK_STATE_IDLE);
if (self->in.batch)
nn_free (self->in.batch);
nn_fsm_event_term (&self->event_error);
nn_fsm_event_term (&self->event_received);
nn_fsm_event_term (&self->event_sent);
nn_fsm_event_term (&self->event_established);
nn_worker_cancel (self->worker, &self->task_recv);
nn_worker_task_term (&self->task_stop);
nn_worker_task_term (&self->task_recv);
nn_worker_task_term (&self->task_send);
nn_worker_task_term (&self->task_accept);
nn_worker_task_term (&self->task_connected);
nn_worker_task_term (&self->task_connecting);
nn_worker_fd_term (&self->wfd);
nn_fsm_term (&self->fsm);
}
int nn_usock_isidle (struct nn_usock *self)
{
return nn_fsm_isidle (&self->fsm);
}
int nn_usock_start (struct nn_usock *self, int domain, int type, int protocol)
{
int s;
/* If the operating system allows to directly open the socket with CLOEXEC
flag, do so. That way there are no race conditions. */
#ifdef SOCK_CLOEXEC
type |= SOCK_CLOEXEC;
#endif
/* Open the underlying socket. */
s = socket (domain, type, protocol);
if (nn_slow (s < 0))
return -errno;
nn_usock_init_from_fd (self, s);
/* Start the state machine. */
nn_fsm_start (&self->fsm);
return 0;
}
void nn_usock_start_fd (struct nn_usock *self, int fd)
{
nn_usock_init_from_fd (self, fd);
nn_fsm_start (&self->fsm);
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_STARTED);
}
static void nn_usock_init_from_fd (struct nn_usock *self, int s)
{
int rc;
int opt;
nn_assert (self->state == NN_USOCK_STATE_IDLE ||
NN_USOCK_STATE_BEING_ACCEPTED);
/* Store the file descriptor. */
nn_assert (self->s == -1);
self->s = s;
/* Setting FD_CLOEXEC option immediately after socket creation is the
second best option after using SOCK_CLOEXEC. There is a race condition
here (if process is forked between socket creation and setting
the option) but the problem is pretty unlikely to happen. */
#if defined FD_CLOEXEC
rc = fcntl (self->s, F_SETFD, FD_CLOEXEC);
#if defined NN_HAVE_OSX
errno_assert (rc != -1 || errno == EINVAL);
#else
errno_assert (rc != -1);
#endif
#endif
/* If applicable, prevent SIGPIPE signal when writing to the connection
already closed by the peer. */
#ifdef SO_NOSIGPIPE
opt = 1;
rc = setsockopt (self->s, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof (opt));
#if defined NN_HAVE_OSX
errno_assert (rc == 0 || errno == EINVAL);
#else
errno_assert (rc == 0);
#endif
#endif
/* Switch the socket to the non-blocking mode. All underlying sockets
are always used in the callbackhronous mode. */
opt = fcntl (self->s, F_GETFL, 0);
if (opt == -1)
opt = 0;
if (!(opt & O_NONBLOCK)) {
rc = fcntl (self->s, F_SETFL, opt | O_NONBLOCK);
#if defined NN_HAVE_OSX
errno_assert (rc != -1 || errno == EINVAL);
#else
errno_assert (rc != -1);
#endif
}
}
void nn_usock_stop (struct nn_usock *self)
{
nn_fsm_stop (&self->fsm);
}
void nn_usock_async_stop (struct nn_usock *self)
{
nn_worker_execute (self->worker, &self->task_stop);
nn_fsm_raise (&self->fsm, &self->event_error, NN_USOCK_SHUTDOWN);
}
void nn_usock_swap_owner (struct nn_usock *self, struct nn_fsm_owner *owner)
{
nn_fsm_swap_owner (&self->fsm, owner);
}
int nn_usock_setsockopt (struct nn_usock *self, int level, int optname,
const void *optval, size_t optlen)
{
int rc;
/* The socket can be modified only before it's active. */
nn_assert (self->state == NN_USOCK_STATE_STARTING ||
self->state == NN_USOCK_STATE_ACCEPTED);
/* EINVAL errors are ignored on OSX platform. The reason for that is buggy
OSX behaviour where setsockopt returns EINVAL if the peer have already
disconnected. Thus, nn_usock_setsockopt() can succeed on OSX even though
the option value was invalid, but the peer have already closed the
connection. This behaviour should be relatively harmless. */
rc = setsockopt (self->s, level, optname, optval, (socklen_t) optlen);
#if defined NN_HAVE_OSX
if (nn_slow (rc != 0 && errno != EINVAL))
return -errno;
#else
if (nn_slow (rc != 0))
return -errno;
#endif
return 0;
}
int nn_usock_bind (struct nn_usock *self, const struct sockaddr *addr,
size_t addrlen)
{
int rc;
int opt;
/* The socket can be bound only before it's connected. */
nn_assert_state (self, NN_USOCK_STATE_STARTING);
/* Allow re-using the address. */
opt = 1;
rc = setsockopt (self->s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt));
errno_assert (rc == 0);
rc = bind (self->s, addr, (socklen_t) addrlen);
if (nn_slow (rc != 0))
return -errno;
return 0;
}
int nn_usock_listen (struct nn_usock *self, int backlog)
{
int rc;
/* You can start listening only before the socket is connected. */
nn_assert_state (self, NN_USOCK_STATE_STARTING);
/* Start listening for incoming connections. */
rc = listen (self->s, backlog);
if (nn_slow (rc != 0))
return -errno;
/* Notify the state machine. */
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_LISTEN);
return 0;
}
void nn_usock_accept (struct nn_usock *self, struct nn_usock *listener)
{
int s;
/* Start the actual accepting. */
if (nn_fsm_isidle(&self->fsm)) {
nn_fsm_start (&self->fsm);
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_BEING_ACCEPTED);
}
nn_fsm_action (&listener->fsm, NN_USOCK_ACTION_ACCEPT);
/* Try to accept new connection in synchronous manner. */
#if NN_HAVE_ACCEPT4
s = accept4 (listener->s, NULL, NULL, SOCK_CLOEXEC);
#else
s = accept (listener->s, NULL, NULL);
#endif
/* Immediate success. */
if (nn_fast (s >= 0)) {
/* Disassociate the listener socket from the accepted
socket. Is useful if we restart accepting on ACCEPT_ERROR */
listener->asock = NULL;
self->asock = NULL;
nn_usock_init_from_fd (self, s);
nn_fsm_action (&listener->fsm, NN_USOCK_ACTION_DONE);
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_DONE);
return;
}
/* Detect a failure. Note that in ECONNABORTED case we simply ignore
the error and wait for next connection in asynchronous manner. */
errno_assert (errno == EAGAIN || errno == EWOULDBLOCK ||
errno == ECONNABORTED || errno == ENFILE || errno == EMFILE ||
errno == ENOBUFS || errno == ENOMEM);
/* Pair the two sockets. They are already paired in case
previous attempt failed on ACCEPT_ERROR */
nn_assert (!self->asock || self->asock == listener);
self->asock = listener;
nn_assert (!listener->asock || listener->asock == self);
listener->asock = self;
/* Some errors are just ok to ignore for now. We also stop repeating
any errors until next IN_FD event so that we are not in a tight loop
and allow processing other events in the meantime */
if (nn_slow (errno != EAGAIN && errno != EWOULDBLOCK
&& errno != ECONNABORTED && errno != listener->errnum))
{
listener->errnum = errno;
listener->state = NN_USOCK_STATE_ACCEPTING_ERROR;
nn_fsm_raise (&listener->fsm,
&listener->event_error, NN_USOCK_ACCEPT_ERROR);
return;
}
/* Ask the worker thread to wait for the new connection. */
nn_worker_execute (listener->worker, &listener->task_accept);
}
void nn_usock_activate (struct nn_usock *self)
{
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ACTIVATE);
}
void nn_usock_connect (struct nn_usock *self, const struct sockaddr *addr,
size_t addrlen)
{
int rc;
/* Notify the state machine that we've started connecting. */
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_CONNECT);
/* Do the connect itself. */
rc = connect (self->s, addr, (socklen_t) addrlen);
/* Immediate success. */
if (nn_fast (rc == 0)) {
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_DONE);
return;
}
/* Immediate error. */
if (nn_slow (errno != EINPROGRESS)) {
self->errnum = errno;
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR);
return;
}
/* Start asynchronous connect. */
nn_worker_execute (self->worker, &self->task_connecting);
}
void nn_usock_send (struct nn_usock *self, const struct nn_iovec *iov,
int iovcnt)
{
int rc;
int i;
int out;
/* Make sure that the socket is actually alive. */
nn_assert_state (self, NN_USOCK_STATE_ACTIVE);
/* Copy the iovecs to the socket. */
nn_assert (iovcnt <= NN_USOCK_MAX_IOVCNT);
self->out.hdr.msg_iov = self->out.iov;
out = 0;
for (i = 0; i != iovcnt; ++i) {
if (iov [i].iov_len == 0)
continue;
self->out.iov [out].iov_base = iov [i].iov_base;
self->out.iov [out].iov_len = iov [i].iov_len;
out++;
}
self->out.hdr.msg_iovlen = out;
/* Try to send the data immediately. */
rc = nn_usock_send_raw (self, &self->out.hdr);
/* Success. */
if (nn_fast (rc == 0)) {
nn_fsm_raise (&self->fsm, &self->event_sent, NN_USOCK_SENT);
return;
}
/* Errors. */
if (nn_slow (rc != -EAGAIN)) {
errnum_assert (rc == -ECONNRESET, -rc);
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR);
return;
}
/* Ask the worker thread to send the remaining data. */
nn_worker_execute (self->worker, &self->task_send);
}
void nn_usock_recv (struct nn_usock *self, void *buf, size_t len, int *fd)
{
int rc;
size_t nbytes;
/* Make sure that the socket is actually alive. */
nn_assert_state (self, NN_USOCK_STATE_ACTIVE);
/* Try to receive the data immediately. */
nbytes = len;
self->in.pfd = fd;
rc = nn_usock_recv_raw (self, buf, &nbytes);
if (nn_slow (rc < 0)) {
errnum_assert (rc == -ECONNRESET, -rc);
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR);
return;
}
/* Success. */
if (nn_fast (nbytes == len)) {
nn_fsm_raise (&self->fsm, &self->event_received, NN_USOCK_RECEIVED);
return;
}
/* There are still data to receive in the background. */
self->in.buf = ((uint8_t*) buf) + nbytes;
self->in.len = len - nbytes;
/* Ask the worker thread to receive the remaining data. */
nn_worker_execute (self->worker, &self->task_recv);
}
static int nn_internal_tasks (struct nn_usock *usock, int src, int type)
{
/******************************************************************************/
/* Internal tasks sent from the user thread to the worker thread. */
/******************************************************************************/
switch (src) {
case NN_USOCK_SRC_TASK_SEND:
nn_assert (type == NN_WORKER_TASK_EXECUTE);
nn_worker_set_out (usock->worker, &usock->wfd);
return 1;
case NN_USOCK_SRC_TASK_RECV:
nn_assert (type == NN_WORKER_TASK_EXECUTE);
nn_worker_set_in (usock->worker, &usock->wfd);
return 1;
case NN_USOCK_SRC_TASK_CONNECTED:
nn_assert (type == NN_WORKER_TASK_EXECUTE);
nn_worker_add_fd (usock->worker, usock->s, &usock->wfd);
return 1;
case NN_USOCK_SRC_TASK_CONNECTING:
nn_assert (type == NN_WORKER_TASK_EXECUTE);
nn_worker_add_fd (usock->worker, usock->s, &usock->wfd);
nn_worker_set_out (usock->worker, &usock->wfd);
return 1;
case NN_USOCK_SRC_TASK_ACCEPT:
nn_assert (type == NN_WORKER_TASK_EXECUTE);
nn_worker_add_fd (usock->worker, usock->s, &usock->wfd);
nn_worker_set_in (usock->worker, &usock->wfd);
return 1;
}
return 0;
}
static void nn_usock_shutdown (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_usock *usock;
usock = nn_cont (self, struct nn_usock, fsm);
if (nn_internal_tasks (usock, src, type))
return;
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
/* Socket in ACCEPTING or CANCELLING state cannot be closed.
Stop the socket being accepted first. */
nn_assert (usock->state != NN_USOCK_STATE_ACCEPTING &&
usock->state != NN_USOCK_STATE_CANCELLING);
usock->errnum = 0;
/* Synchronous stop. */
if (usock->state == NN_USOCK_STATE_IDLE)
goto finish3;
if (usock->state == NN_USOCK_STATE_DONE)
goto finish2;
if (usock->state == NN_USOCK_STATE_STARTING ||
usock->state == NN_USOCK_STATE_ACCEPTED ||
usock->state == NN_USOCK_STATE_ACCEPTING_ERROR ||
usock->state == NN_USOCK_STATE_LISTENING)
goto finish1;
/* When socket that's being accepted is asked to stop, we have to
ask the listener socket to stop accepting first. */
if (usock->state == NN_USOCK_STATE_BEING_ACCEPTED) {
nn_fsm_action (&usock->asock->fsm, NN_USOCK_ACTION_CANCEL);
usock->state = NN_USOCK_STATE_STOPPING_ACCEPT;
return;
}
/* Asynchronous stop. */
if (usock->state != NN_USOCK_STATE_REMOVING_FD)
nn_usock_async_stop (usock);
usock->state = NN_USOCK_STATE_STOPPING;
return;
}
if (nn_slow (usock->state == NN_USOCK_STATE_STOPPING_ACCEPT)) {
nn_assert (src == NN_FSM_ACTION && type == NN_USOCK_ACTION_DONE);
goto finish2;
}
if (nn_slow (usock->state == NN_USOCK_STATE_STOPPING)) {
if (src != NN_USOCK_SRC_TASK_STOP)
return;
nn_assert (type == NN_WORKER_TASK_EXECUTE);
nn_worker_rm_fd (usock->worker, &usock->wfd);
finish1:
nn_closefd (usock->s);
usock->s = -1;
finish2:
usock->state = NN_USOCK_STATE_IDLE;
nn_fsm_stopped (&usock->fsm, NN_USOCK_STOPPED);
finish3:
return;
}
nn_fsm_bad_state(usock->state, src, type);
}
static void nn_usock_handler (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
int rc;
struct nn_usock *usock;
int s;
size_t sz;
int sockerr;
usock = nn_cont (self, struct nn_usock, fsm);
if(nn_internal_tasks(usock, src, type))
return;
switch (usock->state) {
/******************************************************************************/
/* IDLE state. */
/* nn_usock object is initialised, but underlying OS socket is not yet */
/* created. */
/******************************************************************************/
case NN_USOCK_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
usock->state = NN_USOCK_STATE_STARTING;
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/******************************************************************************/
/* STARTING state. */
/* Underlying OS socket is created, but it's not yet passed to the worker */
/* thread. In this state we can set socket options, local and remote */
/* address etc. */
/******************************************************************************/
case NN_USOCK_STATE_STARTING:
/* Events from the owner of the usock. */
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_USOCK_ACTION_LISTEN:
usock->state = NN_USOCK_STATE_LISTENING;
return;
case NN_USOCK_ACTION_CONNECT:
usock->state = NN_USOCK_STATE_CONNECTING;
return;
case NN_USOCK_ACTION_BEING_ACCEPTED:
usock->state = NN_USOCK_STATE_BEING_ACCEPTED;
return;
case NN_USOCK_ACTION_STARTED:
nn_worker_add_fd (usock->worker, usock->s, &usock->wfd);
usock->state = NN_USOCK_STATE_ACTIVE;
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/******************************************************************************/
/* BEING_ACCEPTED state. */
/* accept() was called on the usock. Now the socket is waiting for a new */
/* connection to arrive. */
/******************************************************************************/
case NN_USOCK_STATE_BEING_ACCEPTED:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_USOCK_ACTION_DONE:
usock->state = NN_USOCK_STATE_ACCEPTED;
nn_fsm_raise (&usock->fsm, &usock->event_established,
NN_USOCK_ACCEPTED);
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/******************************************************************************/
/* ACCEPTED state. */
/* Connection was accepted, now it can be tuned. Afterwards, it'll move to */
/* the active state. */
/******************************************************************************/
case NN_USOCK_STATE_ACCEPTED:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_USOCK_ACTION_ACTIVATE:
nn_worker_add_fd (usock->worker, usock->s, &usock->wfd);
usock->state = NN_USOCK_STATE_ACTIVE;
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/******************************************************************************/
/* CONNECTING state. */
/* Asynchronous connecting is going on. */
/******************************************************************************/
case NN_USOCK_STATE_CONNECTING:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_USOCK_ACTION_DONE:
usock->state = NN_USOCK_STATE_ACTIVE;
nn_worker_execute (usock->worker, &usock->task_connected);
nn_fsm_raise (&usock->fsm, &usock->event_established,
NN_USOCK_CONNECTED);
return;
case NN_USOCK_ACTION_ERROR:
nn_closefd (usock->s);
usock->s = -1;
usock->state = NN_USOCK_STATE_DONE;
nn_fsm_raise (&usock->fsm, &usock->event_error,
NN_USOCK_ERROR);
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
case NN_USOCK_SRC_FD:
switch (type) {
case NN_WORKER_FD_OUT:
nn_worker_reset_out (usock->worker, &usock->wfd);
usock->state = NN_USOCK_STATE_ACTIVE;
sockerr = nn_usock_geterr(usock);
if (sockerr == 0) {
nn_fsm_raise (&usock->fsm, &usock->event_established,
NN_USOCK_CONNECTED);
} else {
usock->errnum = sockerr;
nn_worker_rm_fd (usock->worker, &usock->wfd);
rc = close (usock->s);
errno_assert (rc == 0);
usock->s = -1;
usock->state = NN_USOCK_STATE_DONE;
nn_fsm_raise (&usock->fsm,
&usock->event_error, NN_USOCK_ERROR);
}
return;
case NN_WORKER_FD_ERR:
nn_worker_rm_fd (usock->worker, &usock->wfd);
nn_closefd (usock->s);
usock->s = -1;
usock->state = NN_USOCK_STATE_DONE;
nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR);
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/* Socket is connected. It can be used for sending and receiving data. */
/******************************************************************************/
case NN_USOCK_STATE_ACTIVE:
switch (src) {
case NN_USOCK_SRC_FD:
switch (type) {
case NN_WORKER_FD_IN:
sz = usock->in.len;
rc = nn_usock_recv_raw (usock, usock->in.buf, &sz);
if (nn_fast (rc == 0)) {
usock->in.len -= sz;
usock->in.buf += sz;
if (!usock->in.len) {
nn_worker_reset_in (usock->worker, &usock->wfd);
nn_fsm_raise (&usock->fsm, &usock->event_received,
NN_USOCK_RECEIVED);
}
return;
}
errnum_assert (rc == -ECONNRESET, -rc);
goto error;
case NN_WORKER_FD_OUT:
rc = nn_usock_send_raw (usock, &usock->out.hdr);
if (nn_fast (rc == 0)) {
nn_worker_reset_out (usock->worker, &usock->wfd);
nn_fsm_raise (&usock->fsm, &usock->event_sent,
NN_USOCK_SENT);
return;
}
if (nn_fast (rc == -EAGAIN))
return;
errnum_assert (rc == -ECONNRESET, -rc);
goto error;
case NN_WORKER_FD_ERR:
error:
nn_worker_rm_fd (usock->worker, &usock->wfd);
nn_closefd (usock->s);
usock->s = -1;
usock->state = NN_USOCK_STATE_DONE;
nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR);
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
case NN_FSM_ACTION:
switch (type) {
case NN_USOCK_ACTION_ERROR:
usock->state = NN_USOCK_STATE_REMOVING_FD;
nn_usock_async_stop (usock);
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source(usock->state, src, type);
}
/******************************************************************************/
/* REMOVING_FD state. */
/******************************************************************************/
case NN_USOCK_STATE_REMOVING_FD:
switch (src) {
case NN_USOCK_SRC_TASK_STOP:
switch (type) {
case NN_WORKER_TASK_EXECUTE:
nn_worker_rm_fd (usock->worker, &usock->wfd);
nn_closefd (usock->s);
usock->s = -1;
usock->state = NN_USOCK_STATE_DONE;
nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR);
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
/* Events from the file descriptor are ignored while it is being
removed. */
case NN_USOCK_SRC_FD:
return;
default:
nn_fsm_bad_source (usock->state, src, type);
}
/******************************************************************************/
/* DONE state. */
/* Socket is closed. The only thing that can be done in this state is */
/* stopping the usock. */
/******************************************************************************/
case NN_USOCK_STATE_DONE:
nn_fsm_bad_source (usock->state, src, type);
/******************************************************************************/
/* LISTENING state. */
/* Socket is listening for new incoming connections, however, user is not */
/* accepting a new connection. */
/******************************************************************************/
case NN_USOCK_STATE_LISTENING:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_USOCK_ACTION_ACCEPT:
usock->state = NN_USOCK_STATE_ACCEPTING;
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/******************************************************************************/
/* ACCEPTING state. */
/* User is waiting asynchronouslyfor a new inbound connection */
/* to be accepted. */
/******************************************************************************/
case NN_USOCK_STATE_ACCEPTING:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_USOCK_ACTION_DONE:
usock->state = NN_USOCK_STATE_LISTENING;
return;
case NN_USOCK_ACTION_CANCEL:
usock->state = NN_USOCK_STATE_CANCELLING;
nn_worker_execute (usock->worker, &usock->task_stop);
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
case NN_USOCK_SRC_FD:
switch (type) {
case NN_WORKER_FD_IN:
/* New connection arrived in asynchronous manner. */
#if NN_HAVE_ACCEPT4
s = accept4 (usock->s, NULL, NULL, SOCK_CLOEXEC);
#else
s = accept (usock->s, NULL, NULL);
#endif
/* ECONNABORTED is an valid error. New connection was closed
by the peer before we were able to accept it. If it happens
do nothing and wait for next incoming connection. */
if (nn_slow (s < 0 && errno == ECONNABORTED))
return;
/* Resource allocation errors. It's not clear from POSIX
specification whether the new connection is closed in this
case or whether it remains in the backlog. In the latter
case it would be wise to wait here for a while to prevent
busy looping. */
if (nn_slow (s < 0 && (errno == ENFILE || errno == EMFILE ||
errno == ENOBUFS || errno == ENOMEM))) {
usock->errnum = errno;
usock->state = NN_USOCK_STATE_ACCEPTING_ERROR;
/* Wait till the user starts accepting once again. */
nn_worker_rm_fd (usock->worker, &usock->wfd);
nn_fsm_raise (&usock->fsm,
&usock->event_error, NN_USOCK_ACCEPT_ERROR);
return;
}
/* Any other error is unexpected. */
errno_assert (s >= 0);
/* Initialise the new usock object. */
nn_usock_init_from_fd (usock->asock, s);
usock->asock->state = NN_USOCK_STATE_ACCEPTED;
/* Notify the user that connection was accepted. */
nn_fsm_raise (&usock->asock->fsm,
&usock->asock->event_established, NN_USOCK_ACCEPTED);
/* Disassociate the listener socket from the accepted
socket. */
usock->asock->asock = NULL;
usock->asock = NULL;
/* Wait till the user starts accepting once again. */
nn_worker_rm_fd (usock->worker, &usock->wfd);
usock->state = NN_USOCK_STATE_LISTENING;
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/******************************************************************************/
/* ACCEPTING_ERROR state. */
/* Waiting the socket to accept the error and restart */
/******************************************************************************/
case NN_USOCK_STATE_ACCEPTING_ERROR:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_USOCK_ACTION_ACCEPT:
usock->state = NN_USOCK_STATE_ACCEPTING;
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/******************************************************************************/
/* CANCELLING state. */
/******************************************************************************/
case NN_USOCK_STATE_CANCELLING:
switch (src) {
case NN_USOCK_SRC_TASK_STOP:
switch (type) {
case NN_WORKER_TASK_EXECUTE:
nn_worker_rm_fd (usock->worker, &usock->wfd);
usock->state = NN_USOCK_STATE_LISTENING;
/* Notify the accepted socket that it was stopped. */
nn_fsm_action (&usock->asock->fsm, NN_USOCK_ACTION_DONE);
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
case NN_USOCK_SRC_FD:
switch (type) {
case NN_WORKER_FD_IN:
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/******************************************************************************/
/* Invalid state */
/******************************************************************************/
default:
nn_fsm_bad_state (usock->state, src, type);
}
}
static int nn_usock_send_raw (struct nn_usock *self, struct msghdr *hdr)
{
ssize_t nbytes;
/* Try to send the data. */
#if defined MSG_NOSIGNAL
nbytes = sendmsg (self->s, hdr, MSG_NOSIGNAL);
#else
nbytes = sendmsg (self->s, hdr, 0);
#endif
/* Handle errors. */
if (nn_slow (nbytes < 0)) {
if (nn_fast (errno == EAGAIN || errno == EWOULDBLOCK))
nbytes = 0;
else {
/* If the connection fails, return ECONNRESET. */
return -ECONNRESET;
}
}
/* Some bytes were sent. Adjust the iovecs accordingly. */
while (nbytes) {
if (nbytes >= (ssize_t)hdr->msg_iov->iov_len) {
--hdr->msg_iovlen;
if (!hdr->msg_iovlen) {
nn_assert (nbytes == (ssize_t)hdr->msg_iov->iov_len);
return 0;
}
nbytes -= hdr->msg_iov->iov_len;
++hdr->msg_iov;
}
else {
*((uint8_t**) &(hdr->msg_iov->iov_base)) += nbytes;
hdr->msg_iov->iov_len -= nbytes;
return -EAGAIN;
}
}
if (hdr->msg_iovlen > 0)
return -EAGAIN;
return 0;
}
static int nn_usock_recv_raw (struct nn_usock *self, void *buf, size_t *len)
{
size_t sz;
size_t length;
ssize_t nbytes;
struct iovec iov;
struct msghdr hdr;
unsigned char ctrl [256];
#if defined NN_HAVE_MSG_CONTROL
struct cmsghdr *cmsg;
#endif
/* If batch buffer doesn't exist, allocate it. The point of delayed
deallocation to allow non-receiving sockets, such as TCP listening
sockets, to do without the batch buffer. */
if (nn_slow (!self->in.batch)) {
self->in.batch = nn_alloc (NN_USOCK_BATCH_SIZE, "AIO batch buffer");
alloc_assert (self->in.batch);
}
/* Try to satisfy the recv request by data from the batch buffer. */
length = *len;
sz = self->in.batch_len - self->in.batch_pos;
if (sz) {
if (sz > length)
sz = length;
memcpy (buf, self->in.batch + self->in.batch_pos, sz);
self->in.batch_pos += sz;
buf = ((char*) buf) + sz;
length -= sz;
if (!length)
return 0;
}
/* If recv request is greater than the batch buffer, get the data directly
into the place. Otherwise, read data to the batch buffer. */
if (length > NN_USOCK_BATCH_SIZE) {
iov.iov_base = buf;
iov.iov_len = length;
}
else {
iov.iov_base = self->in.batch;
iov.iov_len = NN_USOCK_BATCH_SIZE;
}
memset (&hdr, 0, sizeof (hdr));
hdr.msg_iov = &iov;
hdr.msg_iovlen = 1;
#if defined NN_HAVE_MSG_CONTROL
hdr.msg_control = ctrl;
hdr.msg_controllen = sizeof (ctrl);
#else
*((int*) ctrl) = -1;
hdr.msg_accrights = ctrl;
hdr.msg_accrightslen = sizeof (int);
#endif
nbytes = recvmsg (self->s, &hdr, 0);
/* Handle any possible errors. */
if (nn_slow (nbytes <= 0)) {
if (nn_slow (nbytes == 0))
return -ECONNRESET;
/* Zero bytes received. */
if (nn_fast (errno == EAGAIN || errno == EWOULDBLOCK))
nbytes = 0;
else {
/* If the peer closes the connection, return ECONNRESET. */
return -ECONNRESET;
}
}
/* Extract the associated file descriptor, if any. */
if (nbytes > 0) {
#if defined NN_HAVE_MSG_CONTROL
cmsg = CMSG_FIRSTHDR (&hdr);
while (cmsg) {
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
if (self->in.pfd) {
*self->in.pfd = *((int*) CMSG_DATA (cmsg));
self->in.pfd = NULL;
}
else {
nn_closefd (*((int*) CMSG_DATA (cmsg)));
}
break;
}
cmsg = CMSG_NXTHDR (&hdr, cmsg);
}
#else
if (hdr.msg_accrightslen > 0) {
nn_assert (hdr.msg_accrightslen == sizeof (int));
if (self->in.pfd) {
*self->in.pfd = *((int*) hdr.msg_accrights);
self->in.pfd = NULL;
}
else {
nn_closefd (*((int*) hdr.msg_accrights));
}
}
#endif
}
/* If the data were received directly into the place we can return
straight away. */
if (length > NN_USOCK_BATCH_SIZE) {
length -= nbytes;
*len -= length;
return 0;
}
/* New data were read to the batch buffer. Copy the requested amount of it
to the user-supplied buffer. */
self->in.batch_len = nbytes;
self->in.batch_pos = 0;
if (nbytes) {
sz = nbytes > (ssize_t)length ? length : (size_t)nbytes;
memcpy (buf, self->in.batch, sz);
length -= sz;
self->in.batch_pos += sz;
}
*len -= length;
return 0;
}
static int nn_usock_geterr (struct nn_usock *self)
{
int rc;
int opt;
#if defined NN_HAVE_HPUX
int optsz;
#else
socklen_t optsz;
#endif
opt = 0;
optsz = sizeof (opt);
rc = getsockopt (self->s, SOL_SOCKET, SO_ERROR, &opt, &optsz);
/* The following should handle both Solaris and UNIXes derived from BSD. */
if (rc == -1)
return errno;
errno_assert (rc == 0);
nn_assert (optsz == sizeof (opt));
return opt;
}
nanomsg-0.8-beta/src/aio/usock_win.h0000664000175000017500000000536512623652600020364 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "fsm.h"
#include "worker.h"
#include "../utils/win.h"
struct nn_usock {
/* The state machine. */
struct nn_fsm fsm;
int state;
union {
/* The actual underlying socket. Can be used as a HANDLE too. */
SOCKET s;
/* Named pipe handle. Cannot be used as a SOCKET. */
HANDLE p;
};
/* For NamedPipes, closing an accepted pipe differs from other pipes.
If the NamedPipe was accepted, this member is set to 1. 0 otherwise. */
int isaccepted;
/* Asynchronous operations being executed on the socket. */
struct nn_worker_op in;
struct nn_worker_op out;
/* When accepting new socket, they have to be created with same
type as the listening socket. Thus, in listening socket we
have to store its exact type. */
int domain;
int type;
int protocol;
/* Events raised by the usock. */
struct nn_fsm_event event_established;
struct nn_fsm_event event_sent;
struct nn_fsm_event event_received;
struct nn_fsm_event event_error;
/* In ACCEPTING state points to the socket being accepted.
In BEING_ACCEPTED state points to the listener socket. */
struct nn_usock *asock;
/* Buffer allocated for output of AcceptEx function. If accepting is not
done on this socket, the field is set to NULL. */
void *ainfo;
/* For NamedPipes, we store the address inside the socket. */
struct sockaddr_un pipename;
/* For now we allocate a new buffer for each write to a named pipe. */
void *pipesendbuf;
/* Errno remembered in NN_USOCK_ERROR state */
int errnum;
};
nanomsg-0.8-beta/src/aio/usock_win.inc0000664000175000017500000010451312623652600020701 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "worker.h"
#include "../utils/err.h"
#include "../utils/cont.h"
#include "../utils/alloc.h"
#include
#include
#include
#define NN_USOCK_STATE_IDLE 1
#define NN_USOCK_STATE_STARTING 2
#define NN_USOCK_STATE_BEING_ACCEPTED 3
#define NN_USOCK_STATE_ACCEPTED 4
#define NN_USOCK_STATE_CONNECTING 5
#define NN_USOCK_STATE_ACTIVE 6
#define NN_USOCK_STATE_CANCELLING_IO 7
#define NN_USOCK_STATE_DONE 8
#define NN_USOCK_STATE_LISTENING 9
#define NN_USOCK_STATE_ACCEPTING 10
#define NN_USOCK_STATE_CANCELLING 11
#define NN_USOCK_STATE_STOPPING 12
#define NN_USOCK_STATE_STOPPING_ACCEPT 13
#define NN_USOCK_ACTION_ACCEPT 1
#define NN_USOCK_ACTION_BEING_ACCEPTED 2
#define NN_USOCK_ACTION_CANCEL 3
#define NN_USOCK_ACTION_LISTEN 4
#define NN_USOCK_ACTION_CONNECT 5
#define NN_USOCK_ACTION_ACTIVATE 6
#define NN_USOCK_ACTION_DONE 7
#define NN_USOCK_ACTION_ERROR 8
#define NN_USOCK_SRC_IN 1
#define NN_USOCK_SRC_OUT 2
/* Private functions. */
static void nn_usock_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_usock_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
static int nn_usock_cancel_io (struct nn_usock *self);
static void nn_usock_create_io_completion (struct nn_usock *self);
DWORD nn_usock_open_pipe (struct nn_usock *self, const char *name);
void nn_usock_accept_pipe (struct nn_usock *self, struct nn_usock *listener);
void nn_usock_init (struct nn_usock *self, int src, struct nn_fsm *owner)
{
nn_fsm_init (&self->fsm, nn_usock_handler, nn_usock_shutdown,
src, self, owner);
self->state = NN_USOCK_STATE_IDLE;
self->s = INVALID_SOCKET;
self->isaccepted = 0;
nn_worker_op_init (&self->in, NN_USOCK_SRC_IN, &self->fsm);
nn_worker_op_init (&self->out, NN_USOCK_SRC_OUT, &self->fsm);
self->domain = -1;
self->type = -1;
self->protocol = -1;
/* Intialise events raised by usock. */
nn_fsm_event_init (&self->event_established);
nn_fsm_event_init (&self->event_sent);
nn_fsm_event_init (&self->event_received);
nn_fsm_event_init (&self->event_error);
/* No accepting is going on at the moment. */
self->asock = NULL;
self->ainfo = NULL;
/* NamedPipe-related stuff. */
memset (&self->pipename, 0, sizeof (self->pipename));
self->pipesendbuf = NULL;
}
void nn_usock_term (struct nn_usock *self)
{
nn_assert_state (self, NN_USOCK_STATE_IDLE);
if (self->ainfo)
nn_free (self->ainfo);
if (self->pipesendbuf)
nn_free (self->pipesendbuf);
nn_fsm_event_term (&self->event_error);
nn_fsm_event_term (&self->event_received);
nn_fsm_event_term (&self->event_sent);
nn_fsm_event_term (&self->event_established);
nn_worker_op_term (&self->out);
nn_worker_op_term (&self->in);
nn_fsm_term (&self->fsm);
}
int nn_usock_isidle (struct nn_usock *self)
{
return nn_fsm_isidle (&self->fsm);
}
int nn_usock_start (struct nn_usock *self, int domain, int type, int protocol)
{
int rc;
#if defined IPV6_V6ONLY
DWORD only;
#endif
#if defined HANDLE_FLAG_INHERIT
BOOL brc;
#endif
/* NamedPipes aren't sockets. They don't need all the socket
initialisation stuff. */
if (domain != AF_UNIX) {
/* Open the underlying socket. */
self->s = socket (domain, type, protocol);
if (self->s == INVALID_SOCKET)
return -nn_err_wsa_to_posix (WSAGetLastError ());
/* Disable inheriting the socket to the child processes. */
#if defined HANDLE_FLAG_INHERIT
brc = SetHandleInformation (self->p, HANDLE_FLAG_INHERIT, 0);
win_assert (brc);
#endif
/* IPv4 mapping for IPv6 sockets is disabled by default. Switch it on. */
#if defined IPV6_V6ONLY
if (domain == AF_INET6) {
only = 0;
rc = setsockopt (self->s, IPPROTO_IPV6, IPV6_V6ONLY,
(const char*) &only, sizeof (only));
wsa_assert (rc != SOCKET_ERROR);
}
#endif
/* Associate the socket with a worker thread/completion port. */
nn_usock_create_io_completion (self);
}
/* Remember the type of the socket. */
self->domain = domain;
self->type = type;
self->protocol = protocol;
/* Start the state machine. */
nn_fsm_start (&self->fsm);
return 0;
}
void nn_usock_start_fd (struct nn_usock *self, int fd)
{
nn_assert (0);
}
void nn_usock_stop (struct nn_usock *self)
{
nn_fsm_stop (&self->fsm);
}
void nn_usock_swap_owner (struct nn_usock *self, struct nn_fsm_owner *owner)
{
nn_fsm_swap_owner (&self->fsm, owner);
}
int nn_usock_setsockopt (struct nn_usock *self, int level, int optname,
const void *optval, size_t optlen)
{
int rc;
/* NamedPipes aren't sockets. We can't set socket options on them.
For now we'll ignore the options. */
if (self->domain == AF_UNIX)
return 0;
/* The socket can be modified only before it's active. */
nn_assert (self->state == NN_USOCK_STATE_STARTING ||
self->state == NN_USOCK_STATE_ACCEPTED);
nn_assert (optlen < INT_MAX);
rc = setsockopt (self->s, level, optname, (char*) optval, (int) optlen);
if (nn_slow (rc == SOCKET_ERROR))
return -nn_err_wsa_to_posix (WSAGetLastError ());
return 0;
}
int nn_usock_bind (struct nn_usock *self, const struct sockaddr *addr,
size_t addrlen)
{
int rc;
ULONG opt;
/* In the case of named pipes, let's save the address
for the later use. */
if (self->domain == AF_UNIX) {
if (addrlen > sizeof (struct sockaddr_un))
return -EINVAL;
memcpy (&self->pipename, addr, addrlen);
return 0;
}
/* You can set socket options only before the socket is connected. */
nn_assert_state (self, NN_USOCK_STATE_STARTING);
/* On Windows, the bound port can be hijacked
if SO_EXCLUSIVEADDRUSE is not set. */
opt = 1;
rc = setsockopt (self->s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
(const char*) &opt, sizeof (opt));
wsa_assert (rc != SOCKET_ERROR);
nn_assert (addrlen < INT_MAX);
rc = bind (self->s, addr, (int) addrlen);
if (nn_slow (rc == SOCKET_ERROR))
return -nn_err_wsa_to_posix (WSAGetLastError ());
return 0;
}
int nn_usock_listen (struct nn_usock *self, int backlog)
{
int rc;
/* You can start listening only before the socket is connected. */
nn_assert_state (self, NN_USOCK_STATE_STARTING);
/* Start listening for incoming connections. NamedPipes are already
created in the listening state, so no need to do anything here. */
if (self->domain != AF_UNIX) {
rc = listen (self->s, backlog);
if (nn_slow (rc == SOCKET_ERROR))
return -nn_err_wsa_to_posix (WSAGetLastError ());
}
/* Notify the state machine. */
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_LISTEN);
return 0;
}
void nn_usock_accept (struct nn_usock *self, struct nn_usock *listener)
{
int rc;
BOOL brc;
DWORD nbytes;
/* NamedPipes have their own accepting mechanism. */
if (listener->domain == AF_UNIX) {
nn_usock_accept_pipe (self, listener);
return;
}
rc = nn_usock_start (self, listener->domain, listener->type,
listener->protocol);
/* TODO: EMFILE can be returned here. */
errnum_assert (rc == 0, -rc);
nn_fsm_action (&listener->fsm, NN_USOCK_ACTION_ACCEPT);
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_BEING_ACCEPTED);
/* If the memory for accept information is not yet allocated, do so. */
if (!listener->ainfo) {
listener->ainfo = nn_alloc (512, "accept info");
alloc_assert (listener->ainfo);
}
/* Wait for the incoming connection. */
memset (&listener->in.olpd, 0, sizeof (listener->in.olpd));
brc = AcceptEx (listener->s, self->s, listener->ainfo, 0, 256, 256, &nbytes,
&listener->in.olpd);
/* Immediate success. */
if (nn_fast (brc == TRUE)) {
nn_fsm_action (&listener->fsm, NN_USOCK_ACTION_DONE);
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_DONE);
return;
}
/* We don't expect a synchronous failure at this point. */
wsa_assert (nn_slow (WSAGetLastError () == WSA_IO_PENDING));
/* Pair the two sockets. */
nn_assert (!self->asock);
self->asock = listener;
nn_assert (!listener->asock);
listener->asock = self;
/* Asynchronous accept. */
nn_worker_op_start (&listener->in, 0);
}
void nn_usock_activate (struct nn_usock *self)
{
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ACTIVATE);
}
void nn_usock_connect (struct nn_usock *self, const struct sockaddr *addr,
size_t addrlen)
{
BOOL brc;
const GUID fid = WSAID_CONNECTEX;
LPFN_CONNECTEX pconnectex;
DWORD nbytes;
DWORD winerror;
/* Fail if the socket is already connected, closed or such. */
nn_assert_state (self, NN_USOCK_STATE_STARTING);
/* Notify the state machine that we've started connecting. */
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_CONNECT);
nn_assert(addrlen < INT_MAX);
memset (&self->out.olpd, 0, sizeof (self->out.olpd));
if (self->domain == AF_UNIX) {
winerror = nn_usock_open_pipe (self, ((struct sockaddr_un*) addr)->sun_path);
}
else
{
/* Get the pointer to connect function. */
brc = WSAIoctl(self->s, SIO_GET_EXTENSION_FUNCTION_POINTER,
(void*)&fid, sizeof(fid), (void*)&pconnectex, sizeof(pconnectex),
&nbytes, NULL, NULL) == 0;
wsa_assert(brc == TRUE);
nn_assert(nbytes == sizeof(pconnectex));
/* Connect itself. */
brc = pconnectex(self->s, (struct sockaddr*) addr, addrlen,
NULL, 0, NULL, &self->out.olpd);
winerror = brc ? ERROR_SUCCESS : WSAGetLastError();
}
/* Immediate success. */
if (nn_fast (winerror == ERROR_SUCCESS)) {
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_DONE);
return;
}
/* Immediate error. */
if (nn_slow (winerror != WSA_IO_PENDING)) {
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR);
return;
}
/* Asynchronous connect. */
nn_worker_op_start (&self->out, 0);
}
void nn_usock_send (struct nn_usock *self, const struct nn_iovec *iov,
int iovcnt)
{
int rc;
BOOL brc;
WSABUF wbuf [NN_USOCK_MAX_IOVCNT];
int i;
size_t len;
size_t idx;
DWORD error;
/* Make sure that the socket is actually alive. */
nn_assert_state (self, NN_USOCK_STATE_ACTIVE);
/* Create a WinAPI-style iovec. */
len = 0;
nn_assert (iovcnt <= NN_USOCK_MAX_IOVCNT);
for (i = 0; i != iovcnt; ++i) {
wbuf [i].buf = (char FAR*) iov [i].iov_base;
wbuf [i].len = (u_long) iov [i].iov_len;
len += iov [i].iov_len;
}
/* Start the send operation. */
memset (&self->out.olpd, 0, sizeof (self->out.olpd));
if (self->domain == AF_UNIX)
{
/* TODO: Do not copy the buffer, find an efficent way to Write
multiple buffers that doesn't affect the state machine. */
nn_assert (!self->pipesendbuf);
self->pipesendbuf = nn_alloc (len, "named pipe sendbuf");
idx = 0;
for (i = 0; i != iovcnt; ++i) {
memcpy ((char*)(self->pipesendbuf) + idx, iov [i].iov_base, iov [i].iov_len);
idx += iov [i].iov_len;
}
brc = WriteFile (self->p, self->pipesendbuf, len, NULL, &self->out.olpd);
if (nn_fast (brc || GetLastError() == ERROR_IO_PENDING)) {
nn_worker_op_start (&self->out, 0);
return;
}
error = GetLastError();
win_assert (error == ERROR_NO_DATA);
self->errnum = EINVAL;
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR);
return;
}
rc = WSASend (self->s, wbuf, iovcnt, NULL, 0, &self->out.olpd, NULL);
if (nn_fast (rc == 0)) {
nn_worker_op_start (&self->out, 0);
return;
}
error = WSAGetLastError();
if (nn_fast (error == WSA_IO_PENDING)) {
nn_worker_op_start (&self->out, 0);
return;
}
wsa_assert (error == WSAECONNABORTED || error == WSAECONNRESET ||
error == WSAENETDOWN || error == WSAENETRESET ||
error == WSAENOBUFS || error == WSAEWOULDBLOCK);
self->errnum = nn_err_wsa_to_posix (error);
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR);
}
void nn_usock_recv (struct nn_usock *self, void *buf, size_t len, int *fd)
{
int rc;
BOOL brc;
WSABUF wbuf;
DWORD wflags;
DWORD error;
/* Passing file descriptors is not implemented on Windows platform. */
if (fd)
*fd = -1;
/* Make sure that the socket is actually alive. */
nn_assert_state (self, NN_USOCK_STATE_ACTIVE);
/* Start the receive operation. */
wbuf.len = (u_long) len;
wbuf.buf = (char FAR*) buf;
wflags = MSG_WAITALL;
memset (&self->in.olpd, 0, sizeof (self->in.olpd));
if (self->domain == AF_UNIX) {
brc = ReadFile(self->p, buf, len, NULL, &self->in.olpd);
error = brc ? ERROR_SUCCESS : GetLastError();
}
else {
rc = WSARecv (self->s, &wbuf, 1, NULL, &wflags, &self->in.olpd, NULL);
error = (rc == 0) ? ERROR_SUCCESS : WSAGetLastError ();
}
if (nn_fast (error == ERROR_SUCCESS)) {
nn_worker_op_start (&self->in, 1);
return;
}
if (nn_fast (error == WSA_IO_PENDING)) {
nn_worker_op_start (&self->in, 1);
return;
}
if (error == WSAECONNABORTED || error == WSAECONNRESET ||
error == WSAENETDOWN || error == WSAENETRESET ||
error == WSAETIMEDOUT || error == WSAEWOULDBLOCK ||
error == ERROR_PIPE_NOT_CONNECTED || error == ERROR_BROKEN_PIPE) {
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR);
return;
}
wsa_assert (0);
}
static void nn_usock_create_io_completion (struct nn_usock *self)
{
struct nn_worker *worker;
HANDLE cp;
/* Associate the socket with a worker thread/completion port. */
worker = nn_fsm_choose_worker (&self->fsm);
cp = CreateIoCompletionPort (
self->p,
nn_worker_getcp(worker),
(ULONG_PTR) NULL,
0);
nn_assert(cp);
}
static void nn_usock_create_pipe (struct nn_usock *self, const char *name)
{
char fullname [256];
/* First, create a fully qualified name for the named pipe. */
_snprintf(fullname, sizeof (fullname), "\\\\.\\pipe\\%s", name);
/* TODO: Expose custom nOutBufferSize, nInBufferSize, nDefaultTimeOut,
lpSecurityAttributes */
self->p = CreateNamedPipeA (
(char*) fullname,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
PIPE_UNLIMITED_INSTANCES,
4096,
4096,
0,
NULL);
/* TODO: How to properly handle self->p == INVALID_HANDLE_VALUE? */
win_assert (self->p != INVALID_HANDLE_VALUE);
self->isaccepted = 1;
nn_usock_create_io_completion (self);
}
DWORD nn_usock_open_pipe (struct nn_usock *self, const char *name)
{
char fullname [256];
DWORD winerror;
DWORD mode;
BOOL brc;
/* First, create a fully qualified name for the named pipe. */
_snprintf(fullname, sizeof (fullname), "\\\\.\\pipe\\%s", name);
/* TODO: Expose a way to pass lpSecurityAttributes */
self->p = CreateFileA (
fullname,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_ALWAYS,
FILE_FLAG_OVERLAPPED,
NULL);
if (self->p == INVALID_HANDLE_VALUE)
return GetLastError ();
mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
brc = SetNamedPipeHandleState (
self->p,
&mode,
NULL,
NULL);
if (!brc) {
CloseHandle (self->p);
self->p = INVALID_HANDLE_VALUE;
return GetLastError ();
}
self->isaccepted = 0;
nn_usock_create_io_completion (self);
winerror = GetLastError ();
if (winerror != ERROR_SUCCESS && winerror != ERROR_ALREADY_EXISTS)
return winerror;
return ERROR_SUCCESS;
}
void nn_usock_accept_pipe (struct nn_usock *self, struct nn_usock *listener)
{
int rc;
BOOL brc;
DWORD winerror;
/* TODO: EMFILE can be returned here. */
rc = nn_usock_start (self, listener->domain, listener->type,
listener->protocol);
errnum_assert(rc == 0, -rc);
nn_fsm_action(&listener->fsm, NN_USOCK_ACTION_ACCEPT);
nn_fsm_action(&self->fsm, NN_USOCK_ACTION_BEING_ACCEPTED);
/* If the memory for accept information is not yet allocated, do so now. */
if (!listener->ainfo) {
listener->ainfo = nn_alloc (512, "accept info");
alloc_assert (listener->ainfo);
}
/* Wait for the incoming connection. */
memset (&listener->in.olpd, 0, sizeof(listener->in.olpd));
nn_usock_create_pipe (self, listener->pipename.sun_path);
brc = ConnectNamedPipe (self->p, (LPOVERLAPPED) &listener->in.olpd);
/* TODO: Can this function possibly succeed? */
nn_assert (brc == 0);
winerror = GetLastError();
/* Immediate success. */
if (nn_fast (winerror == ERROR_PIPE_CONNECTED)) {
nn_fsm_action (&listener->fsm, NN_USOCK_ACTION_DONE);
nn_fsm_action (&self->fsm, NN_USOCK_ACTION_DONE);
return;
}
/* We don't expect a synchronous failure at this point. */
wsa_assert (nn_slow (winerror == WSA_IO_PENDING));
/* Pair the two sockets. */
nn_assert (!self->asock);
self->asock = listener;
nn_assert (!listener->asock);
listener->asock = self;
/* Asynchronous accept. */
nn_worker_op_start (&listener->in, 0);
}
static void nn_usock_close (struct nn_usock *self)
{
int rc;
BOOL brc;
if (self->domain == AF_UNIX) {
if (self->p == INVALID_HANDLE_VALUE)
return;
if (self->isaccepted)
DisconnectNamedPipe(self->p);
brc = CloseHandle (self->p);
self->p = INVALID_HANDLE_VALUE;
win_assert (brc);
}
else
{
rc = closesocket (self->s);
self->s = INVALID_SOCKET;
wsa_assert (rc == 0);
}
}
static void nn_usock_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr)
{
struct nn_usock *usock;
usock = nn_cont (self, struct nn_usock, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
/* Socket in ACCEPTING state cannot be closed.
Stop the socket being accepted first. */
nn_assert (usock->state != NN_USOCK_STATE_ACCEPTING);
/* Synchronous stop. */
if (usock->state == NN_USOCK_STATE_IDLE)
goto finish3;
if (usock->state == NN_USOCK_STATE_DONE)
goto finish2;
if (usock->state == NN_USOCK_STATE_STARTING ||
usock->state == NN_USOCK_STATE_ACCEPTED ||
usock->state == NN_USOCK_STATE_LISTENING)
goto finish1;
/* When socket that's being accepted is asked to stop, we have to
ask the listener socket to stop accepting first. */
if (usock->state == NN_USOCK_STATE_BEING_ACCEPTED) {
nn_fsm_action (&usock->asock->fsm, NN_USOCK_ACTION_CANCEL);
usock->state = NN_USOCK_STATE_STOPPING_ACCEPT;
return;
}
/* If we were already in the process of cancelling overlapped
operations, we don't have to do anything. Continue waiting
till cancelling is finished. */
if (usock->state == NN_USOCK_STATE_CANCELLING_IO) {
usock->state = NN_USOCK_STATE_STOPPING;
return;
}
/* Notify our parent that pipe socket is shutting down */
nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_SHUTDOWN);
/* In all remaining states we'll simply cancel all overlapped
operations. */
if (nn_usock_cancel_io (usock) == 0)
goto finish1;
usock->state = NN_USOCK_STATE_STOPPING;
return;
}
if (nn_slow (usock->state == NN_USOCK_STATE_STOPPING_ACCEPT)) {
nn_assert (src == NN_FSM_ACTION && type == NN_USOCK_ACTION_DONE);
goto finish1;
}
if (nn_slow (usock->state == NN_USOCK_STATE_STOPPING)) {
if (!nn_worker_op_isidle (&usock->in) ||
!nn_worker_op_isidle (&usock->out))
return;
finish1:
nn_usock_close(usock);
finish2:
usock->state = NN_USOCK_STATE_IDLE;
nn_fsm_stopped (&usock->fsm, NN_USOCK_STOPPED);
finish3:
return;
}
nn_fsm_bad_state(usock->state, src, type);
}
static void nn_usock_handler (struct nn_fsm *self, int src, int type,
void *srcptr)
{
struct nn_usock *usock;
usock = nn_cont (self, struct nn_usock, fsm);
switch (usock->state) {
/*****************************************************************************/
/* IDLE state. */
/*****************************************************************************/
case NN_USOCK_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
usock->state = NN_USOCK_STATE_STARTING;
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/*****************************************************************************/
/* STARTING state. */
/*****************************************************************************/
case NN_USOCK_STATE_STARTING:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_USOCK_ACTION_LISTEN:
usock->state = NN_USOCK_STATE_LISTENING;
return;
case NN_USOCK_ACTION_CONNECT:
usock->state = NN_USOCK_STATE_CONNECTING;
return;
case NN_USOCK_ACTION_BEING_ACCEPTED:
usock->state = NN_USOCK_STATE_BEING_ACCEPTED;
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/*****************************************************************************/
/* BEING_ACCEPTED state. */
/*****************************************************************************/
case NN_USOCK_STATE_BEING_ACCEPTED:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_USOCK_ACTION_DONE:
usock->state = NN_USOCK_STATE_ACCEPTED;
nn_fsm_raise (&usock->fsm, &usock->event_established,
NN_USOCK_ACCEPTED);
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/*****************************************************************************/
/* ACCEPTED state. */
/*****************************************************************************/
case NN_USOCK_STATE_ACCEPTED:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_USOCK_ACTION_ACTIVATE:
usock->state = NN_USOCK_STATE_ACTIVE;
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/*****************************************************************************/
/* CONNECTING state. */
/*****************************************************************************/
case NN_USOCK_STATE_CONNECTING:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_USOCK_ACTION_DONE:
usock->state = NN_USOCK_STATE_ACTIVE;
nn_fsm_raise (&usock->fsm, &usock->event_established,
NN_USOCK_CONNECTED);
return;
case NN_USOCK_ACTION_ERROR:
nn_usock_close(usock);
usock->state = NN_USOCK_STATE_DONE;
nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR);
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
case NN_USOCK_SRC_OUT:
switch (type) {
case NN_WORKER_OP_DONE:
usock->state = NN_USOCK_STATE_ACTIVE;
nn_fsm_raise (&usock->fsm, &usock->event_established,
NN_USOCK_CONNECTED);
return;
case NN_WORKER_OP_ERROR:
nn_usock_close(usock);
usock->state = NN_USOCK_STATE_DONE;
nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR);
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/*****************************************************************************/
/* ACTIVE state. */
/*****************************************************************************/
case NN_USOCK_STATE_ACTIVE:
switch (src) {
case NN_USOCK_SRC_IN:
switch (type) {
case NN_WORKER_OP_DONE:
nn_fsm_raise (&usock->fsm, &usock->event_received,
NN_USOCK_RECEIVED);
return;
case NN_WORKER_OP_ERROR:
if (nn_usock_cancel_io (usock) == 0) {
nn_fsm_raise(&usock->fsm, &usock->event_error,
NN_USOCK_ERROR);
nn_usock_close (usock);
usock->state = NN_USOCK_STATE_DONE;
return;
}
usock->state = NN_USOCK_STATE_CANCELLING_IO;
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
case NN_USOCK_SRC_OUT:
switch (type) {
case NN_WORKER_OP_DONE:
if (usock->pipesendbuf) {
nn_free(usock->pipesendbuf);
usock->pipesendbuf = NULL;
}
nn_fsm_raise (&usock->fsm, &usock->event_sent, NN_USOCK_SENT);
return;
case NN_WORKER_OP_ERROR:
if (nn_usock_cancel_io (usock) == 0) {
nn_fsm_raise(&usock->fsm, &usock->event_error,
NN_USOCK_ERROR);
nn_usock_close(usock);
usock->state = NN_USOCK_STATE_DONE;
return;
}
usock->state = NN_USOCK_STATE_CANCELLING_IO;
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
case NN_FSM_ACTION:
switch (type) {
case NN_USOCK_ACTION_ERROR:
if (nn_usock_cancel_io (usock) == 0) {
nn_fsm_raise(&usock->fsm, &usock->event_error,
NN_USOCK_SHUTDOWN);
nn_usock_close(usock);
usock->state = NN_USOCK_STATE_DONE;
return;
}
usock->state = NN_USOCK_STATE_CANCELLING_IO;
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/*****************************************************************************/
/* CANCELLING_IO state. */
/*****************************************************************************/
case NN_USOCK_STATE_CANCELLING_IO:
switch (src) {
case NN_USOCK_SRC_IN:
case NN_USOCK_SRC_OUT:
if (!nn_worker_op_isidle (&usock->in) ||
!nn_worker_op_isidle (&usock->out))
return;
nn_fsm_raise(&usock->fsm, &usock->event_error, NN_USOCK_SHUTDOWN);
nn_usock_close(usock);
usock->state = NN_USOCK_STATE_DONE;
return;
default:
nn_fsm_bad_source (usock->state, src, type);
}
/*****************************************************************************/
/* DONE state. */
/*****************************************************************************/
case NN_USOCK_STATE_DONE:
nn_fsm_bad_source (usock->state, src, type);
/*****************************************************************************/
/* LISTENING state. */
/*****************************************************************************/
case NN_USOCK_STATE_LISTENING:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_USOCK_ACTION_ACCEPT:
usock->state = NN_USOCK_STATE_ACCEPTING;
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/*****************************************************************************/
/* ACCEPTING state. */
/*****************************************************************************/
case NN_USOCK_STATE_ACCEPTING:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_USOCK_ACTION_DONE:
usock->state = NN_USOCK_STATE_LISTENING;
return;
case NN_USOCK_ACTION_CANCEL:
if (usock->p == INVALID_HANDLE_VALUE && usock->asock != NULL && usock->domain == AF_UNIX) {
usock->p = usock->asock->p;
nn_usock_cancel_io (usock);
usock->p = INVALID_HANDLE_VALUE;
}
else
{
nn_usock_cancel_io(usock);
}
usock->state = NN_USOCK_STATE_CANCELLING;
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
case NN_USOCK_SRC_IN:
switch (type) {
case NN_WORKER_OP_DONE:
/* Adjust the new usock object. */
usock->asock->state = NN_USOCK_STATE_ACCEPTED;
/* Notify the user that connection was accepted. */
nn_fsm_raise (&usock->asock->fsm,
&usock->asock->event_established, NN_USOCK_ACCEPTED);
/* Disassociate the listener socket from the accepted
socket. */
usock->asock->asock = NULL;
usock->asock = NULL;
/* Wait till the user starts accepting once again. */
usock->state = NN_USOCK_STATE_LISTENING;
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/*****************************************************************************/
/* CANCELLING state. */
/*****************************************************************************/
case NN_USOCK_STATE_CANCELLING:
switch (src) {
case NN_USOCK_SRC_IN:
switch (type) {
case NN_WORKER_OP_DONE:
case NN_WORKER_OP_ERROR:
/* TODO: The socket being accepted should be closed here. */
usock->state = NN_USOCK_STATE_LISTENING;
/* Notify the accepted socket that it was stopped. */
nn_fsm_action (&usock->asock->fsm, NN_USOCK_ACTION_DONE);
return;
default:
nn_fsm_bad_action (usock->state, src, type);
}
default:
nn_fsm_bad_source (usock->state, src, type);
}
/*****************************************************************************/
/* Invalid state. */
/*****************************************************************************/
default:
nn_fsm_bad_state (usock->state, src, type);
}
}
/*****************************************************************************/
/* State machine actions. */
/*****************************************************************************/
/* Returns 0 if there's nothing to cancel or 1 otherwise. */
static int nn_usock_cancel_io (struct nn_usock *self)
{
int rc;
BOOL brc;
/* For some reason simple CancelIo doesn't seem to work here.
We have to use CancelIoEx instead. */
rc = 0;
if (!nn_worker_op_isidle (&self->in)) {
brc = CancelIoEx (self->p, &self->in.olpd);
win_assert (brc || GetLastError () == ERROR_NOT_FOUND);
rc = 1;
}
if (!nn_worker_op_isidle (&self->out)) {
brc = CancelIoEx (self->p, &self->out.olpd);
win_assert (brc || GetLastError () == ERROR_NOT_FOUND);
rc = 1;
}
return rc;
}
nanomsg-0.8-beta/src/aio/worker.h0000664000175000017500000000453012623652600017665 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_WORKER_INCLUDED
#define NN_WORKER_INCLUDED
#include "fsm.h"
#include "timerset.h"
#if defined NN_HAVE_WINDOWS
#include "worker_win.h"
#else
#include "worker_posix.h"
#endif
#define NN_WORKER_TIMER_TIMEOUT 1
struct nn_worker_timer {
struct nn_fsm *owner;
struct nn_timerset_hndl hndl;
};
void nn_worker_timer_init (struct nn_worker_timer *self,
struct nn_fsm *owner);
void nn_worker_timer_term (struct nn_worker_timer *self);
int nn_worker_timer_isactive (struct nn_worker_timer *self);
#define NN_WORKER_TASK_EXECUTE 1
struct nn_worker_task;
void nn_worker_task_init (struct nn_worker_task *self, int src,
struct nn_fsm *owner);
void nn_worker_task_term (struct nn_worker_task *self);
struct nn_worker;
int nn_worker_init (struct nn_worker *self);
void nn_worker_term (struct nn_worker *self);
void nn_worker_execute (struct nn_worker *self, struct nn_worker_task *task);
void nn_worker_cancel (struct nn_worker *self, struct nn_worker_task *task);
void nn_worker_add_timer (struct nn_worker *self, int timeout,
struct nn_worker_timer *timer);
void nn_worker_rm_timer (struct nn_worker *self,
struct nn_worker_timer *timer);
#endif
nanomsg-0.8-beta/src/aio/worker.c0000664000175000017500000000314512623652600017661 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "worker.h"
#if defined NN_HAVE_WINDOWS
#include "worker_win.inc"
#else
#include "worker_posix.inc"
#endif
void nn_worker_timer_init (struct nn_worker_timer *self, struct nn_fsm *owner)
{
self->owner = owner;
nn_timerset_hndl_init (&self->hndl);
}
void nn_worker_timer_term (struct nn_worker_timer *self)
{
nn_timerset_hndl_term (&self->hndl);
}
int nn_worker_timer_isactive (struct nn_worker_timer *self)
{
return nn_timerset_hndl_isactive (&self->hndl);
}
nanomsg-0.8-beta/src/aio/worker_posix.h0000664000175000017500000000470612623652600021114 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../utils/queue.h"
#include "../utils/mutex.h"
#include "../utils/thread.h"
#include "../utils/efd.h"
#include "poller.h"
#define NN_WORKER_FD_IN NN_POLLER_IN
#define NN_WORKER_FD_OUT NN_POLLER_OUT
#define NN_WORKER_FD_ERR NN_POLLER_ERR
struct nn_worker_fd {
int src;
struct nn_fsm *owner;
struct nn_poller_hndl hndl;
};
void nn_worker_fd_init (struct nn_worker_fd *self, int src,
struct nn_fsm *owner);
void nn_worker_fd_term (struct nn_worker_fd *self);
struct nn_worker_task {
int src;
struct nn_fsm *owner;
struct nn_queue_item item;
};
struct nn_worker {
struct nn_mutex sync;
struct nn_queue tasks;
struct nn_queue_item stop;
struct nn_efd efd;
struct nn_poller poller;
struct nn_poller_hndl efd_hndl;
struct nn_timerset timerset;
struct nn_thread thread;
};
void nn_worker_add_fd (struct nn_worker *self, int s, struct nn_worker_fd *fd);
void nn_worker_rm_fd(struct nn_worker *self, struct nn_worker_fd *fd);
void nn_worker_set_in (struct nn_worker *self, struct nn_worker_fd *fd);
void nn_worker_reset_in (struct nn_worker *self, struct nn_worker_fd *fd);
void nn_worker_set_out (struct nn_worker *self, struct nn_worker_fd *fd);
void nn_worker_reset_out (struct nn_worker *self, struct nn_worker_fd *fd);
nanomsg-0.8-beta/src/aio/worker_posix.inc0000664000175000017500000002012612623652600021430 0ustar00travistravis00000000000000/*
Copyright (c) 2013-2014 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Copyright 2015 Garrett D'Amore
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "ctx.h"
#include "../utils/err.h"
#include "../utils/fast.h"
#include "../utils/cont.h"
#include "../utils/attr.h"
#include "../utils/queue.h"
/* Private functions. */
static void nn_worker_routine (void *arg);
void nn_worker_fd_init (struct nn_worker_fd *self, int src,
struct nn_fsm *owner)
{
self->src = src;
self->owner = owner;
}
void nn_worker_fd_term (NN_UNUSED struct nn_worker_fd *self)
{
}
void nn_worker_add_fd (struct nn_worker *self, int s, struct nn_worker_fd *fd)
{
nn_poller_add (&((struct nn_worker*) self)->poller, s, &fd->hndl);
}
void nn_worker_rm_fd (struct nn_worker *self, struct nn_worker_fd *fd)
{
nn_poller_rm (&((struct nn_worker*) self)->poller, &fd->hndl);
}
void nn_worker_set_in (struct nn_worker *self, struct nn_worker_fd *fd)
{
nn_poller_set_in (&((struct nn_worker*) self)->poller, &fd->hndl);
}
void nn_worker_reset_in (struct nn_worker *self, struct nn_worker_fd *fd)
{
nn_poller_reset_in (&((struct nn_worker*) self)->poller, &fd->hndl);
}
void nn_worker_set_out (struct nn_worker *self, struct nn_worker_fd *fd)
{
nn_poller_set_out (&((struct nn_worker*) self)->poller, &fd->hndl);
}
void nn_worker_reset_out (struct nn_worker *self, struct nn_worker_fd *fd)
{
nn_poller_reset_out (&((struct nn_worker*) self)->poller, &fd->hndl);
}
void nn_worker_add_timer (struct nn_worker *self, int timeout,
struct nn_worker_timer *timer)
{
nn_timerset_add (&((struct nn_worker*) self)->timerset, timeout,
&timer->hndl);
}
void nn_worker_rm_timer (struct nn_worker *self, struct nn_worker_timer *timer)
{
nn_timerset_rm (&((struct nn_worker*) self)->timerset, &timer->hndl);
}
void nn_worker_task_init (struct nn_worker_task *self, int src,
struct nn_fsm *owner)
{
self->src = src;
self->owner = owner;
nn_queue_item_init (&self->item);
}
void nn_worker_task_term (struct nn_worker_task *self)
{
nn_queue_item_term (&self->item);
}
int nn_worker_init (struct nn_worker *self)
{
int rc;
rc = nn_efd_init (&self->efd);
if (rc < 0)
return rc;
nn_mutex_init (&self->sync);
nn_queue_init (&self->tasks);
nn_queue_item_init (&self->stop);
nn_poller_init (&self->poller);
nn_poller_add (&self->poller, nn_efd_getfd (&self->efd), &self->efd_hndl);
nn_poller_set_in (&self->poller, &self->efd_hndl);
nn_timerset_init (&self->timerset);
nn_thread_init (&self->thread, nn_worker_routine, self);
return 0;
}
void nn_worker_term (struct nn_worker *self)
{
/* Ask worker thread to terminate. */
nn_mutex_lock (&self->sync);
nn_queue_push (&self->tasks, &self->stop);
nn_efd_signal (&self->efd);
nn_mutex_unlock (&self->sync);
/* Wait till worker thread terminates. */
nn_thread_term (&self->thread);
/* Clean up. */
nn_timerset_term (&self->timerset);
nn_poller_term (&self->poller);
nn_efd_term (&self->efd);
nn_queue_item_term (&self->stop);
nn_queue_term (&self->tasks);
nn_mutex_term (&self->sync);
}
void nn_worker_execute (struct nn_worker *self, struct nn_worker_task *task)
{
nn_mutex_lock (&self->sync);
nn_queue_push (&self->tasks, &task->item);
nn_efd_signal (&self->efd);
nn_mutex_unlock (&self->sync);
}
void nn_worker_cancel (struct nn_worker *self, struct nn_worker_task *task)
{
nn_mutex_lock (&self->sync);
nn_queue_remove (&self->tasks, &task->item);
nn_mutex_unlock (&self->sync);
}
static void nn_worker_routine (void *arg)
{
int rc;
struct nn_worker *self;
int pevent;
struct nn_poller_hndl *phndl;
struct nn_timerset_hndl *thndl;
struct nn_queue tasks;
struct nn_queue_item *item;
struct nn_worker_task *task;
struct nn_worker_fd *fd;
struct nn_worker_timer *timer;
self = (struct nn_worker*) arg;
/* Infinite loop. It will be interrupted only when the object is
shut down. */
while (1) {
/* Wait for new events and/or timeouts. */
rc = nn_poller_wait (&self->poller,
nn_timerset_timeout (&self->timerset));
errnum_assert (rc == 0, -rc);
/* Process all expired timers. */
while (1) {
rc = nn_timerset_event (&self->timerset, &thndl);
if (rc == -EAGAIN)
break;
errnum_assert (rc == 0, -rc);
timer = nn_cont (thndl, struct nn_worker_timer, hndl);
nn_ctx_enter (timer->owner->ctx);
nn_fsm_feed (timer->owner, -1, NN_WORKER_TIMER_TIMEOUT, timer);
nn_ctx_leave (timer->owner->ctx);
}
/* Process all events from the poller. */
while (1) {
/* Get next poller event, such as IN or OUT. */
rc = nn_poller_event (&self->poller, &pevent, &phndl);
if (nn_slow (rc == -EAGAIN))
break;
/* If there are any new incoming worker tasks, process them. */
if (phndl == &self->efd_hndl) {
nn_assert (pevent == NN_POLLER_IN);
/* Make a local copy of the task queue. This way
the application threads are not blocked and can post new
tasks while the existing tasks are being processed. Also,
new tasks can be posted from within task handlers. */
nn_mutex_lock (&self->sync);
nn_efd_unsignal (&self->efd);
memcpy (&tasks, &self->tasks, sizeof (tasks));
nn_queue_init (&self->tasks);
nn_mutex_unlock (&self->sync);
while (1) {
/* Next worker task. */
item = nn_queue_pop (&tasks);
if (nn_slow (!item))
break;
/* If the worker thread is asked to stop, do so. */
if (nn_slow (item == &self->stop)) {
/* Make sure we remove all the other workers from
the queue, because we're not doing anything with
them. */
while (nn_queue_pop (&tasks) != NULL) {
continue;
}
nn_queue_term (&tasks);
return;
}
/* It's a user-defined task. Notify the user that it has
arrived in the worker thread. */
task = nn_cont (item, struct nn_worker_task, item);
nn_ctx_enter (task->owner->ctx);
nn_fsm_feed (task->owner, task->src,
NN_WORKER_TASK_EXECUTE, task);
nn_ctx_leave (task->owner->ctx);
}
nn_queue_term (&tasks);
continue;
}
/* It's a true I/O event. Invoke the handler. */
fd = nn_cont (phndl, struct nn_worker_fd, hndl);
nn_ctx_enter (fd->owner->ctx);
nn_fsm_feed (fd->owner, fd->src, pevent, fd);
nn_ctx_leave (fd->owner->ctx);
}
}
}
nanomsg-0.8-beta/src/aio/worker_win.h0000664000175000017500000000422612623652600020544 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "fsm.h"
#include "timerset.h"
#include "../utils/win.h"
#include "../utils/thread.h"
struct nn_worker_task {
int src;
struct nn_fsm *owner;
};
#define NN_WORKER_OP_DONE 1
#define NN_WORKER_OP_ERROR 2
struct nn_worker_op {
int src;
struct nn_fsm *owner;
int state;
/* This structure is to be used by the user, not nn_worker_op itself.
Actual usage is specific to the asynchronous operation in question. */
OVERLAPPED olpd;
};
void nn_worker_op_init (struct nn_worker_op *self, int src,
struct nn_fsm *owner);
void nn_worker_op_term (struct nn_worker_op *self);
/* Call this function when asynchronous operation is started.
If 'zeroiserror' is set to 1, zero bytes transferred will be treated
as an error. */
void nn_worker_op_start (struct nn_worker_op *self, int zeroiserror);
int nn_worker_op_isidle (struct nn_worker_op *self);
struct nn_worker {
HANDLE cp;
struct nn_timerset timerset;
struct nn_thread thread;
};
HANDLE nn_worker_getcp (struct nn_worker *self);
nanomsg-0.8-beta/src/aio/worker_win.inc0000664000175000017500000001563112623652600021070 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "ctx.h"
#include "usock.h"
#include "../utils/err.h"
#include "../utils/cont.h"
#include "../utils/fast.h"
#define NN_WORKER_MAX_EVENTS 32
#define NN_WORKER_OP_STATE_IDLE 1
#define NN_WORKER_OP_STATE_ACTIVE 2
#define NN_WORKER_OP_STATE_ACTIVE_ZEROISERROR 3
/* The value of this variable is irrelevant. It's used only as a placeholder
for the address that is used as the 'stop' event ID. */
const int nn_worker_stop = 0;
/* Private functions. */
static void nn_worker_routine (void *arg);
void nn_worker_task_init (struct nn_worker_task *self, int src,
struct nn_fsm *owner)
{
self->src = src;
self->owner = owner;
}
void nn_worker_task_term (struct nn_worker_task *self)
{
}
void nn_worker_op_init (struct nn_worker_op *self, int src,
struct nn_fsm *owner)
{
self->src = src;
self->owner = owner;
self->state = NN_WORKER_OP_STATE_IDLE;
}
void nn_worker_op_term (struct nn_worker_op *self)
{
nn_assert_state (self, NN_WORKER_OP_STATE_IDLE);
}
void nn_worker_op_start (struct nn_worker_op *self, int zeroiserror)
{
nn_assert_state (self, NN_WORKER_OP_STATE_IDLE);
self->state = zeroiserror ? NN_WORKER_OP_STATE_ACTIVE_ZEROISERROR :
NN_WORKER_OP_STATE_ACTIVE;
}
int nn_worker_op_isidle (struct nn_worker_op *self)
{
return self->state == NN_WORKER_OP_STATE_IDLE ? 1 : 0;
}
int nn_worker_init (struct nn_worker *self)
{
self->cp = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL, 0, 0);
win_assert (self->cp);
nn_timerset_init (&self->timerset);
nn_thread_init (&self->thread, nn_worker_routine, self);
return 0;
}
void nn_worker_term (struct nn_worker *self)
{
BOOL brc;
/* Ask worker thread to terminate. */
brc = PostQueuedCompletionStatus (self->cp, 0,
(ULONG_PTR) &nn_worker_stop, NULL);
win_assert (brc);
/* Wait till worker thread terminates. */
nn_thread_term (&self->thread);
nn_timerset_term (&self->timerset);
brc = CloseHandle (self->cp);
win_assert (brc);
}
void nn_worker_execute (struct nn_worker *self, struct nn_worker_task *task)
{
BOOL brc;
brc = PostQueuedCompletionStatus (self->cp, 0, (ULONG_PTR) task, NULL);
win_assert (brc);
}
void nn_worker_add_timer (struct nn_worker *self, int timeout,
struct nn_worker_timer *timer)
{
nn_timerset_add (&((struct nn_worker*) self)->timerset, timeout,
&timer->hndl);
}
void nn_worker_rm_timer (struct nn_worker *self, struct nn_worker_timer *timer)
{
nn_timerset_rm (&((struct nn_worker*) self)->timerset, &timer->hndl);
}
HANDLE nn_worker_getcp (struct nn_worker *self)
{
return self->cp;
}
static void nn_worker_routine (void *arg)
{
int rc;
BOOL brc;
struct nn_worker *self;
int timeout;
ULONG count;
ULONG i;
struct nn_timerset_hndl *thndl;
struct nn_worker_timer *timer;
struct nn_worker_task *task;
struct nn_worker_op *op;
OVERLAPPED_ENTRY entries [NN_WORKER_MAX_EVENTS];
self = (struct nn_worker*) arg;
while (1) {
/* Process all expired timers. */
while (1) {
rc = nn_timerset_event (&self->timerset, &thndl);
if (nn_fast (rc == -EAGAIN))
break;
errnum_assert (rc == 0, -rc);
timer = nn_cont (thndl, struct nn_worker_timer, hndl);
nn_ctx_enter (timer->owner->ctx);
nn_fsm_feed (timer->owner, -1, NN_WORKER_TIMER_TIMEOUT, timer);
nn_ctx_leave (timer->owner->ctx);
}
/* Compute the time interval till next timer expiration. */
timeout = nn_timerset_timeout (&self->timerset);
/* Wait for new events and/or timeouts. */
brc = GetQueuedCompletionStatusEx (self->cp, entries,
NN_WORKER_MAX_EVENTS, &count, timeout < 0 ? INFINITE : timeout,
FALSE);
if (nn_slow (!brc && GetLastError () == WAIT_TIMEOUT))
continue;
win_assert (brc);
for (i = 0; i != count; ++i) {
/* Process I/O completion events. */
if (nn_fast (entries [i].lpOverlapped)) {
op = nn_cont (entries [i].lpOverlapped,
struct nn_worker_op, olpd);
/* The 'Internal' field is actually an NTSTATUS. Report
success and error. Ignore warnings and informational
messages.*/
rc = entries [i].Internal & 0xc0000000;
switch (rc) {
case 0x00000000:
rc = NN_WORKER_OP_DONE;
break;
case 0xc0000000:
rc = NN_WORKER_OP_ERROR;
break;
default:
continue;
}
/* Raise the completion event. */
nn_ctx_enter (op->owner->ctx);
nn_assert (op->state != NN_WORKER_OP_STATE_IDLE);
if (rc != NN_WORKER_OP_ERROR &&
op->state == NN_WORKER_OP_STATE_ACTIVE_ZEROISERROR &&
entries [i].dwNumberOfBytesTransferred == 0)
rc = NN_WORKER_OP_ERROR;
op->state = NN_WORKER_OP_STATE_IDLE;
nn_fsm_feed (op->owner, op->src, rc, op);
nn_ctx_leave (op->owner->ctx);
continue;
}
/* Worker thread shutdown is requested. */
if (nn_slow (entries [i].lpCompletionKey ==
(ULONG_PTR) &nn_worker_stop))
return;
/* Process tasks. */
task = (struct nn_worker_task*) entries [i].lpCompletionKey;
nn_ctx_enter (task->owner->ctx);
nn_fsm_feed (task->owner, task->src,
NN_WORKER_TASK_EXECUTE, task);
nn_ctx_leave (task->owner->ctx);
}
}
}
nanomsg-0.8-beta/src/core/0000775000175000017500000000000012623652617016371 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/core/ep.h0000664000175000017500000000447112623652600017144 0ustar00travistravis00000000000000/*
Copyright (c) 2012 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_EP_INCLUDED
#define NN_EP_INCLUDED
#include "../transport.h"
#include "../aio/fsm.h"
#include "../utils/list.h"
/* Events generated by the nn_ep object. */
#define NN_EP_STOPPED 1
struct nn_ep {
struct nn_fsm fsm;
int state;
struct nn_epbase *epbase;
struct nn_sock *sock;
struct nn_ep_options options;
int eid;
struct nn_list_item item;
char addr [NN_SOCKADDR_MAX + 1];
/* Error state for endpoint */
int last_errno;
};
int nn_ep_init (struct nn_ep *self, int src, struct nn_sock *sock, int eid,
struct nn_transport *transport, int bind, const char *addr);
void nn_ep_term (struct nn_ep *self);
void nn_ep_start (struct nn_ep *self);
void nn_ep_stop (struct nn_ep *self);
void nn_ep_stopped (struct nn_ep *self);
struct nn_ctx *nn_ep_getctx (struct nn_ep *self);
const char *nn_ep_getaddr (struct nn_ep *self);
void nn_ep_getopt (struct nn_ep *self, int level, int option,
void *optval, size_t *optvallen);
int nn_ep_ispeer (struct nn_ep *self, int socktype);
void nn_ep_set_error(struct nn_ep *self, int errnum);
void nn_ep_clear_error(struct nn_ep *self);
void nn_ep_stat_increment(struct nn_ep *self, int name, int increment);
#endif
nanomsg-0.8-beta/src/core/ep.c0000664000175000017500000001547612623652600017146 0ustar00travistravis00000000000000/*
Copyright (c) 2012 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../transport.h"
#include "ep.h"
#include "sock.h"
#include "../utils/err.h"
#include "../utils/cont.h"
#include "../utils/fast.h"
#include "../utils/attr.h"
#include
#define NN_EP_STATE_IDLE 1
#define NN_EP_STATE_ACTIVE 2
#define NN_EP_STATE_STOPPING 3
#define NN_EP_ACTION_STOPPED 1
/* Private functions. */
static void nn_ep_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_ep_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
int nn_ep_init (struct nn_ep *self, int src, struct nn_sock *sock, int eid,
struct nn_transport *transport, int bind, const char *addr)
{
int rc;
nn_fsm_init (&self->fsm, nn_ep_handler, nn_ep_shutdown,
src, self, &sock->fsm);
self->state = NN_EP_STATE_IDLE;
self->epbase = NULL;
self->sock = sock;
self->eid = eid;
self->last_errno = 0;
nn_list_item_init (&self->item);
memcpy (&self->options, &sock->ep_template, sizeof(struct nn_ep_options));
/* Store the textual form of the address. */
nn_assert (strlen (addr) <= NN_SOCKADDR_MAX);
strcpy (self->addr, addr);
/* Create transport-specific part of the endpoint. */
if (bind)
rc = transport->bind ((void*) self, &self->epbase);
else
rc = transport->connect ((void*) self, &self->epbase);
/* Endpoint creation failed. */
if (rc < 0) {
nn_list_item_term (&self->item);
nn_fsm_term (&self->fsm);
return rc;
}
return 0;
}
void nn_ep_term (struct nn_ep *self)
{
nn_assert_state (self, NN_EP_STATE_IDLE);
self->epbase->vfptr->destroy (self->epbase);
nn_list_item_term (&self->item);
nn_fsm_term (&self->fsm);
}
void nn_ep_start (struct nn_ep *self)
{
nn_fsm_start (&self->fsm);
}
void nn_ep_stop (struct nn_ep *self)
{
nn_fsm_stop (&self->fsm);
}
void nn_ep_stopped (struct nn_ep *self)
{
/* TODO: Do the following in a more sane way. */
self->fsm.stopped.fsm = &self->fsm;
self->fsm.stopped.src = NN_FSM_ACTION;
self->fsm.stopped.srcptr = NULL;
self->fsm.stopped.type = NN_EP_ACTION_STOPPED;
nn_ctx_raise (self->fsm.ctx, &self->fsm.stopped);
}
struct nn_ctx *nn_ep_getctx (struct nn_ep *self)
{
return nn_sock_getctx (self->sock);
}
const char *nn_ep_getaddr (struct nn_ep *self)
{
return self->addr;
}
void nn_ep_getopt (struct nn_ep *self, int level, int option,
void *optval, size_t *optvallen)
{
int rc;
rc = nn_sock_getopt_inner (self->sock, level, option, optval, optvallen);
errnum_assert (rc == 0, -rc);
}
int nn_ep_ispeer (struct nn_ep *self, int socktype)
{
return nn_sock_ispeer (self->sock, socktype);
}
static void nn_ep_shutdown (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_ep *ep;
ep = nn_cont (self, struct nn_ep, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
ep->epbase->vfptr->stop (ep->epbase);
ep->state = NN_EP_STATE_STOPPING;
return;
}
if (nn_slow (ep->state == NN_EP_STATE_STOPPING)) {
if (src != NN_FSM_ACTION || type != NN_EP_ACTION_STOPPED)
return;
ep->state = NN_EP_STATE_IDLE;
nn_fsm_stopped (&ep->fsm, NN_EP_STOPPED);
return;
}
nn_fsm_bad_state (ep->state, src, type);
}
static void nn_ep_handler (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_ep *ep;
ep = nn_cont (self, struct nn_ep, fsm);
switch (ep->state) {
/******************************************************************************/
/* IDLE state. */
/******************************************************************************/
case NN_EP_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
ep->state = NN_EP_STATE_ACTIVE;
return;
default:
nn_fsm_bad_action (ep->state, src, type);
}
default:
nn_fsm_bad_source (ep->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/* We don't expect any events in this state. The only thing that can be done */
/* is closing the endpoint. */
/******************************************************************************/
case NN_EP_STATE_ACTIVE:
nn_fsm_bad_source (ep->state, src, type);
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (ep->state, src, type);
}
}
void nn_ep_set_error(struct nn_ep *self, int errnum)
{
if (self->last_errno == errnum)
/* Error is still there, no need to report it again */
return;
if (self->last_errno == 0)
nn_sock_stat_increment (self->sock, NN_STAT_CURRENT_EP_ERRORS, 1);
self->last_errno = errnum;
nn_sock_report_error (self->sock, self, errnum);
}
void nn_ep_clear_error (struct nn_ep *self)
{
if (self->last_errno == 0)
/* Error is already clear, no need to report it */
return;
nn_sock_stat_increment (self->sock, NN_STAT_CURRENT_EP_ERRORS, -1);
self->last_errno = 0;
nn_sock_report_error (self->sock, self, 0);
}
void nn_ep_stat_increment (struct nn_ep *self, int name, int increment)
{
nn_sock_stat_increment (self->sock, name, increment);
}
nanomsg-0.8-beta/src/core/epbase.c0000664000175000017500000000447312623652600017774 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../transport.h"
#include "ep.h"
#include "sock.h"
#include "../utils/attr.h"
void nn_epbase_init (struct nn_epbase *self,
const struct nn_epbase_vfptr *vfptr, void *hint)
{
self->vfptr = vfptr;
self->ep = (struct nn_ep*) hint;
}
void nn_epbase_term (NN_UNUSED struct nn_epbase *self)
{
}
void nn_epbase_stopped (struct nn_epbase *self)
{
nn_ep_stopped (self->ep);
}
struct nn_ctx *nn_epbase_getctx (struct nn_epbase *self)
{
return nn_ep_getctx (self->ep);
}
const char *nn_epbase_getaddr (struct nn_epbase *self)
{
return nn_ep_getaddr (self->ep);
}
void nn_epbase_getopt (struct nn_epbase *self, int level, int option,
void *optval, size_t *optvallen)
{
nn_ep_getopt (self->ep, level, option, optval, optvallen);
}
int nn_epbase_ispeer (struct nn_epbase *self, int socktype)
{
return nn_ep_ispeer (self->ep, socktype);
}
void nn_epbase_set_error (struct nn_epbase *self, int errnum)
{
nn_ep_set_error (self->ep, errnum);
}
void nn_epbase_clear_error (struct nn_epbase *self)
{
nn_ep_clear_error (self->ep);
}
void nn_epbase_stat_increment(struct nn_epbase *self, int name, int increment) {
nn_ep_stat_increment(self->ep, name, increment);
}
nanomsg-0.8-beta/src/core/global.h0000664000175000017500000000264512623652600020001 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_GLOBAL_INCLUDED
#define NN_GLOBAL_INCLUDED
/* Provides access to the list of available transports. */
struct nn_transport *nn_global_transport (int id);
/* Returns the global worker thread pool. */
struct nn_pool *nn_global_getpool ();
int nn_global_print_errors();
#endif
nanomsg-0.8-beta/src/core/global.c0000664000175000017500000012141712623652600017773 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2014 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Copyright 2015 Garrett D'Amore
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../nn.h"
#include "../transport.h"
#include "../protocol.h"
#include "global.h"
#include "sock.h"
#include "ep.h"
#include "../aio/pool.h"
#include "../aio/timer.h"
#include "../utils/err.h"
#include "../utils/alloc.h"
#include "../utils/mutex.h"
#include "../utils/list.h"
#include "../utils/cont.h"
#include "../utils/random.h"
#include "../utils/glock.h"
#include "../utils/chunk.h"
#include "../utils/msg.h"
#include "../utils/attr.h"
#include "../transports/inproc/inproc.h"
#include "../transports/ipc/ipc.h"
#include "../transports/tcp/tcp.h"
#include "../transports/ws/ws.h"
#include "../transports/tcpmux/tcpmux.h"
#include "../protocols/pair/pair.h"
#include "../protocols/pair/xpair.h"
#include "../protocols/pubsub/pub.h"
#include "../protocols/pubsub/sub.h"
#include "../protocols/pubsub/xpub.h"
#include "../protocols/pubsub/xsub.h"
#include "../protocols/reqrep/rep.h"
#include "../protocols/reqrep/req.h"
#include "../protocols/reqrep/xrep.h"
#include "../protocols/reqrep/xreq.h"
#include "../protocols/pipeline/push.h"
#include "../protocols/pipeline/pull.h"
#include "../protocols/pipeline/xpush.h"
#include "../protocols/pipeline/xpull.h"
#include "../protocols/survey/respondent.h"
#include "../protocols/survey/surveyor.h"
#include "../protocols/survey/xrespondent.h"
#include "../protocols/survey/xsurveyor.h"
#include "../protocols/bus/bus.h"
#include "../protocols/bus/xbus.h"
#include "../pubsub.h"
#include "../pipeline.h"
#include
#include
#include
#include
#if defined NN_HAVE_MINGW
#include
#elif defined NN_HAVE_WINDOWS
#define gmtime_r(ptr_numtime, ptr_strtime) gmtime_s(ptr_strtime, ptr_numtime)
#endif
#define NN_HAVE_GMTIME_R
#if defined NN_HAVE_WINDOWS
#include "../utils/win.h"
#else
#include
#endif
/* Max number of concurrent SP sockets. */
#define NN_MAX_SOCKETS 512
/* To save some space, list of unused socket slots uses uint16_t integers to
refer to individual sockets. If there's a need to more that 0x10000 sockets,
the type should be changed to uint32_t or int. */
CT_ASSERT (NN_MAX_SOCKETS <= 0x10000);
#define NN_CTX_FLAG_ZOMBIE 1
#define NN_GLOBAL_SRC_STAT_TIMER 1
#define NN_GLOBAL_STATE_IDLE 1
#define NN_GLOBAL_STATE_ACTIVE 2
#define NN_GLOBAL_STATE_STOPPING_TIMER 3
struct nn_global {
/* The global table of existing sockets. The descriptor representing
the socket is the index to this table. This pointer is also used to
find out whether context is initialised. If it is NULL, context is
uninitialised. */
struct nn_sock **socks;
/* Stack of unused file descriptors. */
uint16_t *unused;
/* Number of actual open sockets in the socket table. */
size_t nsocks;
/* Combination of the flags listed above. */
int flags;
/* List of all available transports. Note that this list is not
dynamic; i.e. it is created during global initialization and
is never modified. */
struct nn_list transports;
/* List of all available socket types. Again this list is not dynamic.*/
struct nn_list socktypes;
/* Pool of worker threads. */
struct nn_pool pool;
/* Timer and other machinery for submitting statistics */
struct nn_ctx ctx;
struct nn_fsm fsm;
int state;
struct nn_timer stat_timer;
int print_errors;
int print_statistics;
/* Special socket ids */
int statistics_socket;
/* Application name for statistics */
char hostname[64];
char appname[64];
};
/* Singleton object containing the global state of the library. */
static struct nn_global self;
/* Context creation- and termination-related private functions. */
static void nn_global_init (void);
static void nn_global_term (void);
/* Transport-related private functions. */
static void nn_global_add_transport (struct nn_transport *transport);
static void nn_global_add_socktype (struct nn_socktype *socktype);
/* Private function that unifies nn_bind and nn_connect functionality.
It returns the ID of the newly created endpoint. */
static int nn_global_create_ep (struct nn_sock *, const char *addr, int bind);
/* Private socket creator which doesn't initialize global state and
does no locking by itself */
static int nn_global_create_socket (int domain, int protocol);
/* FSM callbacks */
static void nn_global_handler (struct nn_fsm *self,
int src, int type, void *srcptr);
static void nn_global_shutdown (struct nn_fsm *self,
int src, int type, void *srcptr);
/* Socket holds. */
static int nn_global_hold_socket(struct nn_sock **sockp, int s);
static int nn_global_hold_socket_locked(struct nn_sock **sockp, int s);
static void nn_global_rele_socket(struct nn_sock *);
int nn_errno (void)
{
return nn_err_errno ();
}
const char *nn_strerror (int errnum)
{
return nn_err_strerror (errnum);
}
static void nn_global_init (void)
{
int i;
char *envvar;
int rc;
char *addr;
#if defined NN_HAVE_WINDOWS
WSADATA data;
#endif
/* Check whether the library was already initialised. If so, do nothing. */
if (self.socks)
return;
/* On Windows, initialise the socket library. */
#if defined NN_HAVE_WINDOWS
rc = WSAStartup (MAKEWORD (2, 2), &data);
nn_assert (rc == 0);
nn_assert (LOBYTE (data.wVersion) == 2 &&
HIBYTE (data.wVersion) == 2);
#endif
/* Initialise the memory allocation subsystem. */
nn_alloc_init ();
/* Seed the pseudo-random number generator. */
nn_random_seed ();
/* Allocate the global table of SP sockets. */
self.socks = nn_alloc ((sizeof (struct nn_sock*) * NN_MAX_SOCKETS) +
(sizeof (uint16_t) * NN_MAX_SOCKETS), "socket table");
alloc_assert (self.socks);
for (i = 0; i != NN_MAX_SOCKETS; ++i)
self.socks [i] = NULL;
self.nsocks = 0;
self.flags = 0;
/* Print connection and accepting errors to the stderr */
envvar = getenv("NN_PRINT_ERRORS");
/* any non-empty string is true */
self.print_errors = envvar && *envvar;
/* Print socket statistics to stderr */
envvar = getenv("NN_PRINT_STATISTICS");
self.print_statistics = envvar && *envvar;
/* Allocate the stack of unused file descriptors. */
self.unused = (uint16_t*) (self.socks + NN_MAX_SOCKETS);
alloc_assert (self.unused);
for (i = 0; i != NN_MAX_SOCKETS; ++i)
self.unused [i] = NN_MAX_SOCKETS - i - 1;
/* Initialise other parts of the global state. */
nn_list_init (&self.transports);
nn_list_init (&self.socktypes);
/* Plug in individual transports. */
nn_global_add_transport (nn_inproc);
nn_global_add_transport (nn_ipc);
nn_global_add_transport (nn_tcp);
nn_global_add_transport (nn_ws);
nn_global_add_transport (nn_tcpmux);
/* Plug in individual socktypes. */
nn_global_add_socktype (nn_pair_socktype);
nn_global_add_socktype (nn_xpair_socktype);
nn_global_add_socktype (nn_pub_socktype);
nn_global_add_socktype (nn_sub_socktype);
nn_global_add_socktype (nn_xpub_socktype);
nn_global_add_socktype (nn_xsub_socktype);
nn_global_add_socktype (nn_rep_socktype);
nn_global_add_socktype (nn_req_socktype);
nn_global_add_socktype (nn_xrep_socktype);
nn_global_add_socktype (nn_xreq_socktype);
nn_global_add_socktype (nn_push_socktype);
nn_global_add_socktype (nn_xpush_socktype);
nn_global_add_socktype (nn_pull_socktype);
nn_global_add_socktype (nn_xpull_socktype);
nn_global_add_socktype (nn_respondent_socktype);
nn_global_add_socktype (nn_surveyor_socktype);
nn_global_add_socktype (nn_xrespondent_socktype);
nn_global_add_socktype (nn_xsurveyor_socktype);
nn_global_add_socktype (nn_bus_socktype);
nn_global_add_socktype (nn_xbus_socktype);
/* Start the worker threads. */
nn_pool_init (&self.pool);
/* Start FSM */
nn_fsm_init_root (&self.fsm, nn_global_handler, nn_global_shutdown,
&self.ctx);
self.state = NN_GLOBAL_STATE_IDLE;
nn_ctx_init (&self.ctx, nn_global_getpool (), NULL);
nn_timer_init (&self.stat_timer, NN_GLOBAL_SRC_STAT_TIMER, &self.fsm);
/* Initializing special sockets. */
addr = getenv ("NN_STATISTICS_SOCKET");
if (addr) {
self.statistics_socket = nn_global_create_socket (AF_SP, NN_PUB);
errno_assert (self.statistics_socket >= 0);
rc = nn_global_create_ep (self.socks[self.statistics_socket], addr, 0);
errno_assert (rc >= 0);
} else {
self.statistics_socket = -1;
}
addr = getenv ("NN_APPLICATION_NAME");
if (addr) {
strncpy (self.appname, addr, 63);
self.appname[63] = '\0';
} else {
/* No cross-platform way to find out application binary.
Also, MSVC suggests using _getpid() instead of getpid(),
however, it's not clear whether the former is supported
by older versions of Windows/MSVC. */
#if defined _MSC_VER
#pragma warning (push)
#pragma warning (disable:4996)
#endif
sprintf (self.appname, "nanomsg.%d", getpid());
#if defined _MSC_VER
#pragma warning (pop)
#endif
}
addr = getenv ("NN_HOSTNAME");
if (addr) {
strncpy (self.hostname, addr, 63);
self.hostname[63] = '\0';
} else {
rc = gethostname (self.hostname, 63);
errno_assert (rc == 0);
self.hostname[63] = '\0';
}
nn_fsm_start(&self.fsm);
}
static void nn_global_term (void)
{
#if defined NN_HAVE_WINDOWS
int rc;
#endif
struct nn_list_item *it;
struct nn_transport *tp;
/* If there are no sockets remaining, uninitialise the global context. */
nn_assert (self.socks);
if (self.nsocks > 0)
return;
/* Stop the FSM */
nn_ctx_enter (&self.ctx);
nn_fsm_stop (&self.fsm);
nn_ctx_leave (&self.ctx);
/* Shut down the worker threads. */
nn_pool_term (&self.pool);
/* Terminate ctx mutex */
nn_ctx_term (&self.ctx);
/* Ask all the transport to deallocate their global resources. */
while (!nn_list_empty (&self.transports)) {
it = nn_list_begin (&self.transports);
tp = nn_cont (it, struct nn_transport, item);
if (tp->term)
tp->term ();
nn_list_erase (&self.transports, it);
}
/* For now there's nothing to deallocate about socket types, however,
let's remove them from the list anyway. */
while (!nn_list_empty (&self.socktypes))
nn_list_erase (&self.socktypes, nn_list_begin (&self.socktypes));
/* Final deallocation of the nn_global object itself. */
nn_list_term (&self.socktypes);
nn_list_term (&self.transports);
nn_free (self.socks);
/* This marks the global state as uninitialised. */
self.socks = NULL;
/* Shut down the memory allocation subsystem. */
nn_alloc_term ();
/* On Windows, uninitialise the socket library. */
#if defined NN_HAVE_WINDOWS
rc = WSACleanup ();
nn_assert (rc == 0);
#endif
}
void nn_term (void)
{
int i;
nn_glock_lock ();
/* Switch the global state into the zombie state. */
self.flags |= NN_CTX_FLAG_ZOMBIE;
/* Mark all open sockets as terminating. */
if (self.socks && self.nsocks) {
for (i = 0; i != NN_MAX_SOCKETS; ++i)
if (self.socks [i])
nn_sock_zombify (self.socks [i]);
}
nn_glock_unlock ();
}
void *nn_allocmsg (size_t size, int type)
{
int rc;
void *result;
rc = nn_chunk_alloc (size, type, &result);
if (rc == 0)
return result;
errno = -rc;
return NULL;
}
void *nn_reallocmsg (void *msg, size_t size)
{
int rc;
rc = nn_chunk_realloc (size, &msg);
if (rc == 0)
return msg;
errno = -rc;
return NULL;
}
int nn_freemsg (void *msg)
{
nn_chunk_free (msg);
return 0;
}
struct nn_cmsghdr *nn_cmsg_nxthdr_ (const struct nn_msghdr *mhdr,
const struct nn_cmsghdr *cmsg)
{
char *data;
size_t sz;
struct nn_cmsghdr *next;
size_t headsz;
/* Early return if no message is provided. */
if (nn_slow (mhdr == NULL))
return NULL;
/* Get the actual data. */
if (mhdr->msg_controllen == NN_MSG) {
data = *((void**) mhdr->msg_control);
sz = nn_chunk_size (data);
}
else {
data = (char*) mhdr->msg_control;
sz = mhdr->msg_controllen;
}
/* Ancillary data allocation was not even large enough for one element. */
if (nn_slow (sz < NN_CMSG_SPACE (0)))
return NULL;
/* If cmsg is set to NULL we are going to return first property.
Otherwise move to the next property. */
if (!cmsg)
next = (struct nn_cmsghdr*) data;
else
next = (struct nn_cmsghdr*)
(((char*) cmsg) + NN_CMSG_ALIGN_ (cmsg->cmsg_len));
/* If there's no space for next property, treat it as the end
of the property list. */
headsz = ((char*) next) - data;
if (headsz + NN_CMSG_SPACE (0) > sz ||
headsz + NN_CMSG_ALIGN_ (next->cmsg_len) > sz)
return NULL;
/* Success. */
return next;
}
int nn_global_create_socket (int domain, int protocol)
{
int rc;
int s;
struct nn_list_item *it;
struct nn_socktype *socktype;
struct nn_sock *sock;
/* The function is called with nn_glock held */
/* Only AF_SP and AF_SP_RAW domains are supported. */
if (nn_slow (domain != AF_SP && domain != AF_SP_RAW)) {
return -EAFNOSUPPORT;
}
/* If socket limit was reached, report error. */
if (nn_slow (self.nsocks >= NN_MAX_SOCKETS)) {
return -EMFILE;
}
/* Find an empty socket slot. */
s = self.unused [NN_MAX_SOCKETS - self.nsocks - 1];
/* Find the appropriate socket type. */
for (it = nn_list_begin (&self.socktypes);
it != nn_list_end (&self.socktypes);
it = nn_list_next (&self.socktypes, it)) {
socktype = nn_cont (it, struct nn_socktype, item);
if (socktype->domain == domain && socktype->protocol == protocol) {
/* Instantiate the socket. */
sock = nn_alloc (sizeof (struct nn_sock), "sock");
alloc_assert (sock);
rc = nn_sock_init (sock, socktype, s);
if (rc < 0)
return rc;
/* Adjust the global socket table. */
self.socks [s] = sock;
++self.nsocks;
return s;
}
}
/* Specified socket type wasn't found. */
return -EINVAL;
}
int nn_socket (int domain, int protocol)
{
int rc;
nn_glock_lock ();
/* If nn_term() was already called, return ETERM. */
if (nn_slow (self.flags & NN_CTX_FLAG_ZOMBIE)) {
nn_glock_unlock ();
errno = ETERM;
return -1;
}
/* Make sure that global state is initialised. */
nn_global_init ();
rc = nn_global_create_socket (domain, protocol);
if (rc < 0) {
nn_global_term ();
nn_glock_unlock ();
errno = -rc;
return -1;
}
nn_glock_unlock();
return rc;
}
int nn_close (int s)
{
int rc;
struct nn_sock *sock;
nn_glock_lock ();
rc = nn_global_hold_socket_locked (&sock, s);
if (nn_slow (rc < 0)) {
nn_glock_unlock ();
errno = -rc;
return -1;
}
/* Start the shutdown process on the socket. This will cause
all other socket users, as well as endpoints, to begin cleaning up.
This is done with the glock held to ensure that two instances
of nn_close can't access the same socket. */
nn_sock_stop (sock);
nn_glock_unlock ();
/* We have to drop both the hold we just acquired, as well as
the original hold, in order for nn_sock_term to complete. */
nn_sock_rele (sock);
nn_sock_rele (sock);
/* Now clean up. The termination routine below will block until
all other consumers of the socket have dropped their holds, and
all endpoints have cleanly exited. */
rc = nn_sock_term (sock);
if (nn_slow (rc == -EINTR)) {
nn_global_rele_socket (sock);
errno = EINTR;
return -1;
}
/* Remove the socket from the socket table, add it to unused socket
table. */
nn_glock_lock ();
self.socks [s] = NULL;
self.unused [NN_MAX_SOCKETS - self.nsocks] = s;
--self.nsocks;
nn_free (sock);
/* Destroy the global context if there's no socket remaining. */
nn_global_term ();
nn_glock_unlock ();
return 0;
}
int nn_setsockopt (int s, int level, int option, const void *optval,
size_t optvallen)
{
int rc;
struct nn_sock *sock;
rc = nn_global_hold_socket (&sock, s);
if (nn_slow (rc < 0)) {
errno = -rc;
return -1;
}
if (nn_slow (!optval && optvallen)) {
rc = -EFAULT;
goto fail;
}
rc = nn_sock_setopt (sock, level, option, optval, optvallen);
if (nn_slow (rc < 0))
goto fail;
errnum_assert (rc == 0, -rc);
nn_global_rele_socket (sock);
return 0;
fail:
nn_global_rele_socket (sock);
errno = -rc;
return -1;
}
int nn_getsockopt (int s, int level, int option, void *optval,
size_t *optvallen)
{
int rc;
struct nn_sock *sock;
rc = nn_global_hold_socket (&sock, s);
if (nn_slow (rc < 0)) {
errno = -rc;
return -1;
}
if (nn_slow (!optval && optvallen)) {
rc = -EFAULT;
goto fail;
}
rc = nn_sock_getopt (sock, level, option, optval, optvallen);
if (nn_slow (rc < 0))
goto fail;
errnum_assert (rc == 0, -rc);
nn_global_rele_socket (sock);
return 0;
fail:
nn_global_rele_socket (sock);
errno = -rc;
return -1;
}
int nn_bind (int s, const char *addr)
{
int rc;
struct nn_sock *sock;
rc = nn_global_hold_socket (&sock, s);
if (rc < 0) {
errno = -rc;
return -1;
}
rc = nn_global_create_ep (sock, addr, 1);
if (nn_slow (rc < 0)) {
nn_global_rele_socket (sock);
errno = -rc;
return -1;
}
nn_global_rele_socket (sock);
return rc;
}
int nn_connect (int s, const char *addr)
{
int rc;
struct nn_sock *sock;
rc = nn_global_hold_socket (&sock, s);
if (nn_slow (rc < 0)) {
errno = -rc;
return -1;
}
rc = nn_global_create_ep (sock, addr, 0);
if (rc < 0) {
nn_global_rele_socket (sock);
errno = -rc;
return -1;
}
nn_global_rele_socket (sock);
return rc;
}
int nn_shutdown (int s, int how)
{
int rc;
struct nn_sock *sock;
rc = nn_global_hold_socket (&sock, s);
if (nn_slow (rc < 0)) {
errno = -rc;
return -1;
}
rc = nn_sock_rm_ep (sock, how);
if (nn_slow (rc < 0)) {
nn_global_rele_socket (sock);
errno = -rc;
return -1;
}
nn_assert (rc == 0);
nn_global_rele_socket (sock);
return 0;
}
int nn_send (int s, const void *buf, size_t len, int flags)
{
struct nn_iovec iov;
struct nn_msghdr hdr;
iov.iov_base = (void*) buf;
iov.iov_len = len;
hdr.msg_iov = &iov;
hdr.msg_iovlen = 1;
hdr.msg_control = NULL;
hdr.msg_controllen = 0;
return nn_sendmsg (s, &hdr, flags);
}
int nn_recv (int s, void *buf, size_t len, int flags)
{
struct nn_iovec iov;
struct nn_msghdr hdr;
iov.iov_base = buf;
iov.iov_len = len;
hdr.msg_iov = &iov;
hdr.msg_iovlen = 1;
hdr.msg_control = NULL;
hdr.msg_controllen = 0;
return nn_recvmsg (s, &hdr, flags);
}
int nn_sendmsg (int s, const struct nn_msghdr *msghdr, int flags)
{
int rc;
size_t sz;
size_t spsz;
int i;
struct nn_iovec *iov;
struct nn_msg msg;
void *chunk;
int nnmsg;
struct nn_cmsghdr *cmsg;
struct nn_sock *sock;
rc = nn_global_hold_socket (&sock, s);
if (nn_slow (rc < 0)) {
errno = -rc;
return -1;
}
if (nn_slow (!msghdr)) {
rc = -EINVAL;
goto fail;
}
if (nn_slow (msghdr->msg_iovlen < 0)) {
rc = -EMSGSIZE;
goto fail;
}
if (msghdr->msg_iovlen == 1 && msghdr->msg_iov [0].iov_len == NN_MSG) {
chunk = *(void**) msghdr->msg_iov [0].iov_base;
if (nn_slow (chunk == NULL)) {
rc = -EFAULT;
goto fail;
}
sz = nn_chunk_size (chunk);
nn_msg_init_chunk (&msg, chunk);
nnmsg = 1;
}
else {
/* Compute the total size of the message. */
sz = 0;
for (i = 0; i != msghdr->msg_iovlen; ++i) {
iov = &msghdr->msg_iov [i];
if (nn_slow (iov->iov_len == NN_MSG)) {
rc = -EINVAL;
goto fail;
}
if (nn_slow (!iov->iov_base && iov->iov_len)) {
rc = -EFAULT;
goto fail;
}
if (nn_slow (sz + iov->iov_len < sz)) {
rc = -EINVAL;
goto fail;
}
sz += iov->iov_len;
}
/* Create a message object from the supplied scatter array. */
nn_msg_init (&msg, sz);
sz = 0;
for (i = 0; i != msghdr->msg_iovlen; ++i) {
iov = &msghdr->msg_iov [i];
memcpy (((uint8_t*) nn_chunkref_data (&msg.body)) + sz,
iov->iov_base, iov->iov_len);
sz += iov->iov_len;
}
nnmsg = 0;
}
/* Add ancillary data to the message. */
if (msghdr->msg_control) {
/* Copy all headers. */
/* TODO: SP_HDR should not be copied here! */
if (msghdr->msg_controllen == NN_MSG) {
chunk = *((void**) msghdr->msg_control);
nn_chunkref_term (&msg.hdrs);
nn_chunkref_init_chunk (&msg.hdrs, chunk);
}
else {
nn_chunkref_term (&msg.hdrs);
nn_chunkref_init (&msg.hdrs, msghdr->msg_controllen);
memcpy (nn_chunkref_data (&msg.hdrs),
msghdr->msg_control, msghdr->msg_controllen);
}
/* Search for SP_HDR property. */
cmsg = NN_CMSG_FIRSTHDR (msghdr);
while (cmsg) {
if (cmsg->cmsg_level == PROTO_SP && cmsg->cmsg_type == SP_HDR) {
unsigned char *ptr = NN_CMSG_DATA (cmsg);
size_t clen = cmsg->cmsg_len - NN_CMSG_SPACE (0);
if (clen > sizeof (size_t)) {
spsz = *(size_t *)(void *)ptr;
if (spsz <= (clen - sizeof (size_t))) {
/* Copy body of SP_HDR property into 'sphdr'. */
nn_chunkref_term (&msg.sphdr);
nn_chunkref_init (&msg.sphdr, spsz);
memcpy (nn_chunkref_data (&msg.sphdr),
ptr + sizeof (size_t), spsz);
}
}
break;
}
cmsg = NN_CMSG_NXTHDR (msghdr, cmsg);
}
}
/* Send it further down the stack. */
rc = nn_sock_send (sock, &msg, flags);
if (nn_slow (rc < 0)) {
/* If we are dealing with user-supplied buffer, detach it from
the message object. */
if (nnmsg)
nn_chunkref_init (&msg.body, 0);
nn_msg_term (&msg);
goto fail;
}
/* Adjust the statistics. */
nn_sock_stat_increment (sock, NN_STAT_MESSAGES_SENT, 1);
nn_sock_stat_increment (sock, NN_STAT_BYTES_SENT, sz);
nn_global_rele_socket (sock);
return (int) sz;
fail:
nn_global_rele_socket (sock);
errno = -rc;
return -1;
}
int nn_recvmsg (int s, struct nn_msghdr *msghdr, int flags)
{
int rc;
struct nn_msg msg;
uint8_t *data;
size_t sz;
int i;
struct nn_iovec *iov;
void *chunk;
size_t hdrssz;
void *ctrl;
size_t ctrlsz;
size_t spsz;
size_t sptotalsz;
struct nn_cmsghdr *chdr;
struct nn_sock *sock;
rc = nn_global_hold_socket (&sock, s);
if (nn_slow (rc < 0)) {
errno = -rc;
return -1;
}
if (nn_slow (!msghdr)) {
rc = -EINVAL;
goto fail;
}
if (nn_slow (msghdr->msg_iovlen < 0)) {
rc = -EMSGSIZE;
goto fail;
}
/* Get a message. */
rc = nn_sock_recv (sock, &msg, flags);
if (nn_slow (rc < 0)) {
goto fail;
}
if (msghdr->msg_iovlen == 1 && msghdr->msg_iov [0].iov_len == NN_MSG) {
chunk = nn_chunkref_getchunk (&msg.body);
*(void**) (msghdr->msg_iov [0].iov_base) = chunk;
sz = nn_chunk_size (chunk);
}
else {
/* Copy the message content into the supplied gather array. */
data = nn_chunkref_data (&msg.body);
sz = nn_chunkref_size (&msg.body);
for (i = 0; i != msghdr->msg_iovlen; ++i) {
iov = &msghdr->msg_iov [i];
if (nn_slow (iov->iov_len == NN_MSG)) {
nn_msg_term (&msg);
rc = -EINVAL;
goto fail;
}
if (iov->iov_len > sz) {
memcpy (iov->iov_base, data, sz);
break;
}
memcpy (iov->iov_base, data, iov->iov_len);
data += iov->iov_len;
sz -= iov->iov_len;
}
sz = nn_chunkref_size (&msg.body);
}
/* Retrieve the ancillary data from the message. */
if (msghdr->msg_control) {
spsz = nn_chunkref_size (&msg.sphdr);
sptotalsz = NN_CMSG_SPACE (spsz+sizeof (size_t));
ctrlsz = sptotalsz + nn_chunkref_size (&msg.hdrs);
if (msghdr->msg_controllen == NN_MSG) {
/* Allocate the buffer. */
rc = nn_chunk_alloc (ctrlsz, 0, &ctrl);
errnum_assert (rc == 0, -rc);
/* Set output parameters. */
*((void**) msghdr->msg_control) = ctrl;
}
else {
/* Just use the buffer supplied by the user. */
ctrl = msghdr->msg_control;
ctrlsz = msghdr->msg_controllen;
}
/* If SP header alone won't fit into the buffer, return no ancillary
properties. */
if (ctrlsz >= sptotalsz) {
char *ptr;
/* Fill in SP_HDR ancillary property. */
chdr = (struct nn_cmsghdr*) ctrl;
chdr->cmsg_len = sptotalsz;
chdr->cmsg_level = PROTO_SP;
chdr->cmsg_type = SP_HDR;
ptr = (void *)chdr;
ptr += sizeof (*chdr);
*(size_t *)(void *)ptr = spsz;
ptr += sizeof (size_t);
memcpy (ptr, nn_chunkref_data (&msg.sphdr), spsz);
/* Fill in as many remaining properties as possible.
Truncate the trailing properties if necessary. */
hdrssz = nn_chunkref_size (&msg.hdrs);
if (hdrssz > ctrlsz - sptotalsz)
hdrssz = ctrlsz - sptotalsz;
memcpy (((char*) ctrl) + sptotalsz,
nn_chunkref_data (&msg.hdrs), hdrssz);
}
}
nn_msg_term (&msg);
/* Adjust the statistics. */
nn_sock_stat_increment (sock, NN_STAT_MESSAGES_RECEIVED, 1);
nn_sock_stat_increment (sock, NN_STAT_BYTES_RECEIVED, sz);
nn_global_rele_socket (sock);
return (int) sz;
fail:
nn_global_rele_socket (sock);
errno = -rc;
return -1;
}
static void nn_global_add_transport (struct nn_transport *transport)
{
if (transport->init)
transport->init ();
nn_list_insert (&self.transports, &transport->item,
nn_list_end (&self.transports));
}
static void nn_global_add_socktype (struct nn_socktype *socktype)
{
nn_list_insert (&self.socktypes, &socktype->item,
nn_list_end (&self.socktypes));
}
static void nn_global_submit_counter (int i, struct nn_sock *s,
char *name, uint64_t value)
{
/* Length of buffer is:
len(hostname) + len(appname) + len(socket_name) + len(timebuf)
+ len(str(value)) + len(static characters)
63 + 63 + 63 + 20 + 20 + 60 = 289 */
char buf[512];
char timebuf[20];
time_t numtime;
struct tm strtime;
int len;
if(self.print_statistics) {
fprintf(stderr, "nanomsg: socket.%s: %s: %llu\n",
s->socket_name, name, (long long unsigned int)value);
}
if (self.statistics_socket >= 0) {
/* TODO(tailhook) add HAVE_GMTIME_R ifdef */
time(&numtime);
#ifdef NN_HAVE_GMTIME_R
gmtime_r (&numtime, &strtime);
#else
#error
#endif
strftime (timebuf, 20, "%Y-%m-%dT%H:%M:%S", &strtime);
if(*s->socket_name) {
len = sprintf (buf, "ESTP:%s:%s:socket.%s:%s: %sZ 10 %llu:c",
self.hostname, self.appname, s->socket_name, name,
timebuf, (long long unsigned int)value);
} else {
len = sprintf (buf, "ESTP:%s:%s:socket.%d:%s: %sZ 10 %llu:c",
self.hostname, self.appname, i, name,
timebuf, (long long unsigned int)value);
}
nn_assert (len < (int)sizeof(buf));
(void) nn_send (self.statistics_socket, buf, len, NN_DONTWAIT);
}
}
static void nn_global_submit_level (int i, struct nn_sock *s,
char *name, int value)
{
/* Length of buffer is:
len(hostname) + len(appname) + len(socket_name) + len(timebuf)
+ len(str(value)) + len(static characters)
63 + 63 + 63 + 20 + 20 + 60 = 289 */
char buf[512];
char timebuf[20];
time_t numtime;
struct tm strtime;
int len;
if(self.print_statistics) {
fprintf(stderr, "nanomsg: socket.%s: %s: %d\n",
s->socket_name, name, value);
}
if (self.statistics_socket >= 0) {
/* TODO(tailhook) add HAVE_GMTIME_R ifdef */
time(&numtime);
#ifdef NN_HAVE_GMTIME_R
gmtime_r (&numtime, &strtime);
#else
#error
#endif
strftime (timebuf, 20, "%Y-%m-%dT%H:%M:%S", &strtime);
if(*s->socket_name) {
len = sprintf (buf, "ESTP:%s:%s:socket.%s:%s: %sZ 10 %d",
self.hostname, self.appname, s->socket_name, name,
timebuf, value);
} else {
len = sprintf (buf, "ESTP:%s:%s:socket.%d:%s: %sZ 10 %d",
self.hostname, self.appname, i, name,
timebuf, value);
}
nn_assert (len < (int)sizeof(buf));
(void) nn_send (self.statistics_socket, buf, len, NN_DONTWAIT);
}
}
static void nn_global_submit_errors (int i, struct nn_sock *s,
char *name, int value)
{
/* TODO(tailhook) dynamically allocate buffer */
char buf[4096];
char *curbuf;
int buf_left;
char timebuf[20];
time_t numtime;
struct tm strtime;
int len;
struct nn_list_item *it;
struct nn_ep *ep;
if (self.statistics_socket >= 0) {
/* TODO(tailhook) add HAVE_GMTIME_R ifdef */
time(&numtime);
#ifdef NN_HAVE_GMTIME_R
gmtime_r (&numtime, &strtime);
#else
#error
#endif
strftime (timebuf, 20, "%Y-%m-%dT%H:%M:%S", &strtime);
if(*s->socket_name) {
len = sprintf (buf, "ESTP:%s:%s:socket.%s:%s: %sZ 10 %d\n",
self.hostname, self.appname, s->socket_name, name,
timebuf, value);
} else {
len = sprintf (buf, "ESTP:%s:%s:socket.%d:%s: %sZ 10 %d\n",
self.hostname, self.appname, i, name,
timebuf, value);
}
buf_left = sizeof(buf) - len;
curbuf = buf + len;
for (it = nn_list_begin (&s->eps);
it != nn_list_end (&s->eps);
it = nn_list_next (&s->eps, it)) {
ep = nn_cont (it, struct nn_ep, item);
if (ep->last_errno) {
#ifdef NN_HAVE_WINDOWS
len = _snprintf_s (curbuf, buf_left, _TRUNCATE,
" nanomsg: Endpoint %d [%s] error: %s\n",
ep->eid, nn_ep_getaddr (ep), nn_strerror (ep->last_errno));
#else
len = snprintf (curbuf, buf_left,
" nanomsg: Endpoint %d [%s] error: %s\n",
ep->eid, nn_ep_getaddr (ep), nn_strerror (ep->last_errno));
#endif
if (buf_left < len)
break;
curbuf += len;
buf_left -= len;
}
}
(void) nn_send (self.statistics_socket,
buf, sizeof(buf) - buf_left, NN_DONTWAIT);
}
}
static void nn_global_submit_statistics ()
{
int i;
struct nn_sock *s;
/* TODO(tailhook) optimized it to use nsocks and unused */
for(i = 0; i < NN_MAX_SOCKETS; ++i) {
nn_glock_lock ();
s = self.socks [i];
if (!s) {
nn_glock_unlock ();
continue;
}
if (i == self.statistics_socket) {
nn_glock_unlock ();
continue;
}
nn_ctx_enter (&s->ctx);
nn_glock_unlock ();
nn_global_submit_counter (i, s,
"established_connections", s->statistics.established_connections);
nn_global_submit_counter (i, s,
"accepted_connections", s->statistics.accepted_connections);
nn_global_submit_counter (i, s,
"dropped_connections", s->statistics.dropped_connections);
nn_global_submit_counter (i, s,
"broken_connections", s->statistics.broken_connections);
nn_global_submit_counter (i, s,
"connect_errors", s->statistics.connect_errors);
nn_global_submit_counter (i, s,
"bind_errors", s->statistics.bind_errors);
nn_global_submit_counter (i, s,
"accept_errors", s->statistics.accept_errors);
nn_global_submit_counter (i, s,
"messages_sent", s->statistics.messages_sent);
nn_global_submit_counter (i, s,
"messages_received", s->statistics.messages_received);
nn_global_submit_counter (i, s,
"bytes_sent", s->statistics.bytes_sent);
nn_global_submit_counter (i, s,
"bytes_received", s->statistics.bytes_received);
nn_global_submit_level (i, s,
"current_connections", s->statistics.current_connections);
nn_global_submit_level (i, s,
"inprogress_connections", s->statistics.inprogress_connections);
nn_global_submit_level (i, s,
"current_snd_priority", s->statistics.current_snd_priority);
nn_global_submit_errors (i, s,
"current_ep_errors", s->statistics.current_ep_errors);
nn_ctx_leave (&s->ctx);
}
}
static int nn_global_create_ep (struct nn_sock *sock, const char *addr,
int bind)
{
int rc;
const char *proto;
const char *delim;
size_t protosz;
struct nn_transport *tp;
struct nn_list_item *it;
/* Check whether address is valid. */
if (!addr)
return -EINVAL;
if (strlen (addr) >= NN_SOCKADDR_MAX)
return -ENAMETOOLONG;
/* Separate the protocol and the actual address. */
proto = addr;
delim = strchr (addr, ':');
if (!delim)
return -EINVAL;
if (delim [1] != '/' || delim [2] != '/')
return -EINVAL;
protosz = delim - addr;
addr += protosz + 3;
/* Find the specified protocol. */
tp = NULL;
for (it = nn_list_begin (&self.transports);
it != nn_list_end (&self.transports);
it = nn_list_next (&self.transports, it)) {
tp = nn_cont (it, struct nn_transport, item);
if (strlen (tp->name) == protosz &&
memcmp (tp->name, proto, protosz) == 0)
break;
tp = NULL;
}
/* The protocol specified doesn't match any known protocol. */
if (!tp) {
return -EPROTONOSUPPORT;
}
/* Ask the socket to create the endpoint. */
rc = nn_sock_add_ep (sock, tp, bind, addr);
return rc;
}
struct nn_transport *nn_global_transport (int id)
{
struct nn_transport *tp;
struct nn_list_item *it;
/* Find the specified protocol. */
tp = NULL;
for (it = nn_list_begin (&self.transports);
it != nn_list_end (&self.transports);
it = nn_list_next (&self.transports, it)) {
tp = nn_cont (it, struct nn_transport, item);
if (tp->id == id)
break;
tp = NULL;
}
return tp;
}
struct nn_pool *nn_global_getpool ()
{
return &self.pool;
}
static void nn_global_handler (struct nn_fsm *self,
int src, int type, NN_UNUSED void *srcptr)
{
struct nn_global *global;
global = nn_cont (self, struct nn_global, fsm);
switch (global->state) {
/******************************************************************************/
/* IDLE state. */
/* The state machine wasn't yet started. */
/******************************************************************************/
case NN_GLOBAL_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
global->state = NN_GLOBAL_STATE_ACTIVE;
if (global->print_statistics || global->statistics_socket >= 0)
{
/* Start statistics collection timer. */
nn_timer_start (&global->stat_timer, 10000);
}
return;
default:
nn_fsm_bad_action (global->state, src, type);
}
default:
nn_fsm_bad_source (global->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/* Normal lifetime for global object. */
/******************************************************************************/
case NN_GLOBAL_STATE_ACTIVE:
switch (src) {
case NN_GLOBAL_SRC_STAT_TIMER:
switch (type) {
case NN_TIMER_TIMEOUT:
nn_global_submit_statistics ();
/* No need to change state */
nn_timer_stop (&global->stat_timer);
return;
case NN_TIMER_STOPPED:
nn_timer_start (&global->stat_timer, 10000);
return;
default:
nn_fsm_bad_action (global->state, src, type);
}
default:
nn_fsm_bad_source (global->state, src, type);
}
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (global->state, src, type);
}
}
static void nn_global_shutdown (struct nn_fsm *self,
NN_UNUSED int src, NN_UNUSED int type, NN_UNUSED void *srcptr)
{
struct nn_global *global;
global = nn_cont (self, struct nn_global, fsm);
nn_assert (global->state == NN_GLOBAL_STATE_ACTIVE
|| global->state == NN_GLOBAL_STATE_IDLE);
if (global->state == NN_GLOBAL_STATE_ACTIVE) {
if (!nn_timer_isidle (&global->stat_timer)) {
nn_timer_stop (&global->stat_timer);
return;
}
}
}
int nn_global_print_errors () {
return self.print_errors;
}
/* Get the socket structure for a socket id. This must be called under
the global lock (nn_glock_lock.) The socket itself will not be freed
while the hold is active. */
int nn_global_hold_socket_locked(struct nn_sock **sockp, int s)
{
struct nn_sock *sock;
if (nn_slow (self.socks == NULL)) {
*sockp = NULL;
return -ETERM;
}
if (nn_slow ((self.flags & NN_CTX_FLAG_ZOMBIE) != 0)) {
*sockp = NULL;
return -ETERM;
}
if (nn_slow (s < 0 || s >= NN_MAX_SOCKETS))
return -EBADF;
sock = self.socks[s];
if (nn_slow (sock == NULL))
return -EBADF;
if (nn_slow (nn_sock_hold (sock) != 0)) {
return -EBADF;
}
*sockp = sock;
return 0;
}
int nn_global_hold_socket(struct nn_sock **sockp, int s)
{
int rc;
nn_glock_lock();
rc = nn_global_hold_socket_locked(sockp, s);
nn_glock_unlock();
return rc;
}
void nn_global_rele_socket(struct nn_sock *sock)
{
nn_glock_lock();
nn_sock_rele(sock);
nn_glock_unlock();
}
nanomsg-0.8-beta/src/core/pipe.c0000664000175000017500000001557312623652600017475 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../transport.h"
#include "../protocol.h"
#include "sock.h"
#include "ep.h"
#include "../utils/err.h"
#include "../utils/fast.h"
/* Internal pipe states. */
#define NN_PIPEBASE_STATE_IDLE 1
#define NN_PIPEBASE_STATE_ACTIVE 2
#define NN_PIPEBASE_STATE_FAILED 3
#define NN_PIPEBASE_INSTATE_DEACTIVATED 0
#define NN_PIPEBASE_INSTATE_IDLE 1
#define NN_PIPEBASE_INSTATE_RECEIVING 2
#define NN_PIPEBASE_INSTATE_RECEIVED 3
#define NN_PIPEBASE_INSTATE_ASYNC 4
#define NN_PIPEBASE_OUTSTATE_DEACTIVATED 0
#define NN_PIPEBASE_OUTSTATE_IDLE 1
#define NN_PIPEBASE_OUTSTATE_SENDING 2
#define NN_PIPEBASE_OUTSTATE_SENT 3
#define NN_PIPEBASE_OUTSTATE_ASYNC 4
void nn_pipebase_init (struct nn_pipebase *self,
const struct nn_pipebase_vfptr *vfptr, struct nn_epbase *epbase)
{
nn_assert (epbase->ep->sock);
nn_fsm_init (&self->fsm, NULL, NULL, 0, self, &epbase->ep->sock->fsm);
self->vfptr = vfptr;
self->state = NN_PIPEBASE_STATE_IDLE;
self->instate = NN_PIPEBASE_INSTATE_DEACTIVATED;
self->outstate = NN_PIPEBASE_OUTSTATE_DEACTIVATED;
self->sock = epbase->ep->sock;
memcpy (&self->options, &epbase->ep->options,
sizeof (struct nn_ep_options));
nn_fsm_event_init (&self->in);
nn_fsm_event_init (&self->out);
}
void nn_pipebase_term (struct nn_pipebase *self)
{
nn_assert_state (self, NN_PIPEBASE_STATE_IDLE);
nn_fsm_event_term (&self->out);
nn_fsm_event_term (&self->in);
nn_fsm_term (&self->fsm);
}
int nn_pipebase_start (struct nn_pipebase *self)
{
int rc;
nn_assert_state (self, NN_PIPEBASE_STATE_IDLE);
self->state = NN_PIPEBASE_STATE_ACTIVE;
self->instate = NN_PIPEBASE_INSTATE_ASYNC;
self->outstate = NN_PIPEBASE_OUTSTATE_IDLE;
rc = nn_sock_add (self->sock, (struct nn_pipe*) self);
if (nn_slow (rc < 0)) {
self->state = NN_PIPEBASE_STATE_FAILED;
return rc;
}
if (self->sock)
nn_fsm_raise (&self->fsm, &self->out, NN_PIPE_OUT);
return 0;
}
void nn_pipebase_stop (struct nn_pipebase *self)
{
if (self->state == NN_PIPEBASE_STATE_ACTIVE)
nn_sock_rm (self->sock, (struct nn_pipe*) self);
self->state = NN_PIPEBASE_STATE_IDLE;
}
void nn_pipebase_received (struct nn_pipebase *self)
{
if (nn_fast (self->instate == NN_PIPEBASE_INSTATE_RECEIVING)) {
self->instate = NN_PIPEBASE_INSTATE_RECEIVED;
return;
}
nn_assert (self->instate == NN_PIPEBASE_INSTATE_ASYNC);
self->instate = NN_PIPEBASE_INSTATE_IDLE;
if (self->sock)
nn_fsm_raise (&self->fsm, &self->in, NN_PIPE_IN);
}
void nn_pipebase_sent (struct nn_pipebase *self)
{
if (nn_fast (self->outstate == NN_PIPEBASE_OUTSTATE_SENDING)) {
self->outstate = NN_PIPEBASE_OUTSTATE_SENT;
return;
}
nn_assert (self->outstate == NN_PIPEBASE_OUTSTATE_ASYNC);
self->outstate = NN_PIPEBASE_OUTSTATE_IDLE;
if (self->sock)
nn_fsm_raise (&self->fsm, &self->out, NN_PIPE_OUT);
}
void nn_pipebase_getopt (struct nn_pipebase *self, int level, int option,
void *optval, size_t *optvallen)
{
int rc;
int intval;
if (level == NN_SOL_SOCKET) {
switch (option) {
/* Endpoint options */
case NN_SNDPRIO:
intval = self->options.sndprio;
break;
case NN_RCVPRIO:
intval = self->options.rcvprio;
break;
case NN_IPV4ONLY:
intval = self->options.ipv4only;
break;
/* Fallback to socket options */
default:
rc = nn_sock_getopt_inner (self->sock, level,
option, optval, optvallen);
errnum_assert (rc == 0, -rc);
return;
}
memcpy (optval, &intval,
*optvallen < sizeof (int) ? *optvallen : sizeof (int));
*optvallen = sizeof (int);
return;
}
rc = nn_sock_getopt_inner (self->sock, level, option, optval, optvallen);
errnum_assert (rc == 0, -rc);
}
int nn_pipebase_ispeer (struct nn_pipebase *self, int socktype)
{
return nn_sock_ispeer (self->sock, socktype);
}
void nn_pipe_setdata (struct nn_pipe *self, void *data)
{
((struct nn_pipebase*) self)->data = data;
}
void *nn_pipe_getdata (struct nn_pipe *self)
{
return ((struct nn_pipebase*) self)->data;
}
int nn_pipe_send (struct nn_pipe *self, struct nn_msg *msg)
{
int rc;
struct nn_pipebase *pipebase;
pipebase = (struct nn_pipebase*) self;
nn_assert (pipebase->outstate == NN_PIPEBASE_OUTSTATE_IDLE);
pipebase->outstate = NN_PIPEBASE_OUTSTATE_SENDING;
rc = pipebase->vfptr->send (pipebase, msg);
errnum_assert (rc >= 0, -rc);
if (nn_fast (pipebase->outstate == NN_PIPEBASE_OUTSTATE_SENT)) {
pipebase->outstate = NN_PIPEBASE_OUTSTATE_IDLE;
return rc;
}
nn_assert (pipebase->outstate == NN_PIPEBASE_OUTSTATE_SENDING);
pipebase->outstate = NN_PIPEBASE_OUTSTATE_ASYNC;
return rc | NN_PIPEBASE_RELEASE;
}
int nn_pipe_recv (struct nn_pipe *self, struct nn_msg *msg)
{
int rc;
struct nn_pipebase *pipebase;
pipebase = (struct nn_pipebase*) self;
nn_assert (pipebase->instate == NN_PIPEBASE_INSTATE_IDLE);
pipebase->instate = NN_PIPEBASE_INSTATE_RECEIVING;
rc = pipebase->vfptr->recv (pipebase, msg);
errnum_assert (rc >= 0, -rc);
if (nn_fast (pipebase->instate == NN_PIPEBASE_INSTATE_RECEIVED)) {
pipebase->instate = NN_PIPEBASE_INSTATE_IDLE;
return rc;
}
nn_assert (pipebase->instate == NN_PIPEBASE_INSTATE_RECEIVING);
pipebase->instate = NN_PIPEBASE_INSTATE_ASYNC;
return rc | NN_PIPEBASE_RELEASE;
}
void nn_pipe_getopt (struct nn_pipe *self, int level, int option,
void *optval, size_t *optvallen)
{
struct nn_pipebase *pipebase;
pipebase = (struct nn_pipebase*) self;
nn_pipebase_getopt (pipebase, level, option, optval, optvallen);
}
nanomsg-0.8-beta/src/core/poll.c0000664000175000017500000001357412623652600017505 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../nn.h"
#if defined NN_HAVE_WINDOWS
#include "../utils/win.h"
#include "../utils/fast.h"
#include "../utils/sleep.h"
#include "../utils/err.h"
int nn_poll (struct nn_pollfd *fds, int nfds, int timeout)
{
int rc;
int i;
fd_set fdset;
SOCKET fd;
int res;
size_t sz;
struct timeval tv;
/* Fill in the fdset, as appropriate. */
FD_ZERO (&fdset);
for (i = 0; i != nfds; ++i) {
if (fds [i].events & NN_POLLIN) {
sz = sizeof (fd);
rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_RCVFD, &fd, &sz);
if (nn_slow (rc < 0)) {
errno = -rc;
return -1;
}
nn_assert (sz == sizeof (fd));
FD_SET (fd, &fdset);
}
if (fds [i].events & NN_POLLOUT) {
sz = sizeof (fd);
rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_SNDFD, &fd, &sz);
if (nn_slow (rc < 0)) {
errno = -rc;
return -1;
}
nn_assert (sz == sizeof (fd));
FD_SET (fd, &fdset);
}
}
/* Do the polling itself. */
tv.tv_sec = timeout / 1000;
tv.tv_usec = timeout % 1000 * 1000;
if (nn_fast (nfds)) {
rc = select (-1, &fdset, NULL, NULL, &tv);
if (nn_slow (rc == 0))
return 0;
if (nn_slow (rc == SOCKET_ERROR)) {
errno = nn_err_wsa_to_posix (WSAGetLastError ());
return -1;
}
}
else {
// POSIX platforms will sleep until timeout is expired,
// so let's do the same on Windows.
if (timeout > 0)
nn_sleep(timeout);
return 0;
}
/* Move the results from fdset to the nanomsg pollset. */
res = 0;
for (i = 0; i != nfds; ++i) {
fds [i].revents = 0;
if (fds [i].events & NN_POLLIN) {
sz = sizeof (fd);
rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_RCVFD, &fd, &sz);
if (nn_slow (rc < 0)) {
errno = -rc;
return -1;
}
nn_assert (sz == sizeof (fd));
if (FD_ISSET (fd, &fdset))
fds [i].revents |= NN_POLLIN;
}
if (fds [i].events & NN_POLLOUT) {
sz = sizeof (fd);
rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_SNDFD, &fd, &sz);
if (nn_slow (rc < 0)) {
errno = -rc;
return -1;
}
nn_assert (sz == sizeof (fd));
if (FD_ISSET (fd, &fdset))
fds [i].revents |= NN_POLLOUT;
}
if (fds [i].revents)
++res;
}
return res;
}
#else
#include "../utils/alloc.h"
#include "../utils/fast.h"
#include "../utils/err.h"
#include
#include
int nn_poll (struct nn_pollfd *fds, int nfds, int timeout)
{
int rc;
int i;
int pos;
int fd;
int res;
size_t sz;
struct pollfd *pfd;
/* Construct a pollset to be used with OS-level 'poll' function. */
pfd = nn_alloc (sizeof (struct pollfd) * nfds * 2, "pollset");
alloc_assert (pfd);
pos = 0;
for (i = 0; i != nfds; ++i) {
if (fds [i].events & NN_POLLIN) {
sz = sizeof (fd);
rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_RCVFD, &fd, &sz);
if (nn_slow (rc < 0)) {
nn_free (pfd);
errno = -rc;
return -1;
}
nn_assert (sz == sizeof (fd));
pfd [pos].fd = fd;
pfd [pos].events = POLLIN;
++pos;
}
if (fds [i].events & NN_POLLOUT) {
sz = sizeof (fd);
rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_SNDFD, &fd, &sz);
if (nn_slow (rc < 0)) {
nn_free (pfd);
errno = -rc;
return -1;
}
nn_assert (sz == sizeof (fd));
pfd [pos].fd = fd;
pfd [pos].events = POLLIN;
++pos;
}
}
/* Do the polling itself. */
rc = poll (pfd, pos, timeout);
if (nn_slow (rc <= 0)) {
res = errno;
nn_free (pfd);
errno = res;
return rc;
}
/* Move the results from OS-level poll to nn_poll's pollset. */
res = 0;
pos = 0;
for (i = 0; i != nfds; ++i) {
fds [i].revents = 0;
if (fds [i].events & NN_POLLIN) {
if (pfd [pos].revents & POLLIN)
fds [i].revents |= NN_POLLIN;
++pos;
}
if (fds [i].events & NN_POLLOUT) {
if (pfd [pos].revents & POLLIN)
fds [i].revents |= NN_POLLOUT;
++pos;
}
if (fds [i].revents)
++res;
}
nn_free (pfd);
return res;
}
#endif
nanomsg-0.8-beta/src/core/sock.h0000664000175000017500000001536612623652600017504 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_SOCK_INCLUDED
#define NN_SOCK_INCLUDED
#include "../protocol.h"
#include "../transport.h"
#include "../aio/ctx.h"
#include "../aio/fsm.h"
#include "../utils/efd.h"
#include "../utils/sem.h"
#include "../utils/clock.h"
#include "../utils/list.h"
struct nn_pipe;
/* The maximum implemented transport ID. */
#define NN_MAX_TRANSPORT 4
/* The socket-internal statistics */
#define NN_STAT_MESSAGES_SENT 301
#define NN_STAT_MESSAGES_RECEIVED 302
#define NN_STAT_BYTES_SENT 303
#define NN_STAT_BYTES_RECEIVED 304
struct nn_sock
{
/* Socket state machine. */
struct nn_fsm fsm;
int state;
/* Pointer to the instance of the specific socket type. */
struct nn_sockbase *sockbase;
/* Pointer to the socket type metadata. */
struct nn_socktype *socktype;
int flags;
struct nn_ctx ctx;
struct nn_efd sndfd;
struct nn_efd rcvfd;
struct nn_sem termsem;
struct nn_sem relesem;
/* TODO: This clock can be accessed from different threads. If RDTSC
is out-of-sync among different CPU cores, this can be a problem. */
struct nn_clock clock;
/* List of all endpoints associated with the socket. */
struct nn_list eps;
/* List of all endpoint being in the process of shutting down. */
struct nn_list sdeps;
/* Next endpoint ID to assign to a new endpoint. */
int eid;
/* Count of active holds against the socket. */
int holds;
/* Socket-level socket options. */
int linger;
int sndbuf;
int rcvbuf;
int rcvmaxsize;
int sndtimeo;
int rcvtimeo;
int reconnect_ivl;
int reconnect_ivl_max;
/* Endpoint-specific options. */
struct nn_ep_options ep_template;
/* Transport-specific socket options. */
struct nn_optset *optsets [NN_MAX_TRANSPORT];
struct {
/***** The ever-incrementing counters *****/
/* Successfully established nn_connect() connections */
uint64_t established_connections;
/* Successfully accepted connections */
uint64_t accepted_connections;
/* Forcedly closed connections */
uint64_t dropped_connections;
/* Connections closed by peer */
uint64_t broken_connections;
/* Errors trying to establish active connection */
uint64_t connect_errors;
/* Errors binding to specified port */
uint64_t bind_errors;
/* Errors accepting connections at nn_bind()'ed endpoint */
uint64_t accept_errors;
/* Messages sent */
uint64_t messages_sent;
/* Messages received */
uint64_t messages_received;
/* Bytes sent (sum length of data in messages sent) */
uint64_t bytes_sent;
/* Bytes recevied (sum length of data in messages received) */
uint64_t bytes_received;
/***** Level-style values *****/
/* Number of currently established connections */
int current_connections;
/* Number of connections currently in progress */
int inprogress_connections;
/* The currently set priority for sending data */
int current_snd_priority;
/* Number of endpoints having last_errno set to non-zero value */
int current_ep_errors;
} statistics;
/* The socket name for statistics */
char socket_name[64];
};
/* Initialise the socket. */
int nn_sock_init (struct nn_sock *self, struct nn_socktype *socktype, int fd);
/* Called by nn_close() to stop activity on the socket. It doesn't block. */
void nn_sock_stop (struct nn_sock *self);
/* Called by nn_close() to deallocate the socket. It's a blocking function
and can return -EINTR. */
int nn_sock_term (struct nn_sock *self);
/* Called by sockbase when stopping is done. */
void nn_sock_stopped (struct nn_sock *self);
/* Called by nn_term() to let the socket know about the process shutdown. */
void nn_sock_zombify (struct nn_sock *self);
/* Returns the AIO context associated with the socket. */
struct nn_ctx *nn_sock_getctx (struct nn_sock *self);
/* Returns 1 if the specified socket type is a valid peer for this socket,
0 otherwise. */
int nn_sock_ispeer (struct nn_sock *self, int socktype);
/* Add new endpoint to the socket. */
int nn_sock_add_ep (struct nn_sock *self, struct nn_transport *transport,
int bind, const char *addr);
/* Remove the endpoint with the specified ID from the socket. */
int nn_sock_rm_ep (struct nn_sock *self, int eid);
/* Send a message to the socket. */
int nn_sock_send (struct nn_sock *self, struct nn_msg *msg, int flags);
/* Receive a message from the socket. */
int nn_sock_recv (struct nn_sock *self, struct nn_msg *msg, int flags);
/* Set a socket option. */
int nn_sock_setopt (struct nn_sock *self, int level, int option,
const void *optval, size_t optvallen);
/* Retrieve a socket option. This function is to be called from the API. */
int nn_sock_getopt (struct nn_sock *self, int level, int option,
void *optval, size_t *optvallen);
/* Retrieve a socket option. This function is to be called from within
the socket. */
int nn_sock_getopt_inner (struct nn_sock *self, int level, int option,
void *optval, size_t *optvallen);
/* Used by pipes. */
int nn_sock_add (struct nn_sock *self, struct nn_pipe *pipe);
void nn_sock_rm (struct nn_sock *self, struct nn_pipe *pipe);
/* Monitoring callbacks */
void nn_sock_report_error(struct nn_sock *self, struct nn_ep *ep, int errnum);
void nn_sock_stat_increment(struct nn_sock *self, int name, int64_t increment);
/* Holds and releases. */
int nn_sock_hold (struct nn_sock *self);
void nn_sock_rele (struct nn_sock *self);
#endif
nanomsg-0.8-beta/src/core/sock.c0000664000175000017500000011250112623652600017464 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2014 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Copyright 2015 Garrett D'Amore
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../protocol.h"
#include "../transport.h"
#include "sock.h"
#include "global.h"
#include "ep.h"
#include "../utils/err.h"
#include "../utils/cont.h"
#include "../utils/fast.h"
#include "../utils/alloc.h"
#include "../utils/msg.h"
#include
/* These bits specify whether individual efds are signalled or not at
the moment. Storing this information allows us to avoid redundant signalling
and unsignalling of the efd objects. */
#define NN_SOCK_FLAG_IN 1
#define NN_SOCK_FLAG_OUT 2
/* Possible states of the socket. */
#define NN_SOCK_STATE_INIT 1
#define NN_SOCK_STATE_ACTIVE 2
#define NN_SOCK_STATE_ZOMBIE 3
#define NN_SOCK_STATE_STOPPING_EPS 4
#define NN_SOCK_STATE_STOPPING 5
#define NN_SOCK_STATE_FINI 6
/* Events sent to the state machine. */
#define NN_SOCK_ACTION_ZOMBIFY 1
#define NN_SOCK_ACTION_STOPPED 2
/* Subordinated source objects. */
#define NN_SOCK_SRC_EP 1
/* Private functions. */
static struct nn_optset *nn_sock_optset (struct nn_sock *self, int id);
static int nn_sock_setopt_inner (struct nn_sock *self, int level,
int option, const void *optval, size_t optvallen);
static void nn_sock_onleave (struct nn_ctx *self);
static void nn_sock_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_sock_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_sock_action_zombify (struct nn_sock *self);
/* Initialize a socket. A hold is placed on the initialized socket for
the caller as well. */
int nn_sock_init (struct nn_sock *self, struct nn_socktype *socktype, int fd)
{
int rc;
int i;
/* Make sure that at least one message direction is supported. */
nn_assert (!(socktype->flags & NN_SOCKTYPE_FLAG_NOSEND) ||
!(socktype->flags & NN_SOCKTYPE_FLAG_NORECV));
/* Create the AIO context for the SP socket. */
nn_ctx_init (&self->ctx, nn_global_getpool (), nn_sock_onleave);
/* Initialise the state machine. */
nn_fsm_init_root (&self->fsm, nn_sock_handler,
nn_sock_shutdown, &self->ctx);
self->state = NN_SOCK_STATE_INIT;
/* Open the NN_SNDFD and NN_RCVFD efds. Do so, only if the socket type
supports send/recv, as appropriate. */
if (socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)
memset (&self->sndfd, 0xcd, sizeof (self->sndfd));
else {
rc = nn_efd_init (&self->sndfd);
if (nn_slow (rc < 0))
return rc;
}
if (socktype->flags & NN_SOCKTYPE_FLAG_NORECV)
memset (&self->rcvfd, 0xcd, sizeof (self->rcvfd));
else {
rc = nn_efd_init (&self->rcvfd);
if (nn_slow (rc < 0)) {
if (!(socktype->flags & NN_SOCKTYPE_FLAG_NOSEND))
nn_efd_term (&self->sndfd);
return rc;
}
}
nn_sem_init (&self->termsem);
nn_sem_init (&self->relesem);
if (nn_slow (rc < 0)) {
if (!(socktype->flags & NN_SOCKTYPE_FLAG_NORECV))
nn_efd_term (&self->rcvfd);
if (!(socktype->flags & NN_SOCKTYPE_FLAG_NOSEND))
nn_efd_term (&self->sndfd);
return rc;
}
self->holds = 1; /* Callers hold. */
self->flags = 0;
nn_clock_init (&self->clock);
nn_list_init (&self->eps);
nn_list_init (&self->sdeps);
self->eid = 1;
/* Default values for NN_SOL_SOCKET options. */
self->linger = 1000;
self->sndbuf = 128 * 1024;
self->rcvbuf = 128 * 1024;
self->rcvmaxsize = 1024 * 1024;
self->sndtimeo = -1;
self->rcvtimeo = -1;
self->reconnect_ivl = 100;
self->reconnect_ivl_max = 0;
self->ep_template.sndprio = 8;
self->ep_template.rcvprio = 8;
self->ep_template.ipv4only = 1;
/* Initialize statistic entries */
self->statistics.established_connections = 0;
self->statistics.accepted_connections = 0;
self->statistics.dropped_connections = 0;
self->statistics.broken_connections = 0;
self->statistics.connect_errors = 0;
self->statistics.bind_errors = 0;
self->statistics.accept_errors = 0;
self->statistics.messages_sent = 0;
self->statistics.messages_received = 0;
self->statistics.bytes_sent = 0;
self->statistics.bytes_received = 0;
self->statistics.current_connections = 0;
self->statistics.inprogress_connections = 0;
self->statistics.current_snd_priority = 0;
self->statistics.current_ep_errors = 0;
/* Should be pretty much enough space for just the number */
sprintf(self->socket_name, "%d", fd);
/* The transport-specific options are not initialised immediately,
rather, they are allocated later on when needed. */
for (i = 0; i != NN_MAX_TRANSPORT; ++i)
self->optsets [i] = NULL;
/* Create the specific socket type itself. */
rc = socktype->create ((void*) self, &self->sockbase);
errnum_assert (rc == 0, -rc);
self->socktype = socktype;
/* Launch the state machine. */
nn_ctx_enter (&self->ctx);
nn_fsm_start (&self->fsm);
nn_ctx_leave (&self->ctx);
return 0;
}
void nn_sock_stopped (struct nn_sock *self)
{
/* TODO: Do the following in a more sane way. */
self->fsm.stopped.fsm = &self->fsm;
self->fsm.stopped.src = NN_FSM_ACTION;
self->fsm.stopped.srcptr = NULL;
self->fsm.stopped.type = NN_SOCK_ACTION_STOPPED;
nn_ctx_raise (self->fsm.ctx, &self->fsm.stopped);
}
void nn_sock_zombify (struct nn_sock *self)
{
nn_ctx_enter (&self->ctx);
nn_fsm_action (&self->fsm, NN_SOCK_ACTION_ZOMBIFY);
nn_ctx_leave (&self->ctx);
}
/* Stop the socket. This will prevent new calls from aquiring a
hold on the socket, cause endpoints to shut down, and wake any
threads waiting to recv or send data. */
void nn_sock_stop (struct nn_sock *self)
{
nn_ctx_enter (&self->ctx);
nn_fsm_stop (&self->fsm);
nn_ctx_leave (&self->ctx);
}
int nn_sock_term (struct nn_sock *self)
{
int rc;
int i;
/* NOTE: nn_sock_stop must have already been called. */
/* Some endpoints may still be alive. Here we are going to wait
till they are all closed. This loop is not interruptible, because
making it so would leave a partially cleaned up socket, and we don't
have a way to defer resource deallocation. */
for (;;) {
rc = nn_sem_wait (&self->termsem);
if (nn_slow (rc == -EINTR))
continue;
errnum_assert (rc == 0, -rc);
break;
}
/* Also, wait for all holds on the socket to be released. */
for (;;) {
rc = nn_sem_wait (&self->relesem);
if (nn_slow (rc == -EINTR))
continue;
errnum_assert (rc == 0, -rc);
break;
}
/* Threads that posted the semaphore(s) can still have the ctx locked
for a short while. By simply entering the context and exiting it
immediately we can be sure that any such threads have already
exited the context. */
nn_ctx_enter (&self->ctx);
nn_ctx_leave (&self->ctx);
/* At this point, we can be reasonably certain that no other thread
has any references to the socket. */
nn_fsm_stopped_noevent (&self->fsm);
nn_fsm_term (&self->fsm);
nn_sem_term (&self->termsem);
nn_list_term (&self->sdeps);
nn_list_term (&self->eps);
nn_clock_term (&self->clock);
nn_ctx_term (&self->ctx);
/* Destroy any optsets associated with the socket. */
for (i = 0; i != NN_MAX_TRANSPORT; ++i)
if (self->optsets [i])
self->optsets [i]->vfptr->destroy (self->optsets [i]);
return 0;
}
struct nn_ctx *nn_sock_getctx (struct nn_sock *self)
{
return &self->ctx;
}
int nn_sock_ispeer (struct nn_sock *self, int socktype)
{
/* If the peer implements a different SP protocol it is not a valid peer.
Checking it here ensures that even if faulty protocol implementation
allows for cross-protocol communication, it will never happen
in practice. */
if ((self->socktype->protocol & 0xfff0) != (socktype & 0xfff0))
return 0;
/* As long as the peer speaks the same protocol, socket type itself
decides which socket types are to be accepted. */
return self->socktype->ispeer (socktype);
}
int nn_sock_setopt (struct nn_sock *self, int level, int option,
const void *optval, size_t optvallen)
{
int rc;
nn_ctx_enter (&self->ctx);
if (nn_slow (self->state == NN_SOCK_STATE_ZOMBIE)) {
nn_ctx_leave (&self->ctx);
return -ETERM;
}
rc = nn_sock_setopt_inner (self, level, option, optval, optvallen);
nn_ctx_leave (&self->ctx);
return rc;
}
static int nn_sock_setopt_inner (struct nn_sock *self, int level,
int option, const void *optval, size_t optvallen)
{
struct nn_optset *optset;
int val;
int *dst;
/* Protocol-specific socket options. */
if (level > NN_SOL_SOCKET)
return self->sockbase->vfptr->setopt (self->sockbase, level, option,
optval, optvallen);
/* Transport-specific options. */
if (level < NN_SOL_SOCKET) {
optset = nn_sock_optset (self, level);
if (!optset)
return -ENOPROTOOPT;
return optset->vfptr->setopt (optset, option, optval, optvallen);
}
/* Special-casing socket name for now as it's the only string option */
if (level == NN_SOL_SOCKET && option == NN_SOCKET_NAME) {
if (optvallen > 63)
return -EINVAL;
memcpy (self->socket_name, optval, optvallen);
self->socket_name [optvallen] = 0;
return 0;
}
/* At this point we assume that all options are of type int. */
if (optvallen != sizeof (int))
return -EINVAL;
val = *(int*) optval;
/* Generic socket-level options. */
if (level == NN_SOL_SOCKET) {
switch (option) {
case NN_LINGER:
dst = &self->linger;
break;
case NN_SNDBUF:
if (nn_slow (val <= 0))
return -EINVAL;
dst = &self->sndbuf;
break;
case NN_RCVBUF:
if (nn_slow (val <= 0))
return -EINVAL;
dst = &self->rcvbuf;
break;
case NN_RCVMAXSIZE:
if (nn_slow (val < -1))
return -EINVAL;
dst = &self->rcvmaxsize;
break;
case NN_SNDTIMEO:
dst = &self->sndtimeo;
break;
case NN_RCVTIMEO:
dst = &self->rcvtimeo;
break;
case NN_RECONNECT_IVL:
if (nn_slow (val < 0))
return -EINVAL;
dst = &self->reconnect_ivl;
break;
case NN_RECONNECT_IVL_MAX:
if (nn_slow (val < 0))
return -EINVAL;
dst = &self->reconnect_ivl_max;
break;
case NN_SNDPRIO:
if (nn_slow (val < 1 || val > 16))
return -EINVAL;
dst = &self->ep_template.sndprio;
break;
case NN_RCVPRIO:
if (nn_slow (val < 1 || val > 16))
return -EINVAL;
dst = &self->ep_template.rcvprio;
break;
case NN_IPV4ONLY:
if (nn_slow (val != 0 && val != 1))
return -EINVAL;
dst = &self->ep_template.ipv4only;
break;
default:
return -ENOPROTOOPT;
}
*dst = val;
return 0;
}
nn_assert (0);
}
int nn_sock_getopt (struct nn_sock *self, int level, int option,
void *optval, size_t *optvallen)
{
int rc;
nn_ctx_enter (&self->ctx);
if (nn_slow (self->state == NN_SOCK_STATE_ZOMBIE)) {
nn_ctx_leave (&self->ctx);
return -ETERM;
}
rc = nn_sock_getopt_inner (self, level, option, optval, optvallen);
nn_ctx_leave (&self->ctx);
return rc;
}
int nn_sock_getopt_inner (struct nn_sock *self, int level,
int option, void *optval, size_t *optvallen)
{
int rc;
struct nn_optset *optset;
int intval;
nn_fd fd;
/* Generic socket-level options. */
if (level == NN_SOL_SOCKET) {
switch (option) {
case NN_DOMAIN:
intval = self->socktype->domain;
break;
case NN_PROTOCOL:
intval = self->socktype->protocol;
break;
case NN_LINGER:
intval = self->linger;
break;
case NN_SNDBUF:
intval = self->sndbuf;
break;
case NN_RCVBUF:
intval = self->rcvbuf;
break;
case NN_RCVMAXSIZE:
intval = self->rcvmaxsize;
break;
case NN_SNDTIMEO:
intval = self->sndtimeo;
break;
case NN_RCVTIMEO:
intval = self->rcvtimeo;
break;
case NN_RECONNECT_IVL:
intval = self->reconnect_ivl;
break;
case NN_RECONNECT_IVL_MAX:
intval = self->reconnect_ivl_max;
break;
case NN_SNDPRIO:
intval = self->ep_template.sndprio;
break;
case NN_RCVPRIO:
intval = self->ep_template.rcvprio;
break;
case NN_IPV4ONLY:
intval = self->ep_template.ipv4only;
break;
case NN_SNDFD:
if (self->socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)
return -ENOPROTOOPT;
fd = nn_efd_getfd (&self->sndfd);
memcpy (optval, &fd,
*optvallen < sizeof (nn_fd) ? *optvallen : sizeof (nn_fd));
*optvallen = sizeof (nn_fd);
return 0;
case NN_RCVFD:
if (self->socktype->flags & NN_SOCKTYPE_FLAG_NORECV)
return -ENOPROTOOPT;
fd = nn_efd_getfd (&self->rcvfd);
memcpy (optval, &fd,
*optvallen < sizeof (nn_fd) ? *optvallen : sizeof (nn_fd));
*optvallen = sizeof (nn_fd);
return 0;
case NN_SOCKET_NAME:
strncpy (optval, self->socket_name, *optvallen);
*optvallen = strlen(self->socket_name);
return 0;
default:
return -ENOPROTOOPT;
}
memcpy (optval, &intval,
*optvallen < sizeof (int) ? *optvallen : sizeof (int));
*optvallen = sizeof (int);
return 0;
}
/* Protocol-specific socket options. */
if (level > NN_SOL_SOCKET)
return rc = self->sockbase->vfptr->getopt (self->sockbase,
level, option, optval, optvallen);
/* Transport-specific options. */
if (level < NN_SOL_SOCKET) {
optset = nn_sock_optset (self, level);
if (!optset)
return -ENOPROTOOPT;
return optset->vfptr->getopt (optset, option, optval, optvallen);
}
nn_assert (0);
}
int nn_sock_add_ep (struct nn_sock *self, struct nn_transport *transport,
int bind, const char *addr)
{
int rc;
struct nn_ep *ep;
int eid;
nn_ctx_enter (&self->ctx);
/* Instantiate the endpoint. */
ep = nn_alloc (sizeof (struct nn_ep), "endpoint");
rc = nn_ep_init (ep, NN_SOCK_SRC_EP, self, self->eid, transport,
bind, addr);
if (nn_slow (rc < 0)) {
nn_free (ep);
nn_ctx_leave (&self->ctx);
return rc;
}
nn_ep_start (ep);
/* Increase the endpoint ID for the next endpoint. */
eid = self->eid;
++self->eid;
/* Add it to the list of active endpoints. */
nn_list_insert (&self->eps, &ep->item, nn_list_end (&self->eps));
nn_ctx_leave (&self->ctx);
return eid;
}
int nn_sock_rm_ep (struct nn_sock *self, int eid)
{
struct nn_list_item *it;
struct nn_ep *ep;
nn_ctx_enter (&self->ctx);
/* Find the specified enpoint. */
ep = NULL;
for (it = nn_list_begin (&self->eps);
it != nn_list_end (&self->eps);
it = nn_list_next (&self->eps, it)) {
ep = nn_cont (it, struct nn_ep, item);
if (ep->eid == eid)
break;
ep = NULL;
}
/* The endpoint doesn't exist. */
if (!ep) {
nn_ctx_leave (&self->ctx);
return -EINVAL;
}
/* Move the endpoint from the list of active endpoints to the list
of shutting down endpoints. */
nn_list_erase (&self->eps, &ep->item);
nn_list_insert (&self->sdeps, &ep->item, nn_list_end (&self->sdeps));
/* Ask the endpoint to stop. Actual terminatation may be delayed
by the transport. */
nn_ep_stop (ep);
nn_ctx_leave (&self->ctx);
return 0;
}
int nn_sock_send (struct nn_sock *self, struct nn_msg *msg, int flags)
{
int rc;
uint64_t deadline;
uint64_t now;
int timeout;
/* Some sockets types cannot be used for sending messages. */
if (nn_slow (self->socktype->flags & NN_SOCKTYPE_FLAG_NOSEND))
return -ENOTSUP;
nn_ctx_enter (&self->ctx);
/* Compute the deadline for SNDTIMEO timer. */
if (self->sndtimeo < 0) {
deadline = -1;
timeout = -1;
}
else {
deadline = nn_clock_now (&self->clock) + self->sndtimeo;
timeout = self->sndtimeo;
}
while (1) {
switch (self->state) {
case NN_SOCK_STATE_ACTIVE:
case NN_SOCK_STATE_INIT:
break;
case NN_SOCK_STATE_ZOMBIE:
/* If nn_term() was already called, return ETERM. */
nn_ctx_leave (&self->ctx);
return -ETERM;
case NN_SOCK_STATE_STOPPING_EPS:
case NN_SOCK_STATE_STOPPING:
case NN_SOCK_STATE_FINI:
/* Socket closed or closing. Should we return something
else here; recvmsg(2) for example returns no data in
this case, like read(2). The use of indexed file
descriptors is further problematic, as an FD can be reused
leading to situations where technically the outstanding
operation should refer to some other socket entirely. */
nn_ctx_leave (&self->ctx);
return -EBADF;
}
/* Try to send the message in a non-blocking way. */
rc = self->sockbase->vfptr->send (self->sockbase, msg);
if (nn_fast (rc == 0)) {
nn_ctx_leave (&self->ctx);
return 0;
}
nn_assert (rc < 0);
/* Any unexpected error is forwarded to the caller. */
if (nn_slow (rc != -EAGAIN)) {
nn_ctx_leave (&self->ctx);
return rc;
}
/* If the message cannot be sent at the moment and the send call
is non-blocking, return immediately. */
if (nn_fast (flags & NN_DONTWAIT)) {
nn_ctx_leave (&self->ctx);
return -EAGAIN;
}
/* With blocking send, wait while there are new pipes available
for sending. */
nn_ctx_leave (&self->ctx);
rc = nn_efd_wait (&self->sndfd, timeout);
if (nn_slow (rc == -ETIMEDOUT))
return -ETIMEDOUT;
if (nn_slow (rc == -EINTR))
return -EINTR;
if (nn_slow (rc == -EBADF))
return -EBADF;
errnum_assert (rc == 0, rc);
nn_ctx_enter (&self->ctx);
/*
* Double check if pipes are still available for sending
*/
if (!nn_efd_wait (&self->sndfd, 0)) {
self->flags |= NN_SOCK_FLAG_OUT;
}
/* If needed, re-compute the timeout to reflect the time that have
already elapsed. */
if (self->sndtimeo >= 0) {
now = nn_clock_now (&self->clock);
timeout = (int) (now > deadline ? 0 : deadline - now);
}
}
}
int nn_sock_recv (struct nn_sock *self, struct nn_msg *msg, int flags)
{
int rc;
uint64_t deadline;
uint64_t now;
int timeout;
/* Some sockets types cannot be used for receiving messages. */
if (nn_slow (self->socktype->flags & NN_SOCKTYPE_FLAG_NORECV))
return -ENOTSUP;
nn_ctx_enter (&self->ctx);
/* Compute the deadline for RCVTIMEO timer. */
if (self->rcvtimeo < 0) {
deadline = -1;
timeout = -1;
}
else {
deadline = nn_clock_now (&self->clock) + self->rcvtimeo;
timeout = self->rcvtimeo;
}
while (1) {
switch (self->state) {
case NN_SOCK_STATE_ACTIVE:
case NN_SOCK_STATE_INIT:
break;
case NN_SOCK_STATE_ZOMBIE:
/* If nn_term() was already called, return ETERM. */
nn_ctx_leave (&self->ctx);
return -ETERM;
case NN_SOCK_STATE_STOPPING_EPS:
case NN_SOCK_STATE_STOPPING:
case NN_SOCK_STATE_FINI:
/* Socket closed or closing. Should we return something
else here; recvmsg(2) for example returns no data in
this case, like read(2). The use of indexed file
descriptors is further problematic, as an FD can be reused
leading to situations where technically the outstanding
operation should refer to some other socket entirely. */
nn_ctx_leave (&self->ctx);
return -EBADF;
}
/* Try to receive the message in a non-blocking way. */
rc = self->sockbase->vfptr->recv (self->sockbase, msg);
if (nn_fast (rc == 0)) {
nn_ctx_leave (&self->ctx);
return 0;
}
nn_assert (rc < 0);
/* Any unexpected error is forwarded to the caller. */
if (nn_slow (rc != -EAGAIN)) {
nn_ctx_leave (&self->ctx);
return rc;
}
/* If the message cannot be received at the moment and the recv call
is non-blocking, return immediately. */
if (nn_fast (flags & NN_DONTWAIT)) {
nn_ctx_leave (&self->ctx);
return -EAGAIN;
}
/* With blocking recv, wait while there are new pipes available
for receiving. */
nn_ctx_leave (&self->ctx);
rc = nn_efd_wait (&self->rcvfd, timeout);
if (nn_slow (rc == -ETIMEDOUT))
return -ETIMEDOUT;
if (nn_slow (rc == -EINTR))
return -EINTR;
if (nn_slow (rc == -EBADF))
return -EBADF;
errnum_assert (rc == 0, rc);
nn_ctx_enter (&self->ctx);
/*
* Double check if pipes are still available for receiving
*/
if (!nn_efd_wait (&self->rcvfd, 0)) {
self->flags |= NN_SOCK_FLAG_IN;
}
/* If needed, re-compute the timeout to reflect the time that have
already elapsed. */
if (self->rcvtimeo >= 0) {
now = nn_clock_now (&self->clock);
timeout = (int) (now > deadline ? 0 : deadline - now);
}
}
}
int nn_sock_add (struct nn_sock *self, struct nn_pipe *pipe)
{
int rc;
rc = self->sockbase->vfptr->add (self->sockbase, pipe);
if (nn_slow (rc >= 0)) {
nn_sock_stat_increment (self, NN_STAT_CURRENT_CONNECTIONS, 1);
}
return rc;
}
void nn_sock_rm (struct nn_sock *self, struct nn_pipe *pipe)
{
self->sockbase->vfptr->rm (self->sockbase, pipe);
nn_sock_stat_increment (self, NN_STAT_CURRENT_CONNECTIONS, -1);
}
static void nn_sock_onleave (struct nn_ctx *self)
{
struct nn_sock *sock;
int events;
sock = nn_cont (self, struct nn_sock, ctx);
/* If nn_close() was already called there's no point in adjusting the
snd/rcv file descriptors. */
if (nn_slow (sock->state != NN_SOCK_STATE_ACTIVE))
return;
/* Check whether socket is readable and/or writable at the moment. */
events = sock->sockbase->vfptr->events (sock->sockbase);
errnum_assert (events >= 0, -events);
/* Signal/unsignal IN as needed. */
if (!(sock->socktype->flags & NN_SOCKTYPE_FLAG_NORECV)) {
if (events & NN_SOCKBASE_EVENT_IN) {
if (!(sock->flags & NN_SOCK_FLAG_IN)) {
sock->flags |= NN_SOCK_FLAG_IN;
nn_efd_signal (&sock->rcvfd);
}
}
else {
if (sock->flags & NN_SOCK_FLAG_IN) {
sock->flags &= ~NN_SOCK_FLAG_IN;
nn_efd_unsignal (&sock->rcvfd);
}
}
}
/* Signal/unsignal OUT as needed. */
if (!(sock->socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)) {
if (events & NN_SOCKBASE_EVENT_OUT) {
if (!(sock->flags & NN_SOCK_FLAG_OUT)) {
sock->flags |= NN_SOCK_FLAG_OUT;
nn_efd_signal (&sock->sndfd);
}
}
else {
if (sock->flags & NN_SOCK_FLAG_OUT) {
sock->flags &= ~NN_SOCK_FLAG_OUT;
nn_efd_unsignal (&sock->sndfd);
}
}
}
}
static struct nn_optset *nn_sock_optset (struct nn_sock *self, int id)
{
int index;
struct nn_transport *tp;
/* Transport IDs are negative and start from -1. */
index = (-id) - 1;
/* Check for invalid indices. */
if (nn_slow (index < 0 || index >= NN_MAX_TRANSPORT))
return NULL;
/* If the option set already exists return it. */
if (nn_fast (self->optsets [index] != NULL))
return self->optsets [index];
/* If the option set doesn't exist yet, create it. */
tp = nn_global_transport (id);
if (nn_slow (!tp))
return NULL;
if (nn_slow (!tp->optset))
return NULL;
self->optsets [index] = tp->optset ();
return self->optsets [index];
}
static void nn_sock_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr)
{
struct nn_sock *sock;
struct nn_list_item *it;
struct nn_ep *ep;
sock = nn_cont (self, struct nn_sock, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
nn_assert (sock->state == NN_SOCK_STATE_ACTIVE ||
sock->state == NN_SOCK_STATE_ZOMBIE);
/* Close sndfd and rcvfd. This should make any current
select/poll using SNDFD and/or RCVFD exit. */
if (!(sock->socktype->flags & NN_SOCKTYPE_FLAG_NORECV)) {
nn_efd_stop (&sock->rcvfd);
}
if (!(sock->socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)) {
nn_efd_stop (&sock->sndfd);
}
/* Ask all the associated endpoints to stop. */
it = nn_list_begin (&sock->eps);
while (it != nn_list_end (&sock->eps)) {
ep = nn_cont (it, struct nn_ep, item);
it = nn_list_next (&sock->eps, it);
nn_list_erase (&sock->eps, &ep->item);
nn_list_insert (&sock->sdeps, &ep->item,
nn_list_end (&sock->sdeps));
nn_ep_stop (ep);
}
sock->state = NN_SOCK_STATE_STOPPING_EPS;
goto finish2;
}
if (nn_slow (sock->state == NN_SOCK_STATE_STOPPING_EPS)) {
if (!(src == NN_SOCK_SRC_EP && type == NN_EP_STOPPED)) {
/* If we got here waiting for EPs to teardown, but src is
not an EP, then it isn't safe for us to do anything,
because we just need to wait for the EPs to finish
up their thing. Just bail. */
return;
}
/* Endpoint is stopped. Now we can safely deallocate it. */
ep = (struct nn_ep*) srcptr;
nn_list_erase (&sock->sdeps, &ep->item);
nn_ep_term (ep);
nn_free (ep);
finish2:
/* If all the endpoints are deallocated, we can start stopping
protocol-specific part of the socket. If there' no stop function
we can consider it stopped straight away. */
if (!nn_list_empty (&sock->sdeps))
return;
nn_assert (nn_list_empty (&sock->eps));
sock->state = NN_SOCK_STATE_STOPPING;
if (!sock->sockbase->vfptr->stop)
goto finish1;
sock->sockbase->vfptr->stop (sock->sockbase);
return;
}
if (nn_slow (sock->state == NN_SOCK_STATE_STOPPING)) {
/* We get here when the deallocation of the socket was delayed by the
specific socket type. */
nn_assert (src == NN_FSM_ACTION && type == NN_SOCK_ACTION_STOPPED);
finish1:
/* Protocol-specific part of the socket is stopped.
We can safely deallocate it. */
sock->sockbase->vfptr->destroy (sock->sockbase);
sock->state = NN_SOCK_STATE_FINI;
/* Close the event FDs entirely. */
if (!(sock->socktype->flags & NN_SOCKTYPE_FLAG_NORECV)) {
nn_efd_term (&sock->rcvfd);
}
if (!(sock->socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)) {
nn_efd_term (&sock->sndfd);
}
/* Now we can unblock the application thread blocked in
the nn_close() call. */
nn_sem_post (&sock->termsem);
return;
}
nn_fsm_bad_state(sock->state, src, type);
}
static void nn_sock_handler (struct nn_fsm *self, int src, int type,
void *srcptr)
{
struct nn_sock *sock;
struct nn_ep *ep;
sock = nn_cont (self, struct nn_sock, fsm);
switch (sock->state) {
/******************************************************************************/
/* INIT state. */
/******************************************************************************/
case NN_SOCK_STATE_INIT:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
sock->state = NN_SOCK_STATE_ACTIVE;
return;
case NN_SOCK_ACTION_ZOMBIFY:
nn_sock_action_zombify (sock);
return;
default:
nn_fsm_bad_action (sock->state, src, type);
}
default:
nn_fsm_bad_source (sock->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/******************************************************************************/
case NN_SOCK_STATE_ACTIVE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_SOCK_ACTION_ZOMBIFY:
nn_sock_action_zombify (sock);
return;
default:
nn_fsm_bad_action (sock->state, src, type);
}
case NN_SOCK_SRC_EP:
switch (type) {
case NN_EP_STOPPED:
/* This happens when an endpoint is closed using
nn_shutdown() function. */
ep = (struct nn_ep*) srcptr;
nn_list_erase (&sock->sdeps, &ep->item);
nn_ep_term (ep);
nn_free (ep);
return;
default:
nn_fsm_bad_action (sock->state, src, type);
}
default:
/* The assumption is that all the other events come from pipes. */
switch (type) {
case NN_PIPE_IN:
sock->sockbase->vfptr->in (sock->sockbase,
(struct nn_pipe*) srcptr);
return;
case NN_PIPE_OUT:
sock->sockbase->vfptr->out (sock->sockbase,
(struct nn_pipe*) srcptr);
return;
default:
nn_fsm_bad_action (sock->state, src, type);
}
}
/******************************************************************************/
/* ZOMBIE state. */
/******************************************************************************/
case NN_SOCK_STATE_ZOMBIE:
nn_fsm_bad_state (sock->state, src, type);
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (sock->state, src, type);
}
}
/******************************************************************************/
/* State machine actions. */
/******************************************************************************/
static void nn_sock_action_zombify (struct nn_sock *self)
{
/* Switch to the zombie state. From now on all the socket
functions will return ETERM. */
self->state = NN_SOCK_STATE_ZOMBIE;
/* Set IN and OUT events to unblock any polling function. */
if (!(self->flags & NN_SOCK_FLAG_IN)) {
self->flags |= NN_SOCK_FLAG_IN;
if (!(self->socktype->flags & NN_SOCKTYPE_FLAG_NORECV))
nn_efd_signal (&self->rcvfd);
}
if (!(self->flags & NN_SOCK_FLAG_OUT)) {
self->flags |= NN_SOCK_FLAG_OUT;
if (!(self->socktype->flags & NN_SOCKTYPE_FLAG_NOSEND))
nn_efd_signal (&self->sndfd);
}
}
void nn_sock_report_error (struct nn_sock *self, struct nn_ep *ep, int errnum)
{
if (!nn_global_print_errors())
return;
if (errnum == 0)
return;
if (ep) {
fprintf(stderr, "nanomsg: socket.%s[%s]: Error: %s\n",
self->socket_name, nn_ep_getaddr(ep), nn_strerror(errnum));
} else {
fprintf(stderr, "nanomsg: socket.%s: Error: %s\n",
self->socket_name, nn_strerror(errnum));
}
}
void nn_sock_stat_increment (struct nn_sock *self, int name, int64_t increment)
{
switch (name) {
case NN_STAT_ESTABLISHED_CONNECTIONS:
nn_assert (increment > 0);
self->statistics.established_connections += increment;
break;
case NN_STAT_ACCEPTED_CONNECTIONS:
nn_assert (increment > 0);
self->statistics.accepted_connections += increment;
break;
case NN_STAT_DROPPED_CONNECTIONS:
nn_assert (increment > 0);
self->statistics.dropped_connections += increment;
break;
case NN_STAT_BROKEN_CONNECTIONS:
nn_assert (increment > 0);
self->statistics.broken_connections += increment;
break;
case NN_STAT_CONNECT_ERRORS:
nn_assert (increment > 0);
self->statistics.connect_errors += increment;
break;
case NN_STAT_BIND_ERRORS:
nn_assert (increment > 0);
self->statistics.bind_errors += increment;
break;
case NN_STAT_ACCEPT_ERRORS:
nn_assert (increment > 0);
self->statistics.accept_errors += increment;
break;
case NN_STAT_MESSAGES_SENT:
nn_assert (increment > 0);
self->statistics.messages_sent += increment;
break;
case NN_STAT_MESSAGES_RECEIVED:
nn_assert (increment > 0);
self->statistics.messages_received += increment;
break;
case NN_STAT_BYTES_SENT:
nn_assert (increment >= 0);
self->statistics.bytes_sent += increment;
break;
case NN_STAT_BYTES_RECEIVED:
nn_assert (increment >= 0);
self->statistics.bytes_received += increment;
break;
case NN_STAT_CURRENT_CONNECTIONS:
nn_assert (increment > 0 ||
self->statistics.current_connections >= -increment);
nn_assert(increment < INT_MAX && increment > -INT_MAX);
self->statistics.current_connections += (int) increment;
break;
case NN_STAT_INPROGRESS_CONNECTIONS:
nn_assert (increment > 0 ||
self->statistics.inprogress_connections >= -increment);
nn_assert(increment < INT_MAX && increment > -INT_MAX);
self->statistics.inprogress_connections += (int) increment;
break;
case NN_STAT_CURRENT_SND_PRIORITY:
/* This is an exception, we don't want to increment priority */
nn_assert((increment > 0 && increment <= 16) || increment == -1);
self->statistics.current_snd_priority = (int) increment;
break;
case NN_STAT_CURRENT_EP_ERRORS:
nn_assert (increment > 0 ||
self->statistics.current_ep_errors >= -increment);
nn_assert(increment < INT_MAX && increment > -INT_MAX);
self->statistics.current_ep_errors += (int) increment;
break;
}
}
int nn_sock_hold (struct nn_sock *self)
{
switch (self->state) {
case NN_SOCK_STATE_ACTIVE:
case NN_SOCK_STATE_INIT:
self->holds++;
return 0;
case NN_SOCK_STATE_ZOMBIE:
return -ETERM;
case NN_SOCK_STATE_STOPPING:
case NN_SOCK_STATE_STOPPING_EPS:
case NN_SOCK_STATE_FINI:
default:
return -EBADF;
}
}
void nn_sock_rele (struct nn_sock *self)
{
self->holds--;
if (self->holds == 0) {
nn_sem_post (&self->relesem);
}
}
nanomsg-0.8-beta/src/core/sockbase.c0000664000175000017500000000376412623652600020331 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../protocol.h"
#include "sock.h"
#include "../utils/err.h"
#include "../utils/attr.h"
void nn_sockbase_init (struct nn_sockbase *self,
const struct nn_sockbase_vfptr *vfptr, void *hint)
{
self->vfptr = vfptr;
self->sock = (struct nn_sock*) hint;
}
void nn_sockbase_term (NN_UNUSED struct nn_sockbase *self)
{
}
void nn_sockbase_stopped (struct nn_sockbase *self)
{
nn_sock_stopped (self->sock);
}
struct nn_ctx *nn_sockbase_getctx (struct nn_sockbase *self)
{
return nn_sock_getctx (self->sock);
}
int nn_sockbase_getopt (struct nn_sockbase *self, int option,
void *optval, size_t *optvallen)
{
return nn_sock_getopt_inner (self->sock, NN_SOL_SOCKET, option,
optval, optvallen);
}
void nn_sockbase_stat_increment (struct nn_sockbase *self, int name,
int increment)
{
nn_sock_stat_increment (self->sock, name, increment);
}
nanomsg-0.8-beta/src/core/symbol.c0000664000175000017500000002436712623652600020046 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Evan Wies
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../nn.h"
#include "../inproc.h"
#include "../ipc.h"
#include "../tcp.h"
#include "../pair.h"
#include "../pubsub.h"
#include "../reqrep.h"
#include "../pipeline.h"
#include "../survey.h"
#include "../bus.h"
#include
static const struct nn_symbol_properties sym_value_names [] = {
{NN_NS_NAMESPACE, "NN_NS_NAMESPACE", NN_NS_NAMESPACE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_NS_VERSION, "NN_NS_VERSION", NN_NS_NAMESPACE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_NS_DOMAIN, "NN_NS_DOMAIN", NN_NS_NAMESPACE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_NS_TRANSPORT, "NN_NS_TRANSPORT", NN_NS_NAMESPACE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_NS_PROTOCOL, "NN_NS_PROTOCOL", NN_NS_NAMESPACE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_NS_OPTION_LEVEL, "NN_NS_OPTION_LEVEL", NN_NS_NAMESPACE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_NS_SOCKET_OPTION, "NN_NS_SOCKET_OPTION", NN_NS_NAMESPACE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_NS_TRANSPORT_OPTION, "NN_NS_TRANSPORT_OPTION", NN_NS_NAMESPACE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_NS_OPTION_TYPE, "NN_NS_OPTION_TYPE", NN_NS_NAMESPACE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_NS_OPTION_UNIT, "NN_NS_OPTION_UNIT", NN_NS_NAMESPACE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_NS_FLAG, "NN_NS_FLAG", NN_NS_NAMESPACE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_NS_ERROR, "NN_NS_ERROR", NN_NS_NAMESPACE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_NS_LIMIT, "NN_NS_LIMIT", NN_NS_NAMESPACE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_NS_EVENT, "NN_NS_EVENT", NN_NS_NAMESPACE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_TYPE_NONE, "NN_TYPE_NONE", NN_NS_OPTION_TYPE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_TYPE_INT, "NN_TYPE_INT", NN_NS_OPTION_TYPE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_TYPE_STR, "NN_TYPE_STR", NN_NS_OPTION_TYPE,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_UNIT_NONE, "NN_UNIT_NONE", NN_NS_OPTION_UNIT,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_UNIT_BYTES, "NN_UNIT_BYTES", NN_NS_OPTION_UNIT,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_UNIT_MILLISECONDS, "NN_UNIT_MILLISECONDS", NN_NS_OPTION_UNIT,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_UNIT_PRIORITY, "NN_UNIT_PRIORITY", NN_NS_OPTION_UNIT,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_UNIT_BOOLEAN, "NN_UNIT_BOOLEAN", NN_NS_OPTION_UNIT,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_VERSION_CURRENT, "NN_VERSION_CURRENT", NN_NS_VERSION,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_VERSION_REVISION, "NN_VERSION_REVISION", NN_NS_VERSION,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_VERSION_AGE, "NN_VERSION_AGE", NN_NS_VERSION,
NN_TYPE_NONE, NN_UNIT_NONE},
{AF_SP, "AF_SP", NN_NS_DOMAIN,
NN_TYPE_NONE, NN_UNIT_NONE},
{AF_SP_RAW, "AF_SP_RAW", NN_NS_DOMAIN,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_INPROC, "NN_INPROC", NN_NS_TRANSPORT,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_IPC, "NN_IPC", NN_NS_TRANSPORT,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_TCP, "NN_TCP", NN_NS_TRANSPORT,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_PAIR, "NN_PAIR", NN_NS_PROTOCOL,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_PUB, "NN_PUB", NN_NS_PROTOCOL,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_SUB, "NN_SUB", NN_NS_PROTOCOL,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_REP, "NN_REP", NN_NS_PROTOCOL,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_REQ, "NN_REQ", NN_NS_PROTOCOL,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_PUSH, "NN_PUSH", NN_NS_PROTOCOL,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_PULL, "NN_PULL", NN_NS_PROTOCOL,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_SURVEYOR, "NN_SURVEYOR", NN_NS_PROTOCOL,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_RESPONDENT, "NN_RESPONDENT", NN_NS_PROTOCOL,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_BUS, "NN_BUS", NN_NS_PROTOCOL,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_SOCKADDR_MAX, "NN_SOCKADDR_MAX", NN_NS_LIMIT,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_SOL_SOCKET, "NN_SOL_SOCKET", NN_NS_OPTION_LEVEL,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_LINGER, "NN_LINGER", NN_NS_SOCKET_OPTION,
NN_TYPE_INT, NN_UNIT_MILLISECONDS},
{NN_SNDBUF, "NN_SNDBUF", NN_NS_SOCKET_OPTION,
NN_TYPE_INT, NN_UNIT_BYTES},
{NN_RCVBUF, "NN_RCVBUF", NN_NS_SOCKET_OPTION,
NN_TYPE_INT, NN_UNIT_BYTES},
{NN_RCVMAXSIZE, "NN_RCVMAXSIZE", NN_NS_SOCKET_OPTION,
NN_TYPE_INT, NN_UNIT_BYTES},
{NN_SNDTIMEO, "NN_SNDTIMEO", NN_NS_SOCKET_OPTION,
NN_TYPE_INT, NN_UNIT_MILLISECONDS},
{NN_RCVTIMEO, "NN_RCVTIMEO", NN_NS_SOCKET_OPTION,
NN_TYPE_INT, NN_UNIT_MILLISECONDS},
{NN_RECONNECT_IVL, "NN_RECONNECT_IVL", NN_NS_SOCKET_OPTION,
NN_TYPE_INT, NN_UNIT_MILLISECONDS},
{NN_RECONNECT_IVL_MAX, "NN_RECONNECT_IVL_MAX", NN_NS_SOCKET_OPTION,
NN_TYPE_INT, NN_UNIT_MILLISECONDS},
{NN_SNDPRIO, "NN_SNDPRIO", NN_NS_SOCKET_OPTION,
NN_TYPE_INT, NN_UNIT_PRIORITY},
{NN_RCVPRIO, "NN_RCVPRIO", NN_NS_SOCKET_OPTION,
NN_TYPE_INT, NN_UNIT_PRIORITY},
{NN_SNDFD, "NN_SNDFD", NN_NS_SOCKET_OPTION,
NN_TYPE_INT, NN_UNIT_NONE},
{NN_RCVFD, "NN_RCVFD", NN_NS_SOCKET_OPTION,
NN_TYPE_INT, NN_UNIT_NONE},
{NN_DOMAIN, "NN_DOMAIN", NN_NS_SOCKET_OPTION,
NN_TYPE_INT, NN_UNIT_NONE},
{NN_PROTOCOL, "NN_PROTOCOL", NN_NS_SOCKET_OPTION,
NN_TYPE_INT, NN_UNIT_NONE},
{NN_IPV4ONLY, "NN_IPV4ONLY", NN_NS_SOCKET_OPTION,
NN_TYPE_INT, NN_UNIT_BOOLEAN},
{NN_SOCKET_NAME, "NN_SOCKET_NAME", NN_NS_SOCKET_OPTION,
NN_TYPE_STR, NN_UNIT_NONE},
{NN_SUB_SUBSCRIBE, "NN_SUB_SUBSCRIBE", NN_NS_TRANSPORT_OPTION,
NN_TYPE_STR, NN_UNIT_NONE},
{NN_SUB_UNSUBSCRIBE, "NN_SUB_UNSUBSCRIBE", NN_NS_TRANSPORT_OPTION,
NN_TYPE_STR, NN_UNIT_NONE},
{NN_REQ_RESEND_IVL, "NN_REQ_RESEND_IVL", NN_NS_TRANSPORT_OPTION,
NN_TYPE_INT, NN_UNIT_MILLISECONDS},
{NN_SURVEYOR_DEADLINE, "NN_SURVEYOR_DEADLINE", NN_NS_TRANSPORT_OPTION,
NN_TYPE_INT, NN_UNIT_MILLISECONDS},
{NN_TCP_NODELAY, "NN_TCP_NODELAY", NN_NS_TRANSPORT_OPTION,
NN_TYPE_INT, NN_UNIT_BOOLEAN},
{NN_DONTWAIT, "NN_DONTWAIT", NN_NS_FLAG,
NN_TYPE_NONE, NN_UNIT_NONE},
{NN_POLLIN, "NN_POLLIN", NN_NS_EVENT, NN_TYPE_NONE, NN_UNIT_NONE},
{NN_POLLOUT, "NN_POLLOUT", NN_NS_EVENT, NN_TYPE_NONE, NN_UNIT_NONE},
{EADDRINUSE, "EADDRINUSE", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{EADDRNOTAVAIL, "EADDRNOTAVAIL", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{EAFNOSUPPORT, "EAFNOSUPPORT", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{EAGAIN, "EAGAIN", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{EBADF, "EBADF", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ECONNREFUSED, "ECONNREFUSED", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{EFAULT, "EFAULT", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{EFSM, "EFSM", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{EINPROGRESS, "EINPROGRESS", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{EINTR, "EINTR", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{EINVAL, "EINVAL", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{EMFILE, "EMFILE", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ENAMETOOLONG, "ENAMETOOLONG", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ENETDOWN, "ENETDOWN", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ENOBUFS, "ENOBUFS", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ENODEV, "ENODEV", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ENOMEM, "ENOMEM", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ENOPROTOOPT, "ENOPROTOOPT", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ENOTSOCK, "ENOTSOCK", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ENOTSUP, "ENOTSUP", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{EPROTO, "EPROTO", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{EPROTONOSUPPORT, "EPROTONOSUPPORT", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ETERM, "ETERM", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ETIMEDOUT, "ETIMEDOUT", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{EACCES, "EACCES" , NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ECONNABORTED, "ECONNABORTED", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ECONNRESET, "ECONNRESET", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{EHOSTUNREACH, "EHOSTUNREACH", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{EMSGSIZE, "EMSGSIZE", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ENETRESET, "ENETRESET", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ENETUNREACH, "ENETUNREACH", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
{ENOTCONN, "ENOTCONN", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE},
};
const int SYM_VALUE_NAMES_LEN = (sizeof (sym_value_names) /
sizeof (sym_value_names [0]));
const char *nn_symbol (int i, int *value)
{
const struct nn_symbol_properties *svn;
if (i < 0 || i >= SYM_VALUE_NAMES_LEN) {
errno = EINVAL;
return NULL;
}
svn = &sym_value_names [i];
if (value)
*value = svn->value;
return svn->name;
}
int nn_symbol_info (int i, struct nn_symbol_properties *buf, int buflen)
{
if (i < 0 || i >= SYM_VALUE_NAMES_LEN) {
return 0;
}
if (buflen > (int)sizeof (struct nn_symbol_properties)) {
buflen = (int)sizeof (struct nn_symbol_properties);
}
memcpy(buf, &sym_value_names [i], buflen);
return buflen;
}
nanomsg-0.8-beta/src/devices/0000775000175000017500000000000012623652617017063 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/devices/device.c0000664000175000017500000002663012623652600020465 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../nn.h"
#include "../utils/err.h"
#include "../utils/fast.h"
#include "../utils/fd.h"
#include "../utils/attr.h"
#include "device.h"
#include
#if defined NN_HAVE_WINDOWS
#include "../utils/win.h"
#elif defined NN_HAVE_POLL
#include
#else
#error
#endif
int nn_custom_device(struct nn_device_recipe *device, int s1, int s2,
int flags)
{
return nn_device_entry (device, s1, s2, flags);
}
int nn_device (int s1, int s2)
{
return nn_custom_device (&nn_ordinary_device, s1, s2, 0);
}
int nn_device_entry (struct nn_device_recipe *device, int s1, int s2,
NN_UNUSED int flags)
{
int rc;
int op1;
int op2;
nn_fd s1rcv;
nn_fd s1snd;
nn_fd s2rcv;
nn_fd s2snd;
size_t opsz;
/* At least one socket must be specified. */
if (device->required_checks & NN_CHECK_AT_LEAST_ONE_SOCKET) {
if (s1 < 0 && s2 < 0) {
errno = EBADF;
return -1;
}
}
/* Handle the case when there's only one socket in the device. */
if (device->required_checks & NN_CHECK_ALLOW_LOOPBACK) {
if (s2 < 0)
return nn_device_loopback (device,s1);
if (s1 < 0)
return nn_device_loopback (device,s2);
}
/* Check whether both sockets are "raw" sockets. */
if (device->required_checks & NN_CHECK_REQUIRE_RAW_SOCKETS) {
opsz = sizeof (op1);
rc = nn_getsockopt (s1, NN_SOL_SOCKET, NN_DOMAIN, &op1, &opsz);
errno_assert (rc == 0);
nn_assert (opsz == sizeof (op1));
opsz = sizeof (op2);
rc = nn_getsockopt (s2, NN_SOL_SOCKET, NN_DOMAIN, &op2, &opsz);
errno_assert (rc == 0);
nn_assert (opsz == sizeof (op2));
if (op1 != AF_SP_RAW || op2 != AF_SP_RAW) {
errno = EINVAL;
return -1;
}
}
/* Check whether both sockets are from the same protocol. */
if (device->required_checks & NN_CHECK_SAME_PROTOCOL_FAMILY) {
opsz = sizeof (op1);
rc = nn_getsockopt (s1, NN_SOL_SOCKET, NN_PROTOCOL, &op1, &opsz);
errno_assert (rc == 0);
nn_assert (opsz == sizeof (op1));
opsz = sizeof (op2);
rc = nn_getsockopt (s2, NN_SOL_SOCKET, NN_PROTOCOL, &op2, &opsz);
errno_assert (rc == 0);
nn_assert (opsz == sizeof (op2));
if (op1 / 16 != op2 / 16) {
errno = EINVAL;
return -1;
}
}
/* Get the file descriptors for polling. */
opsz = sizeof (s1rcv);
rc = nn_getsockopt (s1, NN_SOL_SOCKET, NN_RCVFD, &s1rcv, &opsz);
if (rc < 0 && nn_errno () == ENOPROTOOPT)
s1rcv = -1;
else {
nn_assert (rc == 0);
nn_assert (opsz == sizeof (s1rcv));
nn_assert (s1rcv >= 0);
}
opsz = sizeof (s1snd);
rc = nn_getsockopt (s1, NN_SOL_SOCKET, NN_SNDFD, &s1snd, &opsz);
if (rc < 0 && nn_errno () == ENOPROTOOPT)
s1snd = -1;
else {
nn_assert (rc == 0);
nn_assert (opsz == sizeof (s1snd));
nn_assert (s1snd >= 0);
}
opsz = sizeof (s2rcv);
rc = nn_getsockopt (s2, NN_SOL_SOCKET, NN_RCVFD, &s2rcv, &opsz);
if (rc < 0 && nn_errno () == ENOPROTOOPT)
s2rcv = -1;
else {
nn_assert (rc == 0);
nn_assert (opsz == sizeof (s2rcv));
nn_assert (s2rcv >= 0);
}
opsz = sizeof (s2snd);
rc = nn_getsockopt (s2, NN_SOL_SOCKET, NN_SNDFD, &s2snd, &opsz);
if (rc < 0 && nn_errno () == ENOPROTOOPT)
s2snd = -1;
else {
nn_assert (rc == 0);
nn_assert (opsz == sizeof (s2snd));
nn_assert (s2snd >= 0);
}
if (device->required_checks & NN_CHECK_SOCKET_DIRECTIONALITY) {
/* Check the directionality of the sockets. */
if (s1rcv != -1 && s2snd == -1) {
errno = EINVAL;
return -1;
}
if (s1snd != -1 && s2rcv == -1) {
errno = EINVAL;
return -1;
}
if (s2rcv != -1 && s1snd == -1) {
errno = EINVAL;
return -1;
}
if (s2snd != -1 && s1rcv == -1) {
errno = EINVAL;
return -1;
}
}
/* Two-directional device. */
if (device->required_checks & NN_CHECK_ALLOW_BIDIRECTIONAL) {
if (s1rcv != -1 && s1snd != -1 && s2rcv != -1 && s2snd != -1)
return nn_device_twoway (device, s1, s1rcv, s1snd,
s2, s2rcv, s2snd);
}
if (device->required_checks & NN_CHECK_ALLOW_UNIDIRECTIONAL) {
/* Single-directional device passing messages from s1 to s2. */
if (s1rcv != -1 && s1snd == -1 && s2rcv == -1 && s2snd != -1)
return nn_device_oneway (device,s1, s1rcv, s2, s2snd);
/* Single-directional device passing messages from s2 to s1. */
if (s1rcv == -1 && s1snd != -1 && s2rcv != -1 && s2snd == -1)
return nn_device_oneway (device,s2, s2rcv, s1, s1snd);
}
/* This should never happen. */
nn_assert (0);
}
int nn_device_loopback (struct nn_device_recipe *device, int s)
{
int rc;
int op;
size_t opsz;
/* Check whether the socket is a "raw" socket. */
opsz = sizeof (op);
rc = nn_getsockopt (s, NN_SOL_SOCKET, NN_DOMAIN, &op, &opsz);
errno_assert (rc == 0);
nn_assert (opsz == sizeof (op));
if (op != AF_SP_RAW) {
errno = EINVAL;
return -1;
}
while (1) {
rc = nn_device_mvmsg (device,s, s, 0);
if (nn_slow (rc < 0))
return -1;
}
}
#if defined NN_HAVE_WINDOWS
int nn_device_twoway (struct nn_device_recipe *device,
int s1, nn_fd s1rcv, nn_fd s1snd,
int s2, nn_fd s2rcv, nn_fd s2snd)
{
int rc;
fd_set fds;
int s1rcv_isready = 0;
int s1snd_isready = 0;
int s2rcv_isready = 0;
int s2snd_isready = 0;
/* Initialise the pollset. */
FD_ZERO (&fds);
while (1) {
/* Wait for network events. Adjust the 'ready' events based
on the result. */
if (s1rcv_isready)
FD_CLR (s1rcv, &fds);
else
FD_SET (s1rcv, &fds);
if (s1snd_isready)
FD_CLR (s1snd, &fds);
else
FD_SET (s1snd, &fds);
if (s2rcv_isready)
FD_CLR (s2rcv, &fds);
else
FD_SET (s2rcv, &fds);
if (s2snd_isready)
FD_CLR (s2snd, &fds);
else
FD_SET (s2snd, &fds);
rc = select (0, &fds, NULL, NULL, NULL);
wsa_assert (rc != SOCKET_ERROR);
if (FD_ISSET (s1rcv, &fds))
s1rcv_isready = 1;
if (FD_ISSET (s1snd, &fds))
s1snd_isready = 1;
if (FD_ISSET (s2rcv, &fds))
s2rcv_isready = 1;
if (FD_ISSET (s2snd, &fds))
s2snd_isready = 1;
/* If possible, pass the message from s1 to s2. */
if (s1rcv_isready && s2snd_isready) {
rc = nn_device_mvmsg (device,s1, s2, NN_DONTWAIT);
if (nn_slow (rc < 0))
return -1;
s1rcv_isready = 0;
s2snd_isready = 0;
}
/* If possible, pass the message from s2 to s1. */
if (s2rcv_isready && s1snd_isready) {
rc = nn_device_mvmsg (device,s2, s1, NN_DONTWAIT);
if (nn_slow (rc < 0))
return -1;
s2rcv_isready = 0;
s1snd_isready = 0;
}
}
}
#elif defined NN_HAVE_POLL
int nn_device_twoway (struct nn_device_recipe *device,
int s1, nn_fd s1rcv, nn_fd s1snd,
int s2, nn_fd s2rcv, nn_fd s2snd)
{
int rc;
struct pollfd pfd [4];
/* Initialise the pollset. */
pfd [0].fd = s1rcv;
pfd [0].events = POLLIN;
pfd [1].fd = s1snd;
pfd [1].events = POLLIN;
pfd [2].fd = s2rcv;
pfd [2].events = POLLIN;
pfd [3].fd = s2snd;
pfd [3].events = POLLIN;
while (1) {
/* Wait for network events. */
rc = poll (pfd, 4, -1);
errno_assert (rc >= 0);
if (nn_slow (rc < 0 && errno == EINTR))
return -1;
nn_assert (rc != 0);
/* Process the events. When the event is received, we cease polling
for it. */
if (pfd [0].revents & POLLIN)
pfd [0].events = 0;
if (pfd [1].revents & POLLIN)
pfd [1].events = 0;
if (pfd [2].revents & POLLIN)
pfd [2].events = 0;
if (pfd [3].revents & POLLIN)
pfd [3].events = 0;
/* If possible, pass the message from s1 to s2. */
if (pfd [0].events == 0 && pfd [3].events == 0) {
rc = nn_device_mvmsg (device, s1, s2, NN_DONTWAIT);
if (nn_slow (rc < 0))
return -1;
pfd [0].events = POLLIN;
pfd [3].events = POLLIN;
}
/* If possible, pass the message from s2 to s1. */
if (pfd [2].events == 0 && pfd [1].events == 0) {
rc = nn_device_mvmsg (device, s2, s1, NN_DONTWAIT);
if (nn_slow (rc < 0))
return -1;
pfd [2].events = POLLIN;
pfd [1].events = POLLIN;
}
}
}
#else
#error
#endif
int nn_device_oneway (struct nn_device_recipe *device,
int s1, NN_UNUSED nn_fd s1rcv,
int s2, NN_UNUSED nn_fd s2snd)
{
int rc;
while (1) {
rc = nn_device_mvmsg (device, s1, s2, 0);
if (nn_slow (rc < 0))
return -1;
}
}
int nn_device_mvmsg (struct nn_device_recipe *device,
int from, int to, int flags)
{
int rc;
void *body;
void *control;
struct nn_iovec iov;
struct nn_msghdr hdr;
iov.iov_base = &body;
iov.iov_len = NN_MSG;
memset (&hdr, 0, sizeof (hdr));
hdr.msg_iov = &iov;
hdr.msg_iovlen = 1;
hdr.msg_control = &control;
hdr.msg_controllen = NN_MSG;
rc = nn_recvmsg (from, &hdr, flags);
if (nn_slow (rc < 0 && (nn_errno () == ETERM || nn_errno () == EBADF)))
return -1;
errno_assert (rc >= 0);
rc = device->nn_device_rewritemsg (device, from, to, flags, &hdr, rc);
if (nn_slow (rc == -1))
return -1;
else if (rc == 0)
return 0;
nn_assert(rc == 1);
rc = nn_sendmsg (to, &hdr, flags);
if (nn_slow (rc < 0 && nn_errno () == ETERM))
return -1;
errno_assert (rc >= 0);
return 0;
}
int nn_device_rewritemsg (NN_UNUSED struct nn_device_recipe *device,
NN_UNUSED int from, NN_UNUSED int to, NN_UNUSED int flags,
NN_UNUSED struct nn_msghdr *msghdr, NN_UNUSED int bytes)
{
return 1; /* always forward */
}
nanomsg-0.8-beta/src/devices/device.h0000664000175000017500000001147212623652600020470 0ustar00travistravis00000000000000/*
Copyright (c) 2014 Drew Crawford. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
/* Base class for device. */
struct nn_device_recipe {
/* NN_CHECK flags. */
int required_checks;
/* The entry function. This checks the inputs according to the
required_checks flag, chooses the polling function, and starts
the device. You can override this function to implement
additional checks.*/
int(*nn_device_entry) (struct nn_device_recipe *device,
int s1, int s2, int flags);
/* The two-way poll function. */
int (*nn_device_twoway) (struct nn_device_recipe *device,
int s1, nn_fd s1rcv, nn_fd s1snd, int s2, nn_fd s2rcv, nn_fd s2snd);
/* The one-way poll function. */
int (*nn_device_oneway) (struct nn_device_recipe *device,
int s1, nn_fd s1rcv, int s2, nn_fd s2snd);
int (*nn_device_loopback) (struct nn_device_recipe *device, int s);
/* The movemsg function. */
int (*nn_device_mvmsg) (struct nn_device_recipe *device,
int from, int to, int flags);
/* The message intercept function. This function gives you an opportunity
to modify or cancel an nn_msghdr as it passes from one socket
to the other.
from - the socket that the msghdr was received from
to - the socket where it is going
flags - the flags that are being used for send and receive functions
msghdr - the nn_msghdr that was received from the from socket
bytes - the actual received length of the msg.
The nn_msghdr->msg_iov->iov_len is not valid because
it contains NN_MSG
return values:
1 indicates that the msghdr should be forwarded.
0 indicates that the msghdr should *not* be forwarded,
e.g. the message is dropped in the device
-1 indicates an error. Set errno.
*/
int (*nn_device_rewritemsg) (struct nn_device_recipe *device,
int from, int to, int flags, struct nn_msghdr *msghdr, int bytes);
};
/* Default implementations of the functions. */
int nn_device_loopback (struct nn_device_recipe *device, int s);
int nn_device_twoway (struct nn_device_recipe *device,
int s1, nn_fd s1rcv, nn_fd s1snd, int s2, nn_fd s2rcv, nn_fd s2snd);
int nn_device_oneway (struct nn_device_recipe *device,
int s1, nn_fd s1rcv, int s2, nn_fd s2snd);
int nn_device_mvmsg (struct nn_device_recipe *device,
int from, int to, int flags);
int nn_device_entry(struct nn_device_recipe *device,
int s1, int s2, int flags);
int nn_device_rewritemsg(struct nn_device_recipe *device,
int from, int to, int flags, struct nn_msghdr *msghdr, int bytes);
/* At least one socket must be passed to the device. */
#define NN_CHECK_AT_LEAST_ONE_SOCKET (1 << 0)
/* Loopback devices are allowed. */
#define NN_CHECK_ALLOW_LOOPBACK (1 << 1)
/* Bidirectional devices are allowed. */
#define NN_CHECK_ALLOW_BIDIRECTIONAL (1 << 2)
/* Unidirectional devices are allowed. */
#define NN_CHECK_ALLOW_UNIDIRECTIONAL (1<<3)
/* Both sockets must be raw. */
#define NN_CHECK_REQUIRE_RAW_SOCKETS (1 << 4)
/* Both sockets must be same protocol family. */
#define NN_CHECK_SAME_PROTOCOL_FAMILY (1 << 5)
/* Check socket directionality. */
#define NN_CHECK_SOCKET_DIRECTIONALITY (1 << 6)
/* Allows spawning a custom device from a recipe */
int nn_custom_device(struct nn_device_recipe *device,
int s1, int s2, int flags);
static struct nn_device_recipe nn_ordinary_device = {
NN_CHECK_AT_LEAST_ONE_SOCKET | NN_CHECK_ALLOW_LOOPBACK | NN_CHECK_ALLOW_BIDIRECTIONAL | NN_CHECK_REQUIRE_RAW_SOCKETS | NN_CHECK_SAME_PROTOCOL_FAMILY | NN_CHECK_SOCKET_DIRECTIONALITY | NN_CHECK_ALLOW_UNIDIRECTIONAL,
nn_device_entry,
nn_device_twoway,
nn_device_oneway,
nn_device_loopback,
nn_device_mvmsg,
nn_device_rewritemsg
};
nanomsg-0.8-beta/src/devices/tcpmuxd.c0000664000175000017500000002721012623652600020705 0ustar00travistravis00000000000000/*
Copyright (c) 2014 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "../nn.h"
#if defined NN_HAVE_WINDOWS
#include "../utils/err.h"
int nn_tcpmuxd (int port)
{
errno = EPROTONOSUPPORT;
return -1;
}
#else
#include "../utils/thread.h"
#include "../utils/attr.h"
#include "../utils/err.h"
#include "../utils/int.h"
#include "../utils/cont.h"
#include "../utils/wire.h"
#include "../utils/alloc.h"
#include "../utils/list.h"
#include "../utils/mutex.h"
#include "../utils/closefd.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct nn_tcpmuxd_ctx {
int tcp_listener;
int ipc_listener;
struct nn_list conns;
struct pollfd *pfd;
size_t pfd_size;
size_t pfd_capacity;
struct nn_thread thread;
};
struct nn_tcpmuxd_conn {
int fd;
char *service;
struct nn_list_item item;
};
/* Forward declarations. */
static void nn_tcpmuxd_routine (void *arg);
static void nn_tcpmuxd_disconnect (struct nn_tcpmuxd_ctx *ctx, int i);
static int nn_tcpmuxd_send_fd (int s, int fd);
int nn_tcpmuxd (int port)
{
int rc;
int tcp_listener;
int ipc_listener;
int opt;
struct sockaddr_in tcp_addr;
struct sockaddr_un ipc_addr;
struct nn_tcpmuxd_ctx *ctx;
/* Start listening on the specified TCP port. */
errno = 0;
tcp_listener = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (tcp_listener < 0) { return -1; }
opt = 1;
rc = setsockopt (tcp_listener, SOL_SOCKET, SO_REUSEADDR, &opt,
sizeof (opt));
if (rc != 0) { return -1; }
memset (&tcp_addr, 0, sizeof (tcp_addr));
tcp_addr.sin_family = AF_INET;
tcp_addr.sin_port = htons (port);
tcp_addr.sin_addr.s_addr = INADDR_ANY;
rc = bind (tcp_listener, (struct sockaddr*) &tcp_addr, sizeof (tcp_addr));
if (rc != 0) { return -1; }
rc = listen (tcp_listener, 100);
if (rc != 0) { return -1; }
/* Start listening for incoming IPC connections. */
ipc_addr.sun_family = AF_UNIX;
snprintf (ipc_addr.sun_path, sizeof (ipc_addr.sun_path),
"/tmp/tcpmux-%d.ipc", (int) port);
unlink (ipc_addr.sun_path);
errno = 0;
ipc_listener = socket (AF_UNIX, SOCK_STREAM, 0);
if (ipc_listener < 0) {
return -1;
}
rc = bind (ipc_listener, (struct sockaddr*) &ipc_addr, sizeof (ipc_addr));
if (rc != 0) { return -1; }
rc = listen (ipc_listener, 100);
if (rc != 0) { return -1; }
/* Allocate a context for the daemon. */
ctx = nn_alloc (sizeof (struct nn_tcpmuxd_ctx), "tcpmuxd context");
alloc_assert (ctx);
ctx->tcp_listener = tcp_listener;
ctx->ipc_listener = ipc_listener;
nn_list_init (&ctx->conns);
ctx->pfd = nn_alloc (sizeof (struct pollfd) * 16, "tcpmuxd pollfd");
alloc_assert (ctx->pfd);
ctx->pfd_capacity = 16;
ctx->pfd [0].fd = tcp_listener;
ctx->pfd [0].events = POLLIN;
ctx->pfd [1].fd = ipc_listener;
ctx->pfd [1].events = POLLIN;
ctx->pfd_size = 2;
/* Run the daemon in a dedicated thread. */
nn_thread_init (&ctx->thread, nn_tcpmuxd_routine, ctx);
return 0;
}
/* Main body of the daemon. */
static void nn_tcpmuxd_routine (void *arg)
{
int rc;
struct nn_tcpmuxd_ctx *ctx;
int conn;
size_t pos;
char service [256];
struct nn_tcpmuxd_conn *tc;
size_t sz;
ssize_t ssz;
int i;
struct nn_list_item *it;
unsigned char buf [2];
struct timeval tv;
ctx = (struct nn_tcpmuxd_ctx*) arg;
while (1) {
/* Wait for events. */
rc = poll (ctx->pfd, ctx->pfd_size, -1);
errno_assert (rc >= 0);
nn_assert (rc != 0);
/* There's an incoming TCP connection. */
if (ctx->pfd [0].revents & POLLIN) {
/* Accept the connection. */
conn = accept (ctx->tcp_listener, NULL, NULL);
if (conn < 0 && errno == ECONNABORTED)
continue;
errno_assert (conn >= 0);
/* Set timeouts to prevent malevolent client blocking the service.
Note that these options are not supported on Solaris. */
tv.tv_sec = 0;
tv.tv_usec = 100000;
rc = setsockopt (conn, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof (tv));
errno_assert (rc == 0 || (rc < 0 && errno == ENOPROTOOPT));
rc = setsockopt (conn, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof (tv));
errno_assert (rc == 0 || (rc < 0 && errno == ENOPROTOOPT));
/* Read TCPMUX header. */
pos = 0;
while (1) {
nn_assert (pos < sizeof (service));
ssz = recv (conn, &service [pos], 1, 0);
if (ssz < 0 && errno == EAGAIN) {
close (conn);
continue;
}
errno_assert (ssz >= 0);
nn_assert (ssz == 1);
service [pos] = tolower (service [pos]);
if (pos > 0 && service [pos - 1] == 0x0d &&
service [pos] == 0x0a)
break;
++pos;
}
service [pos - 1] = 0;
/* Check whether specified service is listening. */
for (it = nn_list_begin (&ctx->conns);
it != nn_list_end (&ctx->conns);
it = nn_list_next (&ctx->conns, it)) {
tc = nn_cont (it, struct nn_tcpmuxd_conn, item);
if (strcmp (service, tc->service) == 0)
break;
}
/* If no one is listening, tear down the connection. */
if (it == nn_list_end (&ctx->conns)) {
ssz = send (conn, "-\x0d\x0a", 3, 0);
if (ssz < 0 && errno == EAGAIN) {
close (conn);
continue;
}
errno_assert (ssz >= 0);
nn_assert (ssz == 3);
close (conn);
continue;
}
/* Send TCPMUX reply. */
ssz = send (conn, "+\x0d\x0a", 3, 0);
if (ssz < 0 && errno == EAGAIN) {
close (conn);
continue;
}
errno_assert (ssz >= 0);
nn_assert (ssz == 3);
/* Pass the file descriptor to the listening process. */
rc = nn_tcpmuxd_send_fd (tc->fd, conn);
errno_assert (rc == 0);
}
/* There's an incoming IPC connection. */
if (ctx->pfd [1].revents & POLLIN) {
/* Accept the connection. */
conn = accept (ctx->ipc_listener, NULL, NULL);
if (conn < 0 && errno == ECONNABORTED)
continue;
errno_assert (conn >= 0);
/* Create new connection entry. */
tc = nn_alloc (sizeof (struct nn_tcpmuxd_conn), "tcpmuxd_conn");
nn_assert (tc);
tc->fd = conn;
nn_list_item_init (&tc->item);
/* Adjust the pollset. We will poll for errors only. */
ctx->pfd_size++;
if (ctx->pfd_size > ctx->pfd_capacity) {
ctx->pfd_capacity *= 2;
ctx->pfd = nn_realloc (ctx->pfd,
sizeof (struct pollfd) * ctx->pfd_capacity);
alloc_assert (ctx->pfd);
}
ctx->pfd [ctx->pfd_size - 1].fd = conn;
ctx->pfd [ctx->pfd_size - 1].events = 0;
ctx->pfd [ctx->pfd_size - 1].revents = 0;
/* Read the connection header. */
ssz = recv (conn, buf, 2, 0);
errno_assert (ssz >= 0);
nn_assert (ssz == 2);
sz = nn_gets (buf);
tc->service = nn_alloc (sz + 1, "tcpmuxd_conn.service");
nn_assert (tc->service);
ssz = recv (conn, tc->service, sz, 0);
errno_assert (ssz >= 0);
nn_assert ((size_t)ssz == sz);
for (i = 0; (size_t)i != sz; ++i)
tc->service [i] = tolower (tc->service [i]);
tc->service [sz] = 0;
/* Add the entry to the IPC connections list. */
nn_list_insert (&ctx->conns, &tc->item, nn_list_end (&ctx->conns));
}
for (i = 2; (size_t)i < ctx->pfd_size; ++i) {
if (ctx->pfd [i].revents & POLLERR ||
ctx->pfd [i].revents & POLLHUP) {
nn_tcpmuxd_disconnect (ctx, i);
i--;
}
}
}
}
/* Tear down the IPC connection with index i in the pollset. */
static void nn_tcpmuxd_disconnect (struct nn_tcpmuxd_ctx *ctx, int i)
{
int fd;
struct nn_list_item *it;
struct nn_tcpmuxd_conn *conn;
fd = ctx->pfd [i].fd;
/* Remove the descriptor from the pollset. */
if (ctx->pfd_size > 3)
ctx->pfd [i] = ctx->pfd [ctx->pfd_size - 1];
ctx->pfd_size--;
/* Remove the connection entry. */
for (it = nn_list_begin (&ctx->conns);
it != nn_list_end (&ctx->conns);
it = nn_list_next (&ctx->conns, it)) {
conn = nn_cont (it, struct nn_tcpmuxd_conn, item);
if (conn->fd == fd) {
nn_list_erase (&ctx->conns, it);
nn_free (conn->service);
nn_free (conn);
break;
}
}
}
/* Send file descriptor fd to IPC socket s. */
static int nn_tcpmuxd_send_fd (int s, int fd)
{
int rc;
struct iovec iov;
char c = 0;
struct msghdr msg;
char control [sizeof (struct cmsghdr) + 10];
#if defined NN_HAVE_MSG_CONTROL
struct cmsghdr *cmsg;
#endif
/* Compose the message. We'll send one byte long dummy message
accompanied with the fd.*/
iov.iov_base = &c;
iov.iov_len = 1;
memset (&msg, 0, sizeof (msg));
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
/* Attach the file descriptor to the message. */
#if defined NN_HAVE_MSG_CONTROL
msg.msg_control = control;
msg.msg_controllen = sizeof (control);
cmsg = CMSG_FIRSTHDR (&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN (sizeof (fd));
int *data = (int*) CMSG_DATA (cmsg);
*data = fd;
msg.msg_controllen = cmsg->cmsg_len;
#else
msg.msg_accrights = (caddr_t) &fd;
msg.msg_accrightslen = sizeof (fd);
#endif
/* Pass the file descriptor to the registered process. */
rc = sendmsg (s, &msg, 0);
if (rc < 0)
return -1;
nn_assert (rc == 1);
/* Sending the file descriptor to other process acts as dup().
Therefore, we have to close the local copy of the file descriptor. */
nn_closefd (fd);
return 0;
}
#endif
nanomsg-0.8-beta/src/protocols/0000775000175000017500000000000012623652617017465 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/protocols/bus/0000775000175000017500000000000012623652617020256 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/protocols/bus/bus.h0000664000175000017500000000240112623652600021205 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_BUS_INCLUDED
#define NN_BUS_INCLUDED
#include "../../protocol.h"
extern struct nn_socktype *nn_bus_socktype;
#endif
nanomsg-0.8-beta/src/protocols/bus/bus.c0000664000175000017500000000756212623652600021215 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "bus.h"
#include "xbus.h"
#include "../../nn.h"
#include "../../bus.h"
#include "../../utils/cont.h"
#include "../../utils/alloc.h"
#include "../../utils/err.h"
#include "../../utils/list.h"
struct nn_bus {
struct nn_xbus xbus;
};
/* Private functions. */
static void nn_bus_init (struct nn_bus *self,
const struct nn_sockbase_vfptr *vfptr, void *hint);
static void nn_bus_term (struct nn_bus *self);
/* Implementation of nn_sockbase's virtual functions. */
static void nn_bus_destroy (struct nn_sockbase *self);
static int nn_bus_send (struct nn_sockbase *self, struct nn_msg *msg);
static int nn_bus_recv (struct nn_sockbase *self, struct nn_msg *msg);
static const struct nn_sockbase_vfptr nn_bus_sockbase_vfptr = {
NULL,
nn_bus_destroy,
nn_xbus_add,
nn_xbus_rm,
nn_xbus_in,
nn_xbus_out,
nn_xbus_events,
nn_bus_send,
nn_bus_recv,
nn_xbus_setopt,
nn_xbus_getopt
};
static void nn_bus_init (struct nn_bus *self,
const struct nn_sockbase_vfptr *vfptr, void *hint)
{
nn_xbus_init (&self->xbus, vfptr, hint);
}
static void nn_bus_term (struct nn_bus *self)
{
nn_xbus_term (&self->xbus);
}
static void nn_bus_destroy (struct nn_sockbase *self)
{
struct nn_bus *bus;
bus = nn_cont (self, struct nn_bus, xbus.sockbase);
nn_bus_term (bus);
nn_free (bus);
}
static int nn_bus_send (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
struct nn_bus *bus;
bus = nn_cont (self, struct nn_bus, xbus.sockbase);
/* Check for malformed messages. */
if (nn_chunkref_size (&msg->sphdr))
return -EINVAL;
/* Send the message. */
rc = nn_xbus_send (&bus->xbus.sockbase, msg);
errnum_assert (rc == 0, -rc);
return 0;
}
static int nn_bus_recv (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
struct nn_bus *bus;
bus = nn_cont (self, struct nn_bus, xbus.sockbase);
/* Get next message. */
rc = nn_xbus_recv (&bus->xbus.sockbase, msg);
if (nn_slow (rc == -EAGAIN))
return -EAGAIN;
errnum_assert (rc == 0, -rc);
nn_assert (nn_chunkref_size (&msg->sphdr) == sizeof (uint64_t));
/* Discard the header. */
nn_chunkref_term (&msg->sphdr);
nn_chunkref_init (&msg->sphdr, 0);
return 0;
}
static int nn_bus_create (void *hint, struct nn_sockbase **sockbase)
{
struct nn_bus *self;
self = nn_alloc (sizeof (struct nn_bus), "socket (bus)");
alloc_assert (self);
nn_bus_init (self, &nn_bus_sockbase_vfptr, hint);
*sockbase = &self->xbus.sockbase;
return 0;
}
static struct nn_socktype nn_bus_socktype_struct = {
AF_SP,
NN_BUS,
0,
nn_bus_create,
nn_xbus_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_bus_socktype = &nn_bus_socktype_struct;
nanomsg-0.8-beta/src/protocols/bus/xbus.h0000664000175000017500000000450512623652600021404 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_XBUS_INCLUDED
#define NN_XBUS_INCLUDED
#include "../../protocol.h"
#include "../utils/dist.h"
#include "../utils/fq.h"
extern struct nn_socktype *nn_xbus_socktype;
struct nn_xbus_data {
struct nn_dist_data outitem;
struct nn_fq_data initem;
};
struct nn_xbus {
struct nn_sockbase sockbase;
struct nn_dist outpipes;
struct nn_fq inpipes;
};
void nn_xbus_init (struct nn_xbus *self,
const struct nn_sockbase_vfptr *vfptr, void *hint);
void nn_xbus_term (struct nn_xbus *self);
int nn_xbus_add (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_xbus_rm (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_xbus_in (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_xbus_out (struct nn_sockbase *self, struct nn_pipe *pipe);
int nn_xbus_events (struct nn_sockbase *self);
int nn_xbus_send (struct nn_sockbase *self, struct nn_msg *msg);
int nn_xbus_recv (struct nn_sockbase *self, struct nn_msg *msg);
int nn_xbus_setopt (struct nn_sockbase *self, int level, int option,
const void *optval, size_t optvallen);
int nn_xbus_getopt (struct nn_sockbase *self, int level, int option,
void *optval, size_t *optvallen);
int nn_xbus_ispeer (int socktype);
#endif
nanomsg-0.8-beta/src/protocols/bus/xbus.c0000664000175000017500000001515412623652600021401 0ustar00travistravis00000000000000/*
Copyright (c) 2013-2014 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "xbus.h"
#include "../../nn.h"
#include "../../bus.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/alloc.h"
#include "../../utils/list.h"
#include "../../utils/int.h"
#include "../../utils/attr.h"
#include
#include
/* To make the algorithm super efficient we directly cast pipe pointers to
pipe IDs (rather than maintaining a hash table). For this to work, it is
neccessary for the pointer to fit in 64-bit ID. */
CT_ASSERT (sizeof (uint64_t) >= sizeof (struct nn_pipe*));
/* Implementation of nn_sockbase's virtual functions. */
static void nn_xbus_destroy (struct nn_sockbase *self);
static const struct nn_sockbase_vfptr nn_xbus_sockbase_vfptr = {
NULL,
nn_xbus_destroy,
nn_xbus_add,
nn_xbus_rm,
nn_xbus_in,
nn_xbus_out,
nn_xbus_events,
nn_xbus_send,
nn_xbus_recv,
nn_xbus_setopt,
nn_xbus_getopt
};
void nn_xbus_init (struct nn_xbus *self,
const struct nn_sockbase_vfptr *vfptr, void *hint)
{
nn_sockbase_init (&self->sockbase, vfptr, hint);
nn_dist_init (&self->outpipes);
nn_fq_init (&self->inpipes);
}
void nn_xbus_term (struct nn_xbus *self)
{
nn_fq_term (&self->inpipes);
nn_dist_term (&self->outpipes);
nn_sockbase_term (&self->sockbase);
}
static void nn_xbus_destroy (struct nn_sockbase *self)
{
struct nn_xbus *xbus;
xbus = nn_cont (self, struct nn_xbus, sockbase);
nn_xbus_term (xbus);
nn_free (xbus);
}
int nn_xbus_add (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xbus *xbus;
struct nn_xbus_data *data;
int rcvprio;
size_t sz;
xbus = nn_cont (self, struct nn_xbus, sockbase);
sz = sizeof (rcvprio);
nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, &sz);
nn_assert (sz == sizeof (rcvprio));
nn_assert (rcvprio >= 1 && rcvprio <= 16);
data = nn_alloc (sizeof (struct nn_xbus_data), "pipe data (xbus)");
alloc_assert (data);
nn_fq_add (&xbus->inpipes, &data->initem, pipe, rcvprio);
nn_dist_add (&xbus->outpipes, &data->outitem, pipe);
nn_pipe_setdata (pipe, data);
return 0;
}
void nn_xbus_rm (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xbus *xbus;
struct nn_xbus_data *data;
xbus = nn_cont (self, struct nn_xbus, sockbase);
data = nn_pipe_getdata (pipe);
nn_fq_rm (&xbus->inpipes, &data->initem);
nn_dist_rm (&xbus->outpipes, &data->outitem);
nn_free (data);
}
void nn_xbus_in (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xbus *xbus;
struct nn_xbus_data *data;
xbus = nn_cont (self, struct nn_xbus, sockbase);
data = nn_pipe_getdata (pipe);
nn_fq_in (&xbus->inpipes, &data->initem);
}
void nn_xbus_out (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xbus *xbus;
struct nn_xbus_data *data;
xbus = nn_cont (self, struct nn_xbus, sockbase);
data = nn_pipe_getdata (pipe);
nn_dist_out (&xbus->outpipes, &data->outitem);
}
int nn_xbus_events (struct nn_sockbase *self)
{
return (nn_fq_can_recv (&nn_cont (self, struct nn_xbus,
sockbase)->inpipes) ? NN_SOCKBASE_EVENT_IN : 0) | NN_SOCKBASE_EVENT_OUT;
}
int nn_xbus_send (struct nn_sockbase *self, struct nn_msg *msg)
{
size_t hdrsz;
struct nn_pipe *exclude;
hdrsz = nn_chunkref_size (&msg->sphdr);
if (hdrsz == 0)
exclude = NULL;
else if (hdrsz == sizeof (uint64_t)) {
memcpy (&exclude, nn_chunkref_data (&msg->sphdr), sizeof (exclude));
nn_chunkref_term (&msg->sphdr);
nn_chunkref_init (&msg->sphdr, 0);
}
else
return -EINVAL;
return nn_dist_send (&nn_cont (self, struct nn_xbus, sockbase)->outpipes,
msg, exclude);
}
int nn_xbus_recv (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
struct nn_xbus *xbus;
struct nn_pipe *pipe;
xbus = nn_cont (self, struct nn_xbus, sockbase);
while (1) {
/* Get next message in fair-queued manner. */
rc = nn_fq_recv (&xbus->inpipes, msg, &pipe);
if (nn_slow (rc < 0))
return rc;
/* The message should have no header. Drop malformed messages. */
if (nn_chunkref_size (&msg->sphdr) == 0)
break;
nn_msg_term (msg);
}
/* Add pipe ID to the message header. */
nn_chunkref_term (&msg->sphdr);
nn_chunkref_init (&msg->sphdr, sizeof (uint64_t));
memset (nn_chunkref_data (&msg->sphdr), 0, sizeof (uint64_t));
memcpy (nn_chunkref_data (&msg->sphdr), &pipe, sizeof (pipe));
return 0;
}
int nn_xbus_setopt (NN_UNUSED struct nn_sockbase *self, NN_UNUSED int level,
NN_UNUSED int option,
NN_UNUSED const void *optval, NN_UNUSED size_t optvallen)
{
return -ENOPROTOOPT;
}
int nn_xbus_getopt (NN_UNUSED struct nn_sockbase *self, NN_UNUSED int level,
NN_UNUSED int option,
NN_UNUSED void *optval, NN_UNUSED size_t *optvallen)
{
return -ENOPROTOOPT;
}
static int nn_xbus_create (void *hint, struct nn_sockbase **sockbase)
{
struct nn_xbus *self;
self = nn_alloc (sizeof (struct nn_xbus), "socket (bus)");
alloc_assert (self);
nn_xbus_init (self, &nn_xbus_sockbase_vfptr, hint);
*sockbase = &self->sockbase;
return 0;
}
int nn_xbus_ispeer (int socktype)
{
return socktype == NN_BUS ? 1 : 0;
}
static struct nn_socktype nn_xbus_socktype_struct = {
AF_SP_RAW,
NN_BUS,
0,
nn_xbus_create,
nn_xbus_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_xbus_socktype = &nn_xbus_socktype_struct;
nanomsg-0.8-beta/src/protocols/pair/0000775000175000017500000000000012623652617020420 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/protocols/pair/pair.h0000664000175000017500000000241112623652600021512 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_PAIR_INCLUDED
#define NN_PAIR_INCLUDED
#include "../../protocol.h"
extern struct nn_socktype *nn_pair_socktype;
#endif
nanomsg-0.8-beta/src/protocols/pair/pair.c0000664000175000017500000000273112623652600021512 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "pair.h"
#include "xpair.h"
#include "../../nn.h"
#include "../../pair.h"
#include "../../utils/list.h"
static struct nn_socktype nn_pair_socktype_struct = {
AF_SP,
NN_PAIR,
0,
nn_xpair_create,
nn_xpair_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_pair_socktype = &nn_pair_socktype_struct;
nanomsg-0.8-beta/src/protocols/pair/xpair.h0000664000175000017500000000256212623652600021711 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_XPAIR_INCLUDED
#define NN_XPAIR_INCLUDED
#include "../../protocol.h"
extern struct nn_socktype *nn_xpair_socktype;
int nn_xpair_create (void *hint, struct nn_sockbase **sockbase);
int nn_xpair_ispeer (int socktype);
#endif
nanomsg-0.8-beta/src/protocols/pair/xpair.c0000664000175000017500000001314012623652600021676 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "xpair.h"
#include "../../nn.h"
#include "../../pair.h"
#include "../utils/excl.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/alloc.h"
#include "../../utils/list.h"
#include "../../utils/attr.h"
struct nn_xpair {
struct nn_sockbase sockbase;
struct nn_excl excl;
};
/* Private functions. */
static void nn_xpair_init (struct nn_xpair *self,
const struct nn_sockbase_vfptr *vfptr, void *hint);
static void nn_xpair_term (struct nn_xpair *self);
/* Implementation of nn_sockbase's virtual functions. */
static void nn_xpair_destroy (struct nn_sockbase *self);
static int nn_xpair_add (struct nn_sockbase *self, struct nn_pipe *pipe);
static void nn_xpair_rm (struct nn_sockbase *self, struct nn_pipe *pipe);
static void nn_xpair_in (struct nn_sockbase *self, struct nn_pipe *pipe);
static void nn_xpair_out (struct nn_sockbase *self, struct nn_pipe *pipe);
static int nn_xpair_events (struct nn_sockbase *self);
static int nn_xpair_send (struct nn_sockbase *self, struct nn_msg *msg);
static int nn_xpair_recv (struct nn_sockbase *self, struct nn_msg *msg);
static int nn_xpair_setopt (struct nn_sockbase *self, int level, int option,
const void *optval, size_t optvallen);
static int nn_xpair_getopt (struct nn_sockbase *self, int level, int option,
void *optval, size_t *optvallen);
static const struct nn_sockbase_vfptr nn_xpair_sockbase_vfptr = {
NULL,
nn_xpair_destroy,
nn_xpair_add,
nn_xpair_rm,
nn_xpair_in,
nn_xpair_out,
nn_xpair_events,
nn_xpair_send,
nn_xpair_recv,
nn_xpair_setopt,
nn_xpair_getopt
};
static void nn_xpair_init (struct nn_xpair *self,
const struct nn_sockbase_vfptr *vfptr, void *hint)
{
nn_sockbase_init (&self->sockbase, vfptr, hint);
nn_excl_init (&self->excl);
}
static void nn_xpair_term (struct nn_xpair *self)
{
nn_excl_term (&self->excl);
nn_sockbase_term (&self->sockbase);
}
void nn_xpair_destroy (struct nn_sockbase *self)
{
struct nn_xpair *xpair;
xpair = nn_cont (self, struct nn_xpair, sockbase);
nn_xpair_term (xpair);
nn_free (xpair);
}
static int nn_xpair_add (struct nn_sockbase *self, struct nn_pipe *pipe)
{
return nn_excl_add (&nn_cont (self, struct nn_xpair, sockbase)->excl,
pipe);
}
static void nn_xpair_rm (struct nn_sockbase *self, struct nn_pipe *pipe)
{
nn_excl_rm (&nn_cont (self, struct nn_xpair, sockbase)->excl, pipe);
}
static void nn_xpair_in (struct nn_sockbase *self, struct nn_pipe *pipe)
{
nn_excl_in (&nn_cont (self, struct nn_xpair, sockbase)->excl, pipe);
}
static void nn_xpair_out (struct nn_sockbase *self, struct nn_pipe *pipe)
{
nn_excl_out (&nn_cont (self, struct nn_xpair, sockbase)->excl, pipe);
}
static int nn_xpair_events (struct nn_sockbase *self)
{
struct nn_xpair *xpair;
int events;
xpair = nn_cont (self, struct nn_xpair, sockbase);
events = 0;
if (nn_excl_can_recv (&xpair->excl))
events |= NN_SOCKBASE_EVENT_IN;
if (nn_excl_can_send (&xpair->excl))
events |= NN_SOCKBASE_EVENT_OUT;
return events;
}
static int nn_xpair_send (struct nn_sockbase *self, struct nn_msg *msg)
{
return nn_excl_send (&nn_cont (self, struct nn_xpair, sockbase)->excl,
msg);
}
static int nn_xpair_recv (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
rc = nn_excl_recv (&nn_cont (self, struct nn_xpair, sockbase)->excl, msg);
/* Discard NN_PIPEBASE_PARSED flag. */
return rc < 0 ? rc : 0;
}
static int nn_xpair_setopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED const void *optval, NN_UNUSED size_t optvallen)
{
return -ENOPROTOOPT;
}
static int nn_xpair_getopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED void *optval, NN_UNUSED size_t *optvallen)
{
return -ENOPROTOOPT;
}
int nn_xpair_create (void *hint, struct nn_sockbase **sockbase)
{
struct nn_xpair *self;
self = nn_alloc (sizeof (struct nn_xpair), "socket (pair)");
alloc_assert (self);
nn_xpair_init (self, &nn_xpair_sockbase_vfptr, hint);
*sockbase = &self->sockbase;
return 0;
}
int nn_xpair_ispeer (int socktype)
{
return socktype == NN_PAIR ? 1 : 0;
}
static struct nn_socktype nn_xpair_socktype_struct = {
AF_SP_RAW,
NN_PAIR,
0,
nn_xpair_create,
nn_xpair_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_xpair_socktype = &nn_xpair_socktype_struct;
nanomsg-0.8-beta/src/protocols/pipeline/0000775000175000017500000000000012623652617021272 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/protocols/pipeline/push.h0000664000175000017500000000241212623652600022411 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_PUSH_INCLUDED
#define NN_PUSH_INCLUDED
#include "../../protocol.h"
extern struct nn_socktype *nn_push_socktype;
#endif
nanomsg-0.8-beta/src/protocols/pipeline/push.c0000664000175000017500000000276312623652600022415 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "push.h"
#include "xpush.h"
#include "../../nn.h"
#include "../../pipeline.h"
#include "../../utils/list.h"
static struct nn_socktype nn_push_socktype_struct = {
AF_SP,
NN_PUSH,
NN_SOCKTYPE_FLAG_NORECV,
nn_xpush_create,
nn_xpush_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_push_socktype = &nn_push_socktype_struct;
nanomsg-0.8-beta/src/protocols/pipeline/pull.h0000664000175000017500000000241112623652600022405 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_PULL_INCLUDED
#define NN_PULL_INCLUDED
#include "../../protocol.h"
extern struct nn_socktype *nn_pull_socktype;
#endif
nanomsg-0.8-beta/src/protocols/pipeline/pull.c0000664000175000017500000000276312623652600022412 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "pull.h"
#include "xpull.h"
#include "../../nn.h"
#include "../../pipeline.h"
#include "../../utils/list.h"
static struct nn_socktype nn_pull_socktype_struct = {
AF_SP,
NN_PULL,
NN_SOCKTYPE_FLAG_NOSEND,
nn_xpull_create,
nn_xpull_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_pull_socktype = &nn_pull_socktype_struct;
nanomsg-0.8-beta/src/protocols/pipeline/xpull.h0000664000175000017500000000256212623652600022604 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_XPULL_INCLUDED
#define NN_XPULL_INCLUDED
#include "../../protocol.h"
extern struct nn_socktype *nn_xpull_socktype;
int nn_xpull_create (void *hint, struct nn_sockbase **sockbase);
int nn_xpull_ispeer (int socktype);
#endif
nanomsg-0.8-beta/src/protocols/pipeline/xpull.c0000664000175000017500000001415512623652600022600 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2014 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "xpull.h"
#include "../../nn.h"
#include "../../pipeline.h"
#include "../utils/fq.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/alloc.h"
#include "../../utils/list.h"
#include "../../utils/attr.h"
struct nn_xpull_data {
struct nn_fq_data fq;
};
struct nn_xpull {
struct nn_sockbase sockbase;
struct nn_fq fq;
};
/* Private functions. */
static void nn_xpull_init (struct nn_xpull *self,
const struct nn_sockbase_vfptr *vfptr, void *hint);
static void nn_xpull_term (struct nn_xpull *self);
/* Implementation of nn_sockbase's virtual functions. */
static void nn_xpull_destroy (struct nn_sockbase *self);
static int nn_xpull_add (struct nn_sockbase *self, struct nn_pipe *pipe);
static void nn_xpull_rm (struct nn_sockbase *self, struct nn_pipe *pipe);
static void nn_xpull_in (struct nn_sockbase *self, struct nn_pipe *pipe);
static void nn_xpull_out (struct nn_sockbase *self, struct nn_pipe *pipe);
static int nn_xpull_events (struct nn_sockbase *self);
static int nn_xpull_recv (struct nn_sockbase *self, struct nn_msg *msg);
static int nn_xpull_setopt (struct nn_sockbase *self, int level, int option,
const void *optval, size_t optvallen);
static int nn_xpull_getopt (struct nn_sockbase *self, int level, int option,
void *optval, size_t *optvallen);
static const struct nn_sockbase_vfptr nn_xpull_sockbase_vfptr = {
NULL,
nn_xpull_destroy,
nn_xpull_add,
nn_xpull_rm,
nn_xpull_in,
nn_xpull_out,
nn_xpull_events,
NULL,
nn_xpull_recv,
nn_xpull_setopt,
nn_xpull_getopt
};
static void nn_xpull_init (struct nn_xpull *self,
const struct nn_sockbase_vfptr *vfptr, void *hint)
{
nn_sockbase_init (&self->sockbase, vfptr, hint);
nn_fq_init (&self->fq);
}
static void nn_xpull_term (struct nn_xpull *self)
{
nn_fq_term (&self->fq);
nn_sockbase_term (&self->sockbase);
}
void nn_xpull_destroy (struct nn_sockbase *self)
{
struct nn_xpull *xpull;
xpull = nn_cont (self, struct nn_xpull, sockbase);
nn_xpull_term (xpull);
nn_free (xpull);
}
static int nn_xpull_add (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xpull *xpull;
struct nn_xpull_data *data;
int rcvprio;
size_t sz;
xpull = nn_cont (self, struct nn_xpull, sockbase);
sz = sizeof (rcvprio);
nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, &sz);
nn_assert (sz == sizeof (rcvprio));
nn_assert (rcvprio >= 1 && rcvprio <= 16);
data = nn_alloc (sizeof (struct nn_xpull_data), "pipe data (pull)");
alloc_assert (data);
nn_pipe_setdata (pipe, data);
nn_fq_add (&xpull->fq, &data->fq, pipe, rcvprio);
return 0;
}
static void nn_xpull_rm (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xpull *xpull;
struct nn_xpull_data *data;
xpull = nn_cont (self, struct nn_xpull, sockbase);
data = nn_pipe_getdata (pipe);
nn_fq_rm (&xpull->fq, &data->fq);
nn_free (data);
}
static void nn_xpull_in (NN_UNUSED struct nn_sockbase *self,
struct nn_pipe *pipe)
{
struct nn_xpull *xpull;
struct nn_xpull_data *data;
xpull = nn_cont (self, struct nn_xpull, sockbase);
data = nn_pipe_getdata (pipe);
nn_fq_in (&xpull->fq, &data->fq);
}
static void nn_xpull_out (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED struct nn_pipe *pipe)
{
/* We are not going to send any messages, so there's no point is
maintaining a list of pipes ready for sending. */
}
static int nn_xpull_events (struct nn_sockbase *self)
{
return nn_fq_can_recv (&nn_cont (self, struct nn_xpull, sockbase)->fq) ?
NN_SOCKBASE_EVENT_IN : 0;
}
static int nn_xpull_recv (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
rc = nn_fq_recv (&nn_cont (self, struct nn_xpull, sockbase)->fq,
msg, NULL);
/* Discard NN_PIPEBASE_PARSED flag. */
return rc < 0 ? rc : 0;
}
static int nn_xpull_setopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED const void *optval, NN_UNUSED size_t optvallen)
{
return -ENOPROTOOPT;
}
static int nn_xpull_getopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED void *optval, NN_UNUSED size_t *optvallen)
{
return -ENOPROTOOPT;
}
int nn_xpull_create (void *hint, struct nn_sockbase **sockbase)
{
struct nn_xpull *self;
self = nn_alloc (sizeof (struct nn_xpull), "socket (pull)");
alloc_assert (self);
nn_xpull_init (self, &nn_xpull_sockbase_vfptr, hint);
*sockbase = &self->sockbase;
return 0;
}
int nn_xpull_ispeer (int socktype)
{
return socktype == NN_PUSH ? 1 : 0;
}
static struct nn_socktype nn_xpull_socktype_struct = {
AF_SP_RAW,
NN_PULL,
NN_SOCKTYPE_FLAG_NOSEND,
nn_xpull_create,
nn_xpull_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_xpull_socktype = &nn_xpull_socktype_struct;
nanomsg-0.8-beta/src/protocols/pipeline/xpush.h0000664000175000017500000000256312623652600022610 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_XPUSH_INCLUDED
#define NN_XPUSH_INCLUDED
#include "../../protocol.h"
extern struct nn_socktype *nn_xpush_socktype;
int nn_xpush_create (void *hint, struct nn_sockbase **sockbase);
int nn_xpush_ispeer (int socktype);
#endif
nanomsg-0.8-beta/src/protocols/pipeline/xpush.c0000664000175000017500000001416512623652600022604 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "xpush.h"
#include "../../nn.h"
#include "../../pipeline.h"
#include "../utils/lb.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/alloc.h"
#include "../../utils/list.h"
#include "../../utils/attr.h"
struct nn_xpush_data {
struct nn_lb_data lb;
};
struct nn_xpush {
struct nn_sockbase sockbase;
struct nn_lb lb;
};
/* Private functions. */
static void nn_xpush_init (struct nn_xpush *self,
const struct nn_sockbase_vfptr *vfptr, void *hint);
static void nn_xpush_term (struct nn_xpush *self);
/* Implementation of nn_sockbase's virtual functions. */
static void nn_xpush_destroy (struct nn_sockbase *self);
static int nn_xpush_add (struct nn_sockbase *self, struct nn_pipe *pipe);
static void nn_xpush_rm (struct nn_sockbase *self, struct nn_pipe *pipe);
static void nn_xpush_in (struct nn_sockbase *self, struct nn_pipe *pipe);
static void nn_xpush_out (struct nn_sockbase *self, struct nn_pipe *pipe);
static int nn_xpush_events (struct nn_sockbase *self);
static int nn_xpush_send (struct nn_sockbase *self, struct nn_msg *msg);
static int nn_xpush_setopt (struct nn_sockbase *self, int level, int option,
const void *optval, size_t optvallen);
static int nn_xpush_getopt (struct nn_sockbase *self, int level, int option,
void *optval, size_t *optvallen);
static const struct nn_sockbase_vfptr nn_xpush_sockbase_vfptr = {
NULL,
nn_xpush_destroy,
nn_xpush_add,
nn_xpush_rm,
nn_xpush_in,
nn_xpush_out,
nn_xpush_events,
nn_xpush_send,
NULL,
nn_xpush_setopt,
nn_xpush_getopt
};
static void nn_xpush_init (struct nn_xpush *self,
const struct nn_sockbase_vfptr *vfptr, void *hint)
{
nn_sockbase_init (&self->sockbase, vfptr, hint);
nn_lb_init (&self->lb);
}
static void nn_xpush_term (struct nn_xpush *self)
{
nn_lb_term (&self->lb);
nn_sockbase_term (&self->sockbase);
}
void nn_xpush_destroy (struct nn_sockbase *self)
{
struct nn_xpush *xpush;
xpush = nn_cont (self, struct nn_xpush, sockbase);
nn_xpush_term (xpush);
nn_free (xpush);
}
static int nn_xpush_add (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xpush *xpush;
struct nn_xpush_data *data;
int sndprio;
size_t sz;
xpush = nn_cont (self, struct nn_xpush, sockbase);
sz = sizeof (sndprio);
nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_SNDPRIO, &sndprio, &sz);
nn_assert (sz == sizeof (sndprio));
nn_assert (sndprio >= 1 && sndprio <= 16);
data = nn_alloc (sizeof (struct nn_xpush_data), "pipe data (push)");
alloc_assert (data);
nn_pipe_setdata (pipe, data);
nn_lb_add (&xpush->lb, &data->lb, pipe, sndprio);
return 0;
}
static void nn_xpush_rm (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xpush *xpush;
struct nn_xpush_data *data;
xpush = nn_cont (self, struct nn_xpush, sockbase);
data = nn_pipe_getdata (pipe);
nn_lb_rm (&xpush->lb, &data->lb);
nn_free (data);
nn_sockbase_stat_increment (self, NN_STAT_CURRENT_SND_PRIORITY,
nn_lb_get_priority (&xpush->lb));
}
static void nn_xpush_in (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED struct nn_pipe *pipe)
{
/* We are not going to receive any messages, so there's no need to store
the list of inbound pipes. */
}
static void nn_xpush_out (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xpush *xpush;
struct nn_xpush_data *data;
xpush = nn_cont (self, struct nn_xpush, sockbase);
data = nn_pipe_getdata (pipe);
nn_lb_out (&xpush->lb, &data->lb);
nn_sockbase_stat_increment (self, NN_STAT_CURRENT_SND_PRIORITY,
nn_lb_get_priority (&xpush->lb));
}
static int nn_xpush_events (struct nn_sockbase *self)
{
return nn_lb_can_send (&nn_cont (self, struct nn_xpush, sockbase)->lb) ?
NN_SOCKBASE_EVENT_OUT : 0;
}
static int nn_xpush_send (struct nn_sockbase *self, struct nn_msg *msg)
{
return nn_lb_send (&nn_cont (self, struct nn_xpush, sockbase)->lb,
msg, NULL);
}
static int nn_xpush_setopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED const void *optval, NN_UNUSED size_t optvallen)
{
return -ENOPROTOOPT;
}
static int nn_xpush_getopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED void *optval, NN_UNUSED size_t *optvallen)
{
return -ENOPROTOOPT;
}
int nn_xpush_create (void *hint, struct nn_sockbase **sockbase)
{
struct nn_xpush *self;
self = nn_alloc (sizeof (struct nn_xpush), "socket (push)");
alloc_assert (self);
nn_xpush_init (self, &nn_xpush_sockbase_vfptr, hint);
*sockbase = &self->sockbase;
return 0;
}
int nn_xpush_ispeer (int socktype)
{
return socktype == NN_PULL ? 1 : 0;
}
static struct nn_socktype nn_xpush_socktype_struct = {
AF_SP_RAW,
NN_PUSH,
NN_SOCKTYPE_FLAG_NORECV,
nn_xpush_create,
nn_xpush_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_xpush_socktype = &nn_xpush_socktype_struct;
nanomsg-0.8-beta/src/protocols/pubsub/0000775000175000017500000000000012623652617020765 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/protocols/pubsub/pub.h0000664000175000017500000000240112623652600021711 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_PUB_INCLUDED
#define NN_PUB_INCLUDED
#include "../../protocol.h"
extern struct nn_socktype *nn_pub_socktype;
#endif
nanomsg-0.8-beta/src/protocols/pubsub/pub.c0000664000175000017500000000274412623652600021716 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "pub.h"
#include "xpub.h"
#include "../../nn.h"
#include "../../pubsub.h"
#include "../../utils/list.h"
static struct nn_socktype nn_pub_socktype_struct = {
AF_SP,
NN_PUB,
NN_SOCKTYPE_FLAG_NORECV,
nn_xpub_create,
nn_xpub_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_pub_socktype = &nn_pub_socktype_struct;
nanomsg-0.8-beta/src/protocols/pubsub/sub.h0000664000175000017500000000240112623652600021714 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_SUB_INCLUDED
#define NN_SUB_INCLUDED
#include "../../protocol.h"
extern struct nn_socktype *nn_sub_socktype;
#endif
nanomsg-0.8-beta/src/protocols/pubsub/sub.c0000664000175000017500000000274412623652600021721 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "sub.h"
#include "xsub.h"
#include "../../nn.h"
#include "../../pubsub.h"
#include "../../utils/list.h"
static struct nn_socktype nn_sub_socktype_struct = {
AF_SP,
NN_SUB,
NN_SOCKTYPE_FLAG_NOSEND,
nn_xsub_create,
nn_xsub_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_sub_socktype = &nn_sub_socktype_struct;
nanomsg-0.8-beta/src/protocols/pubsub/trie.h0000664000175000017500000001105412623652600022072 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_TRIE_INCLUDED
#define NN_TRIE_INCLUDED
#include "../../utils/int.h"
#include
/* This class implements highly memory-efficient patricia trie. */
/* Maximum length of the prefix. */
#define NN_TRIE_PREFIX_MAX 10
/* Maximum number of children in the sparse mode. */
#define NN_TRIE_SPARSE_MAX 8
/* 'type' is set to this value when in the dense mode. */
#define NN_TRIE_DENSE_TYPE (NN_TRIE_SPARSE_MAX + 1)
/* This structure represents a node in patricia trie. It's a header to be
followed by the array of pointers to child nodes. Each node represents
the string composed of all the prefixes on the way from the trie root,
including the prefix in that node. */
struct nn_trie_node
{
/* Number of subscriptions to the given string. */
uint32_t refcount;
/* Number of elements is a sparse array, or NN_TRIE_DENSE_TYPE in case
the array of children is dense. */
uint8_t type;
/* The node adds more characters to the string, compared to the parent
node. If there is only a single character added, it's represented
directly in the child array. If there's more than one character added,
all but the last one are stored as a 'prefix'. */
uint8_t prefix_len;
uint8_t prefix [NN_TRIE_PREFIX_MAX];
/* The array of characters pointing to individual children of the node.
Actual pointers to child nodes are stored in the memory following
nn_trie_node structure. */
union {
/* Sparse array means that individual children are identified by
characters stored in 'children' array. The number of characters
in the array is specified in the 'type' field. */
struct {
uint8_t children [NN_TRIE_SPARSE_MAX];
} sparse;
/* Dense array means that the array of node pointers following the
structure corresponds to a continuous list of characters starting
by 'min' character and ending by 'max' character. The characters
in the range that have no corresponding child node are represented
by NULL pointers. 'nbr' is the count of child nodes. */
struct {
uint8_t min;
uint8_t max;
uint16_t nbr;
/* There are 4 bytes of padding here. */
} dense;
} u;
};
/* The structure is followed by the array of pointers to children. */
struct nn_trie {
/* The root node of the trie (representing the empty subscription). */
struct nn_trie_node *root;
};
/* Initialise an empty trie. */
void nn_trie_init (struct nn_trie *self);
/* Release all the resources associated with the trie. */
void nn_trie_term (struct nn_trie *self);
/* Add the string to the trie. If the string is not yet there, 1 is returned.
If it already exists in the trie, its reference count is incremented and
0 is returned. */
int nn_trie_subscribe (struct nn_trie *self, const uint8_t *data, size_t size);
/* Remove the string from the trie. If the string was actually removed,
1 is returned. If reference count was decremented without falling to zero,
0 is returned. */
int nn_trie_unsubscribe (struct nn_trie *self, const uint8_t *data,
size_t size);
/* Checks the supplied string. If it matches it returns 1, if it does not
it returns 0. */
int nn_trie_match (struct nn_trie *self, const uint8_t *data, size_t size);
/* Debugging interface. */
void nn_trie_dump (struct nn_trie *self);
#endif
nanomsg-0.8-beta/src/protocols/pubsub/trie.c0000664000175000017500000005113412623652600022070 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include
#include
#include
#include "trie.h"
#include "../../utils/alloc.h"
#include "../../utils/fast.h"
#include "../../utils/err.h"
/* Double check that the size of node structure is as small as
we believe it to be. */
CT_ASSERT (sizeof (struct nn_trie_node) == 24);
/* Forward declarations. */
static struct nn_trie_node *nn_node_compact (struct nn_trie_node *self);
static int nn_node_check_prefix (struct nn_trie_node *self,
const uint8_t *data, size_t size);
static struct nn_trie_node **nn_node_child (struct nn_trie_node *self,
int index);
static struct nn_trie_node **nn_node_next (struct nn_trie_node *self,
uint8_t c);
static int nn_node_unsubscribe (struct nn_trie_node **self,
const uint8_t *data, size_t size);
static void nn_node_term (struct nn_trie_node *self);
static int nn_node_has_subscribers (struct nn_trie_node *self);
static void nn_node_dump (struct nn_trie_node *self, int indent);
static void nn_node_indent (int indent);
static void nn_node_putchar (uint8_t c);
void nn_trie_init (struct nn_trie *self)
{
self->root = NULL;
}
void nn_trie_term (struct nn_trie *self)
{
nn_node_term (self->root);
}
void nn_trie_dump (struct nn_trie *self)
{
nn_node_dump (self->root, 0);
}
void nn_node_dump (struct nn_trie_node *self, int indent)
{
int i;
int children;
if (!self) {
nn_node_indent (indent);
printf ("NULL\n");
return;
}
nn_node_indent (indent);
printf ("===================\n");
nn_node_indent (indent);
printf ("refcount=%d\n", (int) self->refcount);
nn_node_indent (indent);
printf ("prefix_len=%d\n", (int) self->prefix_len);
nn_node_indent (indent);
if (self->type == NN_TRIE_DENSE_TYPE)
printf ("type=dense\n");
else
printf ("type=sparse\n");
nn_node_indent (indent);
printf ("prefix=\"");
for (i = 0; i != self->prefix_len; ++i)
nn_node_putchar (self->prefix [i]);
printf ("\"\n");
if (self->type <= 8) {
nn_node_indent (indent);
printf ("sparse.children=\"");
for (i = 0; i != self->type; ++i)
nn_node_putchar (self->u.sparse.children [i]);
printf ("\"\n");
children = self->type;
}
else {
nn_node_indent (indent);
printf ("dense.min='%c' (%d)\n", (char) self->u.dense.min,
(int) self->u.dense.min);
nn_node_indent (indent);
printf ("dense.max='%c' (%d)\n", (char) self->u.dense.max,
(int) self->u.dense.max);
nn_node_indent (indent);
printf ("dense.nbr=%d\n", (int) self->u.dense.nbr);
children = self->u.dense.max - self->u.dense.min + 1;
}
for (i = 0; i != children; ++i)
nn_node_dump (((struct nn_trie_node**) (self + 1)) [i], indent + 1);
nn_node_indent (indent);
printf ("===================\n");
}
void nn_node_indent (int indent)
{
int i;
for (i = 0; i != indent * 4; ++i)
nn_node_putchar (' ');
}
void nn_node_putchar (uint8_t c)
{
if (c < 32 || c > 127)
putchar ('?');
else
putchar (c);
}
void nn_node_term (struct nn_trie_node *self)
{
int children;
int i;
/* Trivial case of the recursive algorithm. */
if (!self)
return;
/* Recursively destroy the child nodes. */
children = self->type <= NN_TRIE_SPARSE_MAX ?
self->type : (self->u.dense.max - self->u.dense.min + 1);
for (i = 0; i != children; ++i)
nn_node_term (*nn_node_child (self, i));
/* Deallocate this node. */
nn_free (self);
}
int nn_node_check_prefix (struct nn_trie_node *self,
const uint8_t *data, size_t size)
{
/* Check how many characters from the data match the prefix. */
int i;
for (i = 0; i != self->prefix_len; ++i) {
if (!size || self->prefix [i] != *data)
return i;
++data;
--size;
}
return self->prefix_len;
}
struct nn_trie_node **nn_node_child (struct nn_trie_node *self, int index)
{
/* Finds pointer to the n-th child of the node. */
return ((struct nn_trie_node**) (self + 1)) + index;
}
struct nn_trie_node **nn_node_next (struct nn_trie_node *self, uint8_t c)
{
/* Finds the pointer to the next node based on the supplied character.
If there is no such pointer, it returns NULL. */
int i;
if (self->type == 0)
return NULL;
/* Sparse mode. */
if (self->type <= 8) {
for (i = 0; i != self->type; ++i)
if (self->u.sparse.children [i] == c)
return nn_node_child (self, i);
return NULL;
}
/* Dense mode. */
if (c < self->u.dense.min || c > self->u.dense.max)
return NULL;
return nn_node_child (self, c - self->u.dense.min);
}
struct nn_trie_node *nn_node_compact (struct nn_trie_node *self)
{
/* Tries to merge the node with the child node. Returns pointer to
the compacted node. */
struct nn_trie_node *ch;
/* Node that is a subscription cannot be compacted. */
if (nn_node_has_subscribers (self))
return self;
/* Only a node with a single child can be compacted. */
if (self->type != 1)
return self;
/* Check whether combined prefixes would fix into a single node. */
ch = *nn_node_child (self, 0);
if (self->prefix_len + ch->prefix_len + 1 > NN_TRIE_PREFIX_MAX)
return self;
/* Concatenate the prefixes. */
memmove (ch->prefix + self->prefix_len + 1, ch->prefix, ch->prefix_len);
memcpy (ch->prefix, self->prefix, self->prefix_len);
ch->prefix [self->prefix_len] = self->u.sparse.children [0];
ch->prefix_len += self->prefix_len + 1;
/* Get rid of the obsolete parent node. */
nn_free (self);
/* Return the new compacted node. */
return ch;
}
int nn_trie_subscribe (struct nn_trie *self, const uint8_t *data, size_t size)
{
int i;
struct nn_trie_node **node;
struct nn_trie_node **n;
struct nn_trie_node *ch;
struct nn_trie_node *old_node;
int pos;
uint8_t c;
uint8_t c2;
uint8_t new_min;
uint8_t new_max;
int old_children;
int new_children;
int inserted;
int more_nodes;
/* Step 1 -- Traverse the trie. */
node = &self->root;
pos = 0;
while (1) {
/* If there are no more nodes on the path, go to step 4. */
if (!*node)
goto step4;
/* Check whether prefix matches the new subscription. */
pos = nn_node_check_prefix (*node, data, size);
data += pos;
size -= pos;
/* If only part of the prefix matches, go to step 2. */
if (pos < (*node)->prefix_len)
goto step2;
/* Even if whole prefix matches and there's no more data to match,
go directly to step 5. */
if (!size)
goto step5;
/* Move to the next node. If it is not present, go to step 3. */
n = nn_node_next (*node, *data);
if (!n || !*n)
goto step3;
node = n;
++data;
--size;
}
/* Step 2 -- Split the prefix into two parts if required. */
step2:
ch = *node;
*node = nn_alloc (sizeof (struct nn_trie_node) +
sizeof (struct nn_trie_node*), "trie node");
assert (*node);
(*node)->refcount = 0;
(*node)->prefix_len = pos;
(*node)->type = 1;
memcpy ((*node)->prefix, ch->prefix, pos);
(*node)->u.sparse.children [0] = ch->prefix [pos];
ch->prefix_len -= (pos + 1);
memmove (ch->prefix, ch->prefix + pos + 1, ch->prefix_len);
ch = nn_node_compact (ch);
*nn_node_child (*node, 0) = ch;
pos = (*node)->prefix_len;
/* Step 3 -- Adjust the child array to accommodate the new character. */
step3:
/* If there are no more data in the subscription, there's nothing to
adjust in the child array. Proceed directly to the step 5. */
if (!size)
goto step5;
/* If the new branch fits into sparse array... */
if ((*node)->type < NN_TRIE_SPARSE_MAX) {
*node = nn_realloc (*node, sizeof (struct nn_trie_node) +
((*node)->type + 1) * sizeof (struct nn_trie_node*));
assert (*node);
(*node)->u.sparse.children [(*node)->type] = *data;
++(*node)->type;
node = nn_node_child (*node, (*node)->type - 1);
*node = NULL;
++data;
--size;
goto step4;
}
/* If the node is already a dense array, resize it to fit the next
character. */
if ((*node)->type == NN_TRIE_DENSE_TYPE) {
c = *data;
if (c < (*node)->u.dense.min || c > (*node)->u.dense.max) {
new_min = (*node)->u.dense.min < c ? (*node)->u.dense.min : c;
new_max = (*node)->u.dense.max > c ? (*node)->u.dense.max : c;
*node = nn_realloc (*node, sizeof (struct nn_trie_node) +
(new_max - new_min + 1) * sizeof (struct nn_trie_node*));
assert (*node);
old_children = (*node)->u.dense.max - (*node)->u.dense.min + 1;
new_children = new_max - new_min + 1;
if ((*node)->u.dense.min != new_min) {
inserted = (*node)->u.dense.min - new_min;
memmove (nn_node_child (*node, inserted),
nn_node_child (*node, 0),
old_children * sizeof (struct nn_trie_node*));
memset (nn_node_child (*node, 0), 0,
inserted * sizeof (struct nn_trie_node*));
}
else {
memset (nn_node_child (*node, old_children), 0,
(new_children - old_children) *
sizeof (struct nn_trie_node*));
}
(*node)->u.dense.min = new_min;
(*node)->u.dense.max = new_max;
}
++(*node)->u.dense.nbr;
node = nn_node_child (*node, c - (*node)->u.dense.min);
++data;
--size;
goto step4;
}
/* This is a sparse array, but no more children can be added to it.
We have to convert it into a dense array. */
{
/* First, determine the range of children. */
new_min = 255;
new_max = 0;
for (i = 0; i != (*node)->type; ++i) {
c2 = (*node)->u.sparse.children [i];
new_min = new_min < c2 ? new_min : c2;
new_max = new_max > c2 ? new_max : c2;
}
new_min = new_min < *data ? new_min : *data;
new_max = new_max > *data ? new_max : *data;
/* Create a new mode, while keeping the old one for a while. */
old_node = *node;
*node = (struct nn_trie_node*) nn_alloc (sizeof (struct nn_trie_node) +
(new_max - new_min + 1) * sizeof (struct nn_trie_node*),
"trie node");
assert (*node);
/* Fill in the new node. */
(*node)->refcount = 0;
(*node)->prefix_len = old_node->prefix_len;
(*node)->type = NN_TRIE_DENSE_TYPE;
memcpy ((*node)->prefix, old_node->prefix, old_node->prefix_len);
(*node)->u.dense.min = new_min;
(*node)->u.dense.max = new_max;
(*node)->u.dense.nbr = old_node->type + 1;
memset (*node + 1, 0, (new_max - new_min + 1) *
sizeof (struct nn_trie_node*));
for (i = 0; i != old_node->type; ++i)
*nn_node_child (*node, old_node->u.sparse.children [i] - new_min) =
*nn_node_child (old_node, i);
node = nn_node_next (*node, *data);
++data;
--size;
/* Get rid of the obsolete old node. */
nn_free (old_node);
}
/* Step 4 -- Create new nodes for remaining part of the subscription. */
step4:
assert (!*node);
while (1) {
/* Create a new node to hold the next part of the subscription. */
more_nodes = size > NN_TRIE_PREFIX_MAX;
*node = nn_alloc (sizeof (struct nn_trie_node) +
(more_nodes ? sizeof (struct nn_trie_node*) : 0), "trie node");
assert (*node);
/* Fill in the new node. */
(*node)->refcount = 0;
(*node)->type = more_nodes ? 1 : 0;
(*node)->prefix_len = size < (uint8_t) NN_TRIE_PREFIX_MAX ?
(uint8_t) size : (uint8_t) NN_TRIE_PREFIX_MAX;
memcpy ((*node)->prefix, data, (*node)->prefix_len);
data += (*node)->prefix_len;
size -= (*node)->prefix_len;
if (!more_nodes)
break;
(*node)->u.sparse.children [0] = *data;
node = nn_node_child (*node, 0);
++data;
--size;
}
/* Step 5 -- Create the subscription as such. */
step5:
++(*node)->refcount;
/* Return 1 in case of a fresh subscription. */
return (*node)->refcount == 1 ? 1 : 0;
}
int nn_trie_match (struct nn_trie *self, const uint8_t *data, size_t size)
{
struct nn_trie_node *node;
struct nn_trie_node **tmp;
node = self->root;
while (1) {
/* If we are at the end of the trie, return. */
if (!node)
return 0;
/* Check whether whole prefix matches the data. If not so,
the whole string won't match. */
if (nn_node_check_prefix (node, data, size) != node->prefix_len)
return 0;
/* Skip the prefix. */
data += node->prefix_len;
size -= node->prefix_len;
/* If all the data are matched, return. */
if (nn_node_has_subscribers (node))
return 1;
/* Move to the next node. */
tmp = nn_node_next (node, *data);
node = tmp ? *tmp : NULL;
++data;
--size;
}
}
int nn_trie_unsubscribe (struct nn_trie *self, const uint8_t *data, size_t size)
{
return nn_node_unsubscribe (&self->root, data, size);
}
static int nn_node_unsubscribe (struct nn_trie_node **self,
const uint8_t *data, size_t size)
{
int i;
int j;
int index;
int new_min;
struct nn_trie_node **ch;
struct nn_trie_node *new_node;
struct nn_trie_node *ch2;
if (!size)
goto found;
/* If prefix does not match the data, return. */
if (nn_node_check_prefix (*self, data, size) != (*self)->prefix_len)
return 0;
/* Skip the prefix. */
data += (*self)->prefix_len;
size -= (*self)->prefix_len;
if (!size)
goto found;
/* Move to the next node. */
ch = nn_node_next (*self, *data);
if (!ch)
return 0; /* TODO: This should be an error. */
/* Recursive traversal of the trie happens here. If the subscription
wasn't really removed, nothing have changed in the trie and
no additional pruning is needed. */
if (nn_node_unsubscribe (ch, data + 1, size - 1) == 0)
return 0;
/* Subscription removal is already done. Now we are going to compact
the trie. However, if the following node remains in place, there's
nothing to compact here. */
if (*ch)
return 1;
/* Sparse array. */
if ((*self)->type < NN_TRIE_DENSE_TYPE) {
/* Get the indices of the removed child. */
for (index = 0; index != (*self)->type; ++index)
if ((*self)->u.sparse.children [index] == *data)
break;
assert (index != (*self)->type);
/* Remove the destroyed child from both lists of children. */
memmove (
(*self)->u.sparse.children + index,
(*self)->u.sparse.children + index + 1,
(*self)->type - index - 1);
memmove (
nn_node_child (*self, index),
nn_node_child (*self, index + 1),
((*self)->type - index - 1) * sizeof (struct nn_trie_node*));
--(*self)->type;
*self = nn_realloc (*self, sizeof (struct nn_trie_node) +
((*self)->type * sizeof (struct nn_trie_node*)));
assert (*self);
/* If there are no more children and no refcount, we can delete
the node altogether. */
if (!(*self)->type && !nn_node_has_subscribers (*self)) {
nn_free (*self);
*self = NULL;
return 1;
}
/* Try to merge the node with the following node. */
*self = nn_node_compact (*self);
return 1;
}
/* Dense array. */
/* In this case the array stays dense. We have to adjust the limits of
the array, if appropriate. */
if ((*self)->u.dense.nbr > NN_TRIE_SPARSE_MAX + 1) {
/* If the removed item is the leftmost one, trim the array from
the left side. */
if (*data == (*self)->u.dense.min) {
for (i = 0; i != (*self)->u.dense.max - (*self)->u.dense.min + 1;
++i)
if (*nn_node_child (*self, i))
break;
new_min = i + (*self)->u.dense.min;
memmove (nn_node_child (*self, 0), nn_node_child (*self, i),
((*self)->u.dense.max - new_min + 1) *
sizeof (struct nn_trie_node*));
(*self)->u.dense.min = new_min;
--(*self)->u.dense.nbr;
*self = nn_realloc (*self, sizeof (struct nn_trie_node) +
((*self)->u.dense.max - new_min + 1) *
sizeof (struct nn_trie_node*));
assert (*self);
return 1;
}
/* If the removed item is the rightmost one, trim the array from
the right side. */
if (*data == (*self)->u.dense.max) {
for (i = (*self)->u.dense.max - (*self)->u.dense.min; i != 0; --i)
if (*nn_node_child (*self, i))
break;
(*self)->u.dense.max = i + (*self)->u.dense.min;
--(*self)->u.dense.nbr;
*self = nn_realloc (*self, sizeof (struct nn_trie_node) +
((*self)->u.dense.max - (*self)->u.dense.min + 1) *
sizeof (struct nn_trie_node*));
assert (*self);
return 1;
}
/* If the item is removed from the middle of the array, do nothing. */
--(*self)->u.dense.nbr;
return 1;
}
/* Convert dense array into sparse array. */
{
new_node = nn_alloc (sizeof (struct nn_trie_node) +
NN_TRIE_SPARSE_MAX * sizeof (struct nn_trie_node*), "trie node");
assert (new_node);
new_node->refcount = 0;
new_node->prefix_len = (*self)->prefix_len;
memcpy (new_node->prefix, (*self)->prefix, new_node->prefix_len);
new_node->type = NN_TRIE_SPARSE_MAX;
j = 0;
for (i = 0; i != (*self)->u.dense.max - (*self)->u.dense.min + 1;
++i) {
ch2 = *nn_node_child (*self, i);
if (ch2) {
new_node->u.sparse.children [j] = i + (*self)->u.dense.min;
*nn_node_child (new_node, j) = ch2;
++j;
}
}
assert (j == NN_TRIE_SPARSE_MAX);
nn_free (*self);
*self = new_node;
return 1;
}
found:
/* We are at the end of the subscription here. */
/* Subscription doesn't exist. */
if (nn_slow (!*self || !nn_node_has_subscribers (*self)))
return -EINVAL;
/* Subscription exists. Unsubscribe. */
--(*self)->refcount;
/* If reference count has dropped to zero we can try to compact
the node. */
if (!(*self)->refcount) {
/* If there are no children, we can delete the node altogether. */
if (!(*self)->type) {
nn_free (*self);
*self = NULL;
return 1;
}
/* Try to merge the node with the following node. */
*self = nn_node_compact (*self);
return 1;
}
return 0;
}
int nn_node_has_subscribers (struct nn_trie_node *node)
{
/* Returns 1 when there are no subscribers associated with the node. */
return node->refcount ? 1 : 0;
}
nanomsg-0.8-beta/src/protocols/pubsub/xpub.h0000664000175000017500000000255612623652600022114 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_XPUB_INCLUDED
#define NN_XPUB_INCLUDED
#include "../../protocol.h"
extern struct nn_socktype *nn_xpub_socktype;
int nn_xpub_create (void *hint, struct nn_sockbase **sockbase);
int nn_xpub_ispeer (int socktype);
#endif
nanomsg-0.8-beta/src/protocols/pubsub/xpub.c0000664000175000017500000001325712623652600022107 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "xpub.h"
#include "../../nn.h"
#include "../../pubsub.h"
#include "../utils/dist.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/alloc.h"
#include "../../utils/list.h"
#include "../../utils/attr.h"
#include
struct nn_xpub_data {
struct nn_dist_data item;
};
struct nn_xpub {
/* The generic socket base class. */
struct nn_sockbase sockbase;
/* Distributor. */
struct nn_dist outpipes;
};
/* Private functions. */
static void nn_xpub_init (struct nn_xpub *self,
const struct nn_sockbase_vfptr *vfptr, void *hint);
static void nn_xpub_term (struct nn_xpub *self);
/* Implementation of nn_sockbase's virtual functions. */
static void nn_xpub_destroy (struct nn_sockbase *self);
static int nn_xpub_add (struct nn_sockbase *self, struct nn_pipe *pipe);
static void nn_xpub_rm (struct nn_sockbase *self, struct nn_pipe *pipe);
static void nn_xpub_in (struct nn_sockbase *self, struct nn_pipe *pipe);
static void nn_xpub_out (struct nn_sockbase *self, struct nn_pipe *pipe);
static int nn_xpub_events (struct nn_sockbase *self);
static int nn_xpub_send (struct nn_sockbase *self, struct nn_msg *msg);
static int nn_xpub_setopt (struct nn_sockbase *self, int level, int option,
const void *optval, size_t optvallen);
static int nn_xpub_getopt (struct nn_sockbase *self, int level, int option,
void *optval, size_t *optvallen);
static const struct nn_sockbase_vfptr nn_xpub_sockbase_vfptr = {
NULL,
nn_xpub_destroy,
nn_xpub_add,
nn_xpub_rm,
nn_xpub_in,
nn_xpub_out,
nn_xpub_events,
nn_xpub_send,
NULL,
nn_xpub_setopt,
nn_xpub_getopt
};
static void nn_xpub_init (struct nn_xpub *self,
const struct nn_sockbase_vfptr *vfptr, void *hint)
{
nn_sockbase_init (&self->sockbase, vfptr, hint);
nn_dist_init (&self->outpipes);
}
static void nn_xpub_term (struct nn_xpub *self)
{
nn_dist_term (&self->outpipes);
nn_sockbase_term (&self->sockbase);
}
void nn_xpub_destroy (struct nn_sockbase *self)
{
struct nn_xpub *xpub;
xpub = nn_cont (self, struct nn_xpub, sockbase);
nn_xpub_term (xpub);
nn_free (xpub);
}
static int nn_xpub_add (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xpub *xpub;
struct nn_xpub_data *data;
xpub = nn_cont (self, struct nn_xpub, sockbase);
data = nn_alloc (sizeof (struct nn_xpub_data), "pipe data (pub)");
alloc_assert (data);
nn_dist_add (&xpub->outpipes, &data->item, pipe);
nn_pipe_setdata (pipe, data);
return 0;
}
static void nn_xpub_rm (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xpub *xpub;
struct nn_xpub_data *data;
xpub = nn_cont (self, struct nn_xpub, sockbase);
data = nn_pipe_getdata (pipe);
nn_dist_rm (&xpub->outpipes, &data->item);
nn_free (data);
}
static void nn_xpub_in (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED struct nn_pipe *pipe)
{
/* We shouldn't get any messages from subscribers. */
nn_assert (0);
}
static void nn_xpub_out (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xpub *xpub;
struct nn_xpub_data *data;
xpub = nn_cont (self, struct nn_xpub, sockbase);
data = nn_pipe_getdata (pipe);
nn_dist_out (&xpub->outpipes, &data->item);
}
static int nn_xpub_events (NN_UNUSED struct nn_sockbase *self)
{
return NN_SOCKBASE_EVENT_OUT;
}
static int nn_xpub_send (struct nn_sockbase *self, struct nn_msg *msg)
{
return nn_dist_send (&nn_cont (self, struct nn_xpub, sockbase)->outpipes,
msg, NULL);
}
static int nn_xpub_setopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED const void *optval, NN_UNUSED size_t optvallen)
{
return -ENOPROTOOPT;
}
static int nn_xpub_getopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED void *optval, NN_UNUSED size_t *optvallen)
{
return -ENOPROTOOPT;
}
int nn_xpub_create (void *hint, struct nn_sockbase **sockbase)
{
struct nn_xpub *self;
self = nn_alloc (sizeof (struct nn_xpub), "socket (xpub)");
alloc_assert (self);
nn_xpub_init (self, &nn_xpub_sockbase_vfptr, hint);
*sockbase = &self->sockbase;
return 0;
}
int nn_xpub_ispeer (int socktype)
{
return socktype == NN_SUB ? 1 : 0;
}
static struct nn_socktype nn_xpub_socktype_struct = {
AF_SP_RAW,
NN_PUB,
NN_SOCKTYPE_FLAG_NORECV,
nn_xpub_create,
nn_xpub_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_xpub_socktype = &nn_xpub_socktype_struct;
nanomsg-0.8-beta/src/protocols/pubsub/xsub.h0000664000175000017500000000255512623652600022116 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_XSUB_INCLUDED
#define NN_XSUB_INCLUDED
#include "../../protocol.h"
extern struct nn_socktype *nn_xsub_socktype;
int nn_xsub_create (void *hint, struct nn_sockbase **sockbase);
int nn_xsub_ispeer (int socktype);
#endif
nanomsg-0.8-beta/src/protocols/pubsub/xsub.c0000664000175000017500000001603012623652600022102 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2014 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "xsub.h"
#include "trie.h"
#include "../../nn.h"
#include "../../pubsub.h"
#include "../utils/fq.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/alloc.h"
#include "../../utils/list.h"
#include "../../utils/attr.h"
struct nn_xsub_data {
struct nn_fq_data fq;
};
struct nn_xsub {
struct nn_sockbase sockbase;
struct nn_fq fq;
struct nn_trie trie;
};
/* Private functions. */
static void nn_xsub_init (struct nn_xsub *self,
const struct nn_sockbase_vfptr *vfptr, void *hint);
static void nn_xsub_term (struct nn_xsub *self);
/* Implementation of nn_sockbase's virtual functions. */
static void nn_xsub_destroy (struct nn_sockbase *self);
static int nn_xsub_add (struct nn_sockbase *self, struct nn_pipe *pipe);
static void nn_xsub_rm (struct nn_sockbase *self, struct nn_pipe *pipe);
static void nn_xsub_in (struct nn_sockbase *self, struct nn_pipe *pipe);
static void nn_xsub_out (struct nn_sockbase *self, struct nn_pipe *pipe);
static int nn_xsub_events (struct nn_sockbase *self);
static int nn_xsub_recv (struct nn_sockbase *self, struct nn_msg *msg);
static int nn_xsub_setopt (struct nn_sockbase *self, int level, int option,
const void *optval, size_t optvallen);
static int nn_xsub_getopt (struct nn_sockbase *self, int level, int option,
void *optval, size_t *optvallen);
static const struct nn_sockbase_vfptr nn_xsub_sockbase_vfptr = {
NULL,
nn_xsub_destroy,
nn_xsub_add,
nn_xsub_rm,
nn_xsub_in,
nn_xsub_out,
nn_xsub_events,
NULL,
nn_xsub_recv,
nn_xsub_setopt,
nn_xsub_getopt
};
static void nn_xsub_init (struct nn_xsub *self,
const struct nn_sockbase_vfptr *vfptr, void *hint)
{
nn_sockbase_init (&self->sockbase, vfptr, hint);
nn_fq_init (&self->fq);
nn_trie_init (&self->trie);
}
static void nn_xsub_term (struct nn_xsub *self)
{
nn_trie_term (&self->trie);
nn_fq_term (&self->fq);
nn_sockbase_term (&self->sockbase);
}
void nn_xsub_destroy (struct nn_sockbase *self)
{
struct nn_xsub *xsub;
xsub = nn_cont (self, struct nn_xsub, sockbase);
nn_xsub_term (xsub);
nn_free (xsub);
}
static int nn_xsub_add (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xsub *xsub;
struct nn_xsub_data *data;
int rcvprio;
size_t sz;
xsub = nn_cont (self, struct nn_xsub, sockbase);
sz = sizeof (rcvprio);
nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, &sz);
nn_assert (sz == sizeof (rcvprio));
nn_assert (rcvprio >= 1 && rcvprio <= 16);
data = nn_alloc (sizeof (struct nn_xsub_data), "pipe data (sub)");
alloc_assert (data);
nn_pipe_setdata (pipe, data);
nn_fq_add (&xsub->fq, &data->fq, pipe, rcvprio);
return 0;
}
static void nn_xsub_rm (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xsub *xsub;
struct nn_xsub_data *data;
xsub = nn_cont (self, struct nn_xsub, sockbase);
data = nn_pipe_getdata (pipe);
nn_fq_rm (&xsub->fq, &data->fq);
nn_free (data);
}
static void nn_xsub_in (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xsub *xsub;
struct nn_xsub_data *data;
xsub = nn_cont (self, struct nn_xsub, sockbase);
data = nn_pipe_getdata (pipe);
nn_fq_in (&xsub->fq, &data->fq);
}
static void nn_xsub_out (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED struct nn_pipe *pipe)
{
/* We are not going to send any messages until subscription forwarding
is implemented, so there's no point is maintaining a list of pipes
ready for sending. */
}
static int nn_xsub_events (struct nn_sockbase *self)
{
return nn_fq_can_recv (&nn_cont (self, struct nn_xsub, sockbase)->fq) ?
NN_SOCKBASE_EVENT_IN : 0;
}
static int nn_xsub_recv (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
struct nn_xsub *xsub;
xsub = nn_cont (self, struct nn_xsub, sockbase);
/* Loop while a matching message is found or when there are no more
messages to receive. */
while (1) {
rc = nn_fq_recv (&xsub->fq, msg, NULL);
if (nn_slow (rc == -EAGAIN))
return -EAGAIN;
errnum_assert (rc >= 0, -rc);
rc = nn_trie_match (&xsub->trie, nn_chunkref_data (&msg->body),
nn_chunkref_size (&msg->body));
if (rc == 0) {
nn_msg_term (msg);
continue;
}
if (rc == 1)
return 0;
errnum_assert (0, -rc);
}
}
static int nn_xsub_setopt (struct nn_sockbase *self, int level, int option,
const void *optval, size_t optvallen)
{
int rc;
struct nn_xsub *xsub;
xsub = nn_cont (self, struct nn_xsub, sockbase);
if (level != NN_SUB)
return -ENOPROTOOPT;
if (option == NN_SUB_SUBSCRIBE) {
rc = nn_trie_subscribe (&xsub->trie, optval, optvallen);
if (rc >= 0)
return 0;
return rc;
}
if (option == NN_SUB_UNSUBSCRIBE) {
rc = nn_trie_unsubscribe (&xsub->trie, optval, optvallen);
if (rc >= 0)
return 0;
return rc;
}
return -ENOPROTOOPT;
}
static int nn_xsub_getopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED void *optval, NN_UNUSED size_t *optvallen)
{
return -ENOPROTOOPT;
}
int nn_xsub_create (void *hint, struct nn_sockbase **sockbase)
{
struct nn_xsub *self;
self = nn_alloc (sizeof (struct nn_xsub), "socket (xsub)");
alloc_assert (self);
nn_xsub_init (self, &nn_xsub_sockbase_vfptr, hint);
*sockbase = &self->sockbase;
return 0;
}
int nn_xsub_ispeer (int socktype)
{
return socktype == NN_PUB ? 1 : 0;
}
static struct nn_socktype nn_xsub_socktype_struct = {
AF_SP_RAW,
NN_SUB,
NN_SOCKTYPE_FLAG_NOSEND,
nn_xsub_create,
nn_xsub_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_xsub_socktype = &nn_xsub_socktype_struct;
nanomsg-0.8-beta/src/protocols/reqrep/0000775000175000017500000000000012623652617020763 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/protocols/reqrep/req.h0000664000175000017500000000605212623652600021716 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_REQ_INCLUDED
#define NN_REQ_INCLUDED
#include "xreq.h"
#include "task.h"
#include "../../protocol.h"
#include "../../aio/fsm.h"
struct nn_req {
/* The base class. Raw REQ socket. */
struct nn_xreq xreq;
/* The state machine. */
struct nn_fsm fsm;
int state;
/* Last request ID assigned. */
uint32_t lastid;
/* Protocol-specific socket options. */
int resend_ivl;
/* The request being processed. */
struct nn_task task;
};
extern struct nn_socktype *nn_req_socktype;
/* Some users may want to extend the REQ protocol similar to how REQ extends XREQ.
Expose these methods to improve extensibility. */
void nn_req_init (struct nn_req *self,
const struct nn_sockbase_vfptr *vfptr, void *hint);
void nn_req_term (struct nn_req *self);
int nn_req_inprogress (struct nn_req *self);
void nn_req_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
void nn_req_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
void nn_req_action_send (struct nn_req *self, int allow_delay);
/* Implementation of nn_sockbase's virtual functions. */
void nn_req_stop (struct nn_sockbase *self);
void nn_req_destroy (struct nn_sockbase *self);
void nn_req_in (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_req_out (struct nn_sockbase *self, struct nn_pipe *pipe);
int nn_req_events (struct nn_sockbase *self);
int nn_req_csend (struct nn_sockbase *self, struct nn_msg *msg);
void nn_req_rm (struct nn_sockbase *self, struct nn_pipe *pipe);
int nn_req_crecv (struct nn_sockbase *self, struct nn_msg *msg);
int nn_req_setopt (struct nn_sockbase *self, int level, int option,
const void *optval, size_t optvallen);
int nn_req_getopt (struct nn_sockbase *self, int level, int option,
void *optval, size_t *optvallen);
int nn_req_csend (struct nn_sockbase *self, struct nn_msg *msg);
int nn_req_crecv (struct nn_sockbase *self, struct nn_msg *msg);
#endif
nanomsg-0.8-beta/src/protocols/reqrep/req.c0000664000175000017500000005163312623652600021716 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "req.h"
#include "xreq.h"
#include "../../nn.h"
#include "../../reqrep.h"
#include "../../aio/fsm.h"
#include "../../aio/timer.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/alloc.h"
#include "../../utils/random.h"
#include "../../utils/wire.h"
#include "../../utils/list.h"
#include "../../utils/int.h"
#include "../../utils/attr.h"
#include
#include
/* Default re-send interval is 1 minute. */
#define NN_REQ_DEFAULT_RESEND_IVL 60000
#define NN_REQ_STATE_IDLE 1
#define NN_REQ_STATE_PASSIVE 2
#define NN_REQ_STATE_DELAYED 3
#define NN_REQ_STATE_ACTIVE 4
#define NN_REQ_STATE_TIMED_OUT 5
#define NN_REQ_STATE_CANCELLING 6
#define NN_REQ_STATE_STOPPING_TIMER 7
#define NN_REQ_STATE_DONE 8
#define NN_REQ_STATE_STOPPING 9
#define NN_REQ_ACTION_START 1
#define NN_REQ_ACTION_IN 2
#define NN_REQ_ACTION_OUT 3
#define NN_REQ_ACTION_SENT 4
#define NN_REQ_ACTION_RECEIVED 5
#define NN_REQ_ACTION_PIPE_RM 6
#define NN_REQ_SRC_RESEND_TIMER 1
static const struct nn_sockbase_vfptr nn_req_sockbase_vfptr = {
nn_req_stop,
nn_req_destroy,
nn_xreq_add,
nn_req_rm,
nn_req_in,
nn_req_out,
nn_req_events,
nn_req_csend,
nn_req_crecv,
nn_req_setopt,
nn_req_getopt
};
void nn_req_init (struct nn_req *self,
const struct nn_sockbase_vfptr *vfptr, void *hint)
{
nn_req_handle hndl;
nn_xreq_init (&self->xreq, vfptr, hint);
nn_fsm_init_root (&self->fsm, nn_req_handler, nn_req_shutdown,
nn_sockbase_getctx (&self->xreq.sockbase));
self->state = NN_REQ_STATE_IDLE;
/* Start assigning request IDs beginning with a random number. This way
there should be no key clashes even if the executable is re-started. */
nn_random_generate (&self->lastid, sizeof (self->lastid));
self->task.sent_to = NULL;
nn_msg_init (&self->task.request, 0);
nn_msg_init (&self->task.reply, 0);
nn_timer_init (&self->task.timer, NN_REQ_SRC_RESEND_TIMER, &self->fsm);
self->resend_ivl = NN_REQ_DEFAULT_RESEND_IVL;
/* For now, handle is empty. */
memset (&hndl, 0, sizeof (hndl));
nn_task_init (&self->task, self->lastid, hndl);
/* Start the state machine. */
nn_fsm_start (&self->fsm);
}
void nn_req_term (struct nn_req *self)
{
nn_timer_term (&self->task.timer);
nn_task_term (&self->task);
nn_msg_term (&self->task.reply);
nn_msg_term (&self->task.request);
nn_fsm_term (&self->fsm);
nn_xreq_term (&self->xreq);
}
void nn_req_stop (struct nn_sockbase *self)
{
struct nn_req *req;
req = nn_cont (self, struct nn_req, xreq.sockbase);
nn_fsm_stop (&req->fsm);
}
void nn_req_destroy (struct nn_sockbase *self)
{
struct nn_req *req;
req = nn_cont (self, struct nn_req, xreq.sockbase);
nn_req_term (req);
nn_free (req);
}
int nn_req_inprogress (struct nn_req *self)
{
/* Return 1 if there's a request submitted. 0 otherwise. */
return self->state == NN_REQ_STATE_IDLE ||
self->state == NN_REQ_STATE_PASSIVE ||
self->state == NN_REQ_STATE_STOPPING ? 0 : 1;
}
void nn_req_in (struct nn_sockbase *self, struct nn_pipe *pipe)
{
int rc;
struct nn_req *req;
uint32_t reqid;
req = nn_cont (self, struct nn_req, xreq.sockbase);
/* Pass the pipe to the raw REQ socket. */
nn_xreq_in (&req->xreq.sockbase, pipe);
while (1) {
/* Get new reply. */
rc = nn_xreq_recv (&req->xreq.sockbase, &req->task.reply);
if (nn_slow (rc == -EAGAIN))
return;
errnum_assert (rc == 0, -rc);
/* No request was sent. Getting a reply doesn't make sense. */
if (nn_slow (!nn_req_inprogress (req))) {
nn_msg_term (&req->task.reply);
continue;
}
/* Ignore malformed replies. */
if (nn_slow (nn_chunkref_size (&req->task.reply.sphdr) !=
sizeof (uint32_t))) {
nn_msg_term (&req->task.reply);
continue;
}
/* Ignore replies with incorrect request IDs. */
reqid = nn_getl (nn_chunkref_data (&req->task.reply.sphdr));
if (nn_slow (!(reqid & 0x80000000))) {
nn_msg_term (&req->task.reply);
continue;
}
if (nn_slow (reqid != (req->task.id | 0x80000000))) {
nn_msg_term (&req->task.reply);
continue;
}
/* Trim the request ID. */
nn_chunkref_term (&req->task.reply.sphdr);
nn_chunkref_init (&req->task.reply.sphdr, 0);
/* TODO: Deallocate the request here? */
/* Notify the state machine. */
if (req->state == NN_REQ_STATE_ACTIVE)
nn_fsm_action (&req->fsm, NN_REQ_ACTION_IN);
return;
}
}
void nn_req_out (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_req *req;
req = nn_cont (self, struct nn_req, xreq.sockbase);
/* Add the pipe to the underlying raw socket. */
nn_xreq_out (&req->xreq.sockbase, pipe);
/* Notify the state machine. */
if (req->state == NN_REQ_STATE_DELAYED)
nn_fsm_action (&req->fsm, NN_REQ_ACTION_OUT);
}
int nn_req_events (struct nn_sockbase *self)
{
int rc;
struct nn_req *req;
req = nn_cont (self, struct nn_req, xreq.sockbase);
/* OUT is signalled all the time because sending a request while
another one is being processed cancels the old one. */
rc = NN_SOCKBASE_EVENT_OUT;
/* In DONE state the reply is stored in 'reply' field. */
if (req->state == NN_REQ_STATE_DONE)
rc |= NN_SOCKBASE_EVENT_IN;
return rc;
}
int nn_req_send (NN_UNUSED int s, NN_UNUSED nn_req_handle hndl,
NN_UNUSED const void *buf, NN_UNUSED size_t len, NN_UNUSED int flags)
{
nn_assert (0);
}
int nn_req_csend (struct nn_sockbase *self, struct nn_msg *msg)
{
struct nn_req *req;
req = nn_cont (self, struct nn_req, xreq.sockbase);
/* Generate new request ID for the new request and put it into message
header. The most important bit is set to 1 to indicate that this is
the bottom of the backtrace stack. */
++req->task.id;
nn_assert (nn_chunkref_size (&msg->sphdr) == 0);
nn_chunkref_term (&msg->sphdr);
nn_chunkref_init (&msg->sphdr, 4);
nn_putl (nn_chunkref_data (&msg->sphdr), req->task.id | 0x80000000);
/* Store the message so that it can be re-sent if there's no reply. */
nn_msg_term (&req->task.request);
nn_msg_mv (&req->task.request, msg);
/* Notify the state machine. */
nn_fsm_action (&req->fsm, NN_REQ_ACTION_SENT);
return 0;
}
int nn_req_recv (NN_UNUSED int s, NN_UNUSED nn_req_handle *hndl,
NN_UNUSED void *buf, NN_UNUSED size_t len, NN_UNUSED int flags)
{
nn_assert (0);
}
int nn_req_crecv (struct nn_sockbase *self, struct nn_msg *msg)
{
struct nn_req *req;
req = nn_cont (self, struct nn_req, xreq.sockbase);
/* No request was sent. Waiting for a reply doesn't make sense. */
if (nn_slow (!nn_req_inprogress (req)))
return -EFSM;
/* If reply was not yet recieved, wait further. */
if (nn_slow (req->state != NN_REQ_STATE_DONE))
return -EAGAIN;
/* If the reply was already received, just pass it to the caller. */
nn_msg_mv (msg, &req->task.reply);
nn_msg_init (&req->task.reply, 0);
/* Notify the state machine. */
nn_fsm_action (&req->fsm, NN_REQ_ACTION_RECEIVED);
return 0;
}
int nn_req_setopt (struct nn_sockbase *self, int level, int option,
const void *optval, size_t optvallen)
{
struct nn_req *req;
req = nn_cont (self, struct nn_req, xreq.sockbase);
if (level != NN_REQ)
return -ENOPROTOOPT;
if (option == NN_REQ_RESEND_IVL) {
if (nn_slow (optvallen != sizeof (int)))
return -EINVAL;
req->resend_ivl = *(int*) optval;
return 0;
}
return -ENOPROTOOPT;
}
int nn_req_getopt (struct nn_sockbase *self, int level, int option,
void *optval, size_t *optvallen)
{
struct nn_req *req;
req = nn_cont (self, struct nn_req, xreq.sockbase);
if (level != NN_REQ)
return -ENOPROTOOPT;
if (option == NN_REQ_RESEND_IVL) {
if (nn_slow (*optvallen < sizeof (int)))
return -EINVAL;
*(int*) optval = req->resend_ivl;
*optvallen = sizeof (int);
return 0;
}
return -ENOPROTOOPT;
}
void nn_req_shutdown (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_req *req;
req = nn_cont (self, struct nn_req, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
nn_timer_stop (&req->task.timer);
req->state = NN_REQ_STATE_STOPPING;
}
if (nn_slow (req->state == NN_REQ_STATE_STOPPING)) {
if (!nn_timer_isidle (&req->task.timer))
return;
req->state = NN_REQ_STATE_IDLE;
nn_fsm_stopped_noevent (&req->fsm);
nn_sockbase_stopped (&req->xreq.sockbase);
return;
}
nn_fsm_bad_state(req->state, src, type);
}
void nn_req_handler (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_req *req;
req = nn_cont (self, struct nn_req, fsm);
switch (req->state) {
/******************************************************************************/
/* IDLE state. */
/* The socket was created recently. Intermediate state. */
/* Pass straight to the PASSIVE state. */
/******************************************************************************/
case NN_REQ_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
req->state = NN_REQ_STATE_PASSIVE;
return;
default:
nn_fsm_bad_action (req->state, src, type);
}
default:
nn_fsm_bad_source (req->state, src, type);
}
/******************************************************************************/
/* PASSIVE state. */
/* No request is submitted. */
/******************************************************************************/
case NN_REQ_STATE_PASSIVE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_REQ_ACTION_SENT:
nn_req_action_send (req, 1);
return;
default:
nn_fsm_bad_action (req->state, src, type);
}
default:
nn_fsm_bad_source (req->state, src, type);
}
/******************************************************************************/
/* DELAYED state. */
/* Request was submitted but it could not be sent to the network because */
/* there was no peer available at the moment. Now we are waiting for the */
/* peer to arrive to send the request to it. */
/******************************************************************************/
case NN_REQ_STATE_DELAYED:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_REQ_ACTION_OUT:
nn_req_action_send (req, 0);
return;
case NN_REQ_ACTION_SENT:
return;
default:
nn_fsm_bad_action (req->state, src, type);
}
default:
nn_fsm_bad_source (req->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/* Request was submitted. Waiting for reply. */
/******************************************************************************/
case NN_REQ_STATE_ACTIVE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_REQ_ACTION_IN:
/* Reply arrived. */
nn_timer_stop (&req->task.timer);
req->task.sent_to = NULL;
req->state = NN_REQ_STATE_STOPPING_TIMER;
return;
case NN_REQ_ACTION_SENT:
/* New request was sent while the old one was still being
processed. Cancel the old request first. */
nn_timer_stop (&req->task.timer);
req->task.sent_to = NULL;
req->state = NN_REQ_STATE_CANCELLING;
return;
case NN_REQ_ACTION_PIPE_RM:
/* Pipe that we sent request to is removed */
nn_timer_stop (&req->task.timer);
req->task.sent_to = NULL;
/* Pretend we timed out so request resent immediately */
req->state = NN_REQ_STATE_TIMED_OUT;
return;
default:
nn_fsm_bad_action (req->state, src, type);
}
case NN_REQ_SRC_RESEND_TIMER:
switch (type) {
case NN_TIMER_TIMEOUT:
nn_timer_stop (&req->task.timer);
req->task.sent_to = NULL;
req->state = NN_REQ_STATE_TIMED_OUT;
return;
default:
nn_fsm_bad_action (req->state, src, type);
}
default:
nn_fsm_bad_source (req->state, src, type);
}
/******************************************************************************/
/* TIMED_OUT state. */
/* Waiting for reply has timed out. Stopping the timer. Afterwards, we'll */
/* re-send the request. */
/******************************************************************************/
case NN_REQ_STATE_TIMED_OUT:
switch (src) {
case NN_REQ_SRC_RESEND_TIMER:
switch (type) {
case NN_TIMER_STOPPED:
nn_req_action_send (req, 1);
return;
default:
nn_fsm_bad_action (req->state, src, type);
}
case NN_FSM_ACTION:
switch (type) {
case NN_REQ_ACTION_SENT:
req->state = NN_REQ_STATE_CANCELLING;
return;
default:
nn_fsm_bad_action (req->state, src, type);
}
default:
nn_fsm_bad_source (req->state, src, type);
}
/******************************************************************************/
/* CANCELLING state. */
/* Request was canceled. Waiting till the timer is stopped. Note that */
/* cancelling is done by sending a new request. Thus there's already */
/* a request waiting to be sent in this state. */
/******************************************************************************/
case NN_REQ_STATE_CANCELLING:
switch (src) {
case NN_REQ_SRC_RESEND_TIMER:
switch (type) {
case NN_TIMER_STOPPED:
/* Timer is stopped. Now we can send the delayed request. */
nn_req_action_send (req, 1);
return;
default:
nn_fsm_bad_action (req->state, src, type);
}
case NN_FSM_ACTION:
switch (type) {
case NN_REQ_ACTION_SENT:
/* No need to do anything here. Old delayed request is just
replaced by the new one that will be sent once the timer
is closed. */
return;
default:
nn_fsm_bad_action (req->state, src, type);
}
default:
nn_fsm_bad_source (req->state, src, type);
}
/******************************************************************************/
/* STOPPING_TIMER state. */
/* Reply was delivered. Waiting till the timer is stopped. */
/******************************************************************************/
case NN_REQ_STATE_STOPPING_TIMER:
switch (src) {
case NN_REQ_SRC_RESEND_TIMER:
switch (type) {
case NN_TIMER_STOPPED:
req->state = NN_REQ_STATE_DONE;
return;
default:
nn_fsm_bad_action (req->state, src, type);
}
case NN_FSM_ACTION:
switch (type) {
case NN_REQ_ACTION_SENT:
req->state = NN_REQ_STATE_CANCELLING;
return;
default:
nn_fsm_bad_action (req->state, src, type);
}
default:
nn_fsm_bad_source (req->state, src, type);
}
/******************************************************************************/
/* DONE state. */
/* Reply was received but not yet retrieved by the user. */
/******************************************************************************/
case NN_REQ_STATE_DONE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_REQ_ACTION_RECEIVED:
req->state = NN_REQ_STATE_PASSIVE;
return;
case NN_REQ_ACTION_SENT:
nn_req_action_send (req, 1);
return;
default:
nn_fsm_bad_action (req->state, src, type);
}
default:
nn_fsm_bad_source (req->state, src, type);
}
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (req->state, src, type);
}
}
/******************************************************************************/
/* State machine actions. */
/******************************************************************************/
void nn_req_action_send (struct nn_req *self, int allow_delay)
{
int rc;
struct nn_msg msg;
struct nn_pipe *to;
/* Send the request. */
nn_msg_cp (&msg, &self->task.request);
rc = nn_xreq_send_to (&self->xreq.sockbase, &msg, &to);
/* If the request cannot be sent at the moment wait till
new outbound pipe arrives. */
if (nn_slow (rc == -EAGAIN)) {
nn_assert (allow_delay == 1);
nn_msg_term (&msg);
self->state = NN_REQ_STATE_DELAYED;
return;
}
/* Request was successfully sent. Set up the re-send timer
in case the request gets lost somewhere further out
in the topology. */
if (nn_fast (rc == 0)) {
nn_timer_start (&self->task.timer, self->resend_ivl);
nn_assert (to);
self->task.sent_to = to;
self->state = NN_REQ_STATE_ACTIVE;
return;
}
/* Unexpected error. */
errnum_assert (0, -rc);
}
static int nn_req_create (void *hint, struct nn_sockbase **sockbase)
{
struct nn_req *self;
self = nn_alloc (sizeof (struct nn_req), "socket (req)");
alloc_assert (self);
nn_req_init (self, &nn_req_sockbase_vfptr, hint);
*sockbase = &self->xreq.sockbase;
return 0;
}
void nn_req_rm (struct nn_sockbase *self, struct nn_pipe *pipe) {
struct nn_req *req;
req = nn_cont (self, struct nn_req, xreq.sockbase);
nn_xreq_rm (self, pipe);
if (nn_slow (pipe == req->task.sent_to)) {
nn_fsm_action (&req->fsm, NN_REQ_ACTION_PIPE_RM);
}
}
static struct nn_socktype nn_req_socktype_struct = {
AF_SP,
NN_REQ,
0,
nn_req_create,
nn_xreq_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_req_socktype = &nn_req_socktype_struct;
nanomsg-0.8-beta/src/protocols/reqrep/rep.h0000664000175000017500000000364312623652600021720 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_REP_INCLUDED
#define NN_REP_INCLUDED
#include "../../protocol.h"
#include "xrep.h"
extern struct nn_socktype *nn_rep_socktype;
struct nn_rep {
struct nn_xrep xrep;
uint32_t flags;
struct nn_chunkref backtrace;
};
/* Some users may want to extend the REP protocol similar to how REP extends XREP.
Expose these methods to improve extensibility. */
void nn_rep_init (struct nn_rep *self,
const struct nn_sockbase_vfptr *vfptr, void *hint);
void nn_rep_term (struct nn_rep *self);
/* Implementation of nn_sockbase's virtual functions. */
void nn_rep_destroy (struct nn_sockbase *self);
int nn_rep_events (struct nn_sockbase *self);
int nn_rep_send (struct nn_sockbase *self, struct nn_msg *msg);
int nn_rep_recv (struct nn_sockbase *self, struct nn_msg *msg);
#endif
nanomsg-0.8-beta/src/protocols/reqrep/rep.c0000664000175000017500000001075012623652600021710 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "rep.h"
#include "xrep.h"
#include "../../nn.h"
#include "../../reqrep.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/alloc.h"
#include "../../utils/chunkref.h"
#include "../../utils/wire.h"
#include "../../utils/list.h"
#include "../../utils/int.h"
#include
#include
#define NN_REP_INPROGRESS 1
static const struct nn_sockbase_vfptr nn_rep_sockbase_vfptr = {
NULL,
nn_rep_destroy,
nn_xrep_add,
nn_xrep_rm,
nn_xrep_in,
nn_xrep_out,
nn_rep_events,
nn_rep_send,
nn_rep_recv,
nn_xrep_setopt,
nn_xrep_getopt
};
void nn_rep_init (struct nn_rep *self,
const struct nn_sockbase_vfptr *vfptr, void *hint)
{
nn_xrep_init (&self->xrep, vfptr, hint);
self->flags = 0;
}
void nn_rep_term (struct nn_rep *self)
{
if (self->flags & NN_REP_INPROGRESS)
nn_chunkref_term (&self->backtrace);
nn_xrep_term (&self->xrep);
}
void nn_rep_destroy (struct nn_sockbase *self)
{
struct nn_rep *rep;
rep = nn_cont (self, struct nn_rep, xrep.sockbase);
nn_rep_term (rep);
nn_free (rep);
}
int nn_rep_events (struct nn_sockbase *self)
{
struct nn_rep *rep;
int events;
rep = nn_cont (self, struct nn_rep, xrep.sockbase);
events = nn_xrep_events (&rep->xrep.sockbase);
if (!(rep->flags & NN_REP_INPROGRESS))
events &= ~NN_SOCKBASE_EVENT_OUT;
return events;
}
int nn_rep_send (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
struct nn_rep *rep;
rep = nn_cont (self, struct nn_rep, xrep.sockbase);
/* If no request was received, there's nowhere to send the reply to. */
if (nn_slow (!(rep->flags & NN_REP_INPROGRESS)))
return -EFSM;
/* Move the stored backtrace into the message header. */
nn_assert (nn_chunkref_size (&msg->sphdr) == 0);
nn_chunkref_term (&msg->sphdr);
nn_chunkref_mv (&msg->sphdr, &rep->backtrace);
rep->flags &= ~NN_REP_INPROGRESS;
/* Send the reply. If it cannot be sent because of pushback,
drop it silently. */
rc = nn_xrep_send (&rep->xrep.sockbase, msg);
errnum_assert (rc == 0 || rc == -EAGAIN, -rc);
return 0;
}
int nn_rep_recv (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
struct nn_rep *rep;
rep = nn_cont (self, struct nn_rep, xrep.sockbase);
/* If a request is already being processed, cancel it. */
if (nn_slow (rep->flags & NN_REP_INPROGRESS)) {
nn_chunkref_term (&rep->backtrace);
rep->flags &= ~NN_REP_INPROGRESS;
}
/* Receive the request. */
rc = nn_xrep_recv (&rep->xrep.sockbase, msg);
if (nn_slow (rc == -EAGAIN))
return -EAGAIN;
errnum_assert (rc == 0, -rc);
/* Store the backtrace. */
nn_chunkref_mv (&rep->backtrace, &msg->sphdr);
nn_chunkref_init (&msg->sphdr, 0);
rep->flags |= NN_REP_INPROGRESS;
return 0;
}
static int nn_rep_create (void *hint, struct nn_sockbase **sockbase)
{
struct nn_rep *self;
self = nn_alloc (sizeof (struct nn_rep), "socket (rep)");
alloc_assert (self);
nn_rep_init (self, &nn_rep_sockbase_vfptr, hint);
*sockbase = &self->xrep.sockbase;
return 0;
}
static struct nn_socktype nn_rep_socktype_struct = {
AF_SP,
NN_REP,
0,
nn_rep_create,
nn_xrep_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_rep_socktype = &nn_rep_socktype_struct;
nanomsg-0.8-beta/src/protocols/reqrep/task.h0000664000175000017500000000417312623652600022073 0ustar00travistravis00000000000000/*
Copyright (c) 2014 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_TASK_INCLUDED
#define NN_TASK_INCLUDED
#include "../../reqrep.h"
#include "../../aio/fsm.h"
#include "../../aio/timer.h"
#include "../../utils/msg.h"
#include "../../utils/int.h"
struct nn_task {
/* ID of the request being currently processed. Replies for different
requests are considered stale and simply dropped. */
uint32_t id;
/* User-defined handle of the task. */
nn_req_handle hndl;
/* Stored request, so that it can be re-sent if needed. */
struct nn_msg request;
/* Stored reply, so that user can retrieve it later on. */
struct nn_msg reply;
/* Timer used to wait while request should be re-sent. */
struct nn_timer timer;
/* Pipe the current request has been sent to. This is an optimisation so
that request can be re-sent immediately if the pipe disappears. */
struct nn_pipe *sent_to;
};
void nn_task_init (struct nn_task *self, uint32_t id, nn_req_handle hndl);
void nn_task_term (struct nn_task *self);
#endif
nanomsg-0.8-beta/src/protocols/reqrep/task.c0000664000175000017500000000254112623652600022063 0ustar00travistravis00000000000000/*
Copyright (c) 2014 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "task.h"
#include "../../utils/attr.h"
void nn_task_init (struct nn_task *self, uint32_t id, nn_req_handle hndl)
{
self->id = id;
self->hndl = hndl;
}
void nn_task_term (NN_UNUSED struct nn_task *self)
{
}
nanomsg-0.8-beta/src/protocols/reqrep/xrep.h0000664000175000017500000000520212623652600022101 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_XREP_INCLUDED
#define NN_XREP_INCLUDED
#include "../../protocol.h"
#include "../../utils/hash.h"
#include "../../utils/int.h"
#include "../utils/fq.h"
#include
#define NN_XREP_OUT 1
struct nn_xrep_data {
struct nn_pipe *pipe;
struct nn_hash_item outitem;
struct nn_fq_data initem;
uint32_t flags;
};
struct nn_xrep {
struct nn_sockbase sockbase;
/* Key to be assigned to the next added pipe. */
uint32_t next_key;
/* Map of all registered pipes indexed by the peer ID. */
struct nn_hash outpipes;
/* Fair-queuer to get messages from. */
struct nn_fq inpipes;
};
void nn_xrep_init (struct nn_xrep *self, const struct nn_sockbase_vfptr *vfptr,
void *hint);
void nn_xrep_term (struct nn_xrep *self);
int nn_xrep_add (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_xrep_rm (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_xrep_in (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_xrep_out (struct nn_sockbase *self, struct nn_pipe *pipe);
int nn_xrep_events (struct nn_sockbase *self);
int nn_xrep_send (struct nn_sockbase *self, struct nn_msg *msg);
int nn_xrep_recv (struct nn_sockbase *self, struct nn_msg *msg);
int nn_xrep_setopt (struct nn_sockbase *self, int level, int option,
const void *optval, size_t optvallen);
int nn_xrep_getopt (struct nn_sockbase *self, int level, int option,
void *optval, size_t *optvallen);
int nn_xrep_ispeer (int socktype);
extern struct nn_socktype *nn_xrep_socktype;
#endif
nanomsg-0.8-beta/src/protocols/reqrep/xrep.c0000664000175000017500000002027212623652600022100 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2014 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "xrep.h"
#include "../../nn.h"
#include "../../reqrep.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/alloc.h"
#include "../../utils/random.h"
#include "../../utils/wire.h"
#include "../../utils/list.h"
#include "../../utils/attr.h"
#include
/* Private functions. */
static void nn_xrep_destroy (struct nn_sockbase *self);
static const struct nn_sockbase_vfptr nn_xrep_sockbase_vfptr = {
NULL,
nn_xrep_destroy,
nn_xrep_add,
nn_xrep_rm,
nn_xrep_in,
nn_xrep_out,
nn_xrep_events,
nn_xrep_send,
nn_xrep_recv,
nn_xrep_setopt,
nn_xrep_getopt
};
void nn_xrep_init (struct nn_xrep *self, const struct nn_sockbase_vfptr *vfptr,
void *hint)
{
nn_sockbase_init (&self->sockbase, vfptr, hint);
/* Start assigning keys beginning with a random number. This way there
are no key clashes even if the executable is re-started. */
nn_random_generate (&self->next_key, sizeof (self->next_key));
nn_hash_init (&self->outpipes);
nn_fq_init (&self->inpipes);
}
void nn_xrep_term (struct nn_xrep *self)
{
nn_fq_term (&self->inpipes);
nn_hash_term (&self->outpipes);
nn_sockbase_term (&self->sockbase);
}
static void nn_xrep_destroy (struct nn_sockbase *self)
{
struct nn_xrep *xrep;
xrep = nn_cont (self, struct nn_xrep, sockbase);
nn_xrep_term (xrep);
nn_free (xrep);
}
int nn_xrep_add (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xrep *xrep;
struct nn_xrep_data *data;
int rcvprio;
size_t sz;
xrep = nn_cont (self, struct nn_xrep, sockbase);
sz = sizeof (rcvprio);
nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, &sz);
nn_assert (sz == sizeof (rcvprio));
nn_assert (rcvprio >= 1 && rcvprio <= 16);
data = nn_alloc (sizeof (struct nn_xrep_data), "pipe data (xrep)");
alloc_assert (data);
data->pipe = pipe;
nn_hash_item_init (&data->outitem);
data->flags = 0;
nn_hash_insert (&xrep->outpipes, xrep->next_key & 0x7fffffff,
&data->outitem);
++xrep->next_key;
nn_fq_add (&xrep->inpipes, &data->initem, pipe, rcvprio);
nn_pipe_setdata (pipe, data);
return 0;
}
void nn_xrep_rm (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xrep *xrep;
struct nn_xrep_data *data;
xrep = nn_cont (self, struct nn_xrep, sockbase);
data = nn_pipe_getdata (pipe);
nn_fq_rm (&xrep->inpipes, &data->initem);
nn_hash_erase (&xrep->outpipes, &data->outitem);
nn_hash_item_term (&data->outitem);
nn_free (data);
}
void nn_xrep_in (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xrep *xrep;
struct nn_xrep_data *data;
xrep = nn_cont (self, struct nn_xrep, sockbase);
data = nn_pipe_getdata (pipe);
nn_fq_in (&xrep->inpipes, &data->initem);
}
void nn_xrep_out (NN_UNUSED struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xrep_data *data;
data = nn_pipe_getdata (pipe);
data->flags |= NN_XREP_OUT;
}
int nn_xrep_events (struct nn_sockbase *self)
{
return (nn_fq_can_recv (&nn_cont (self, struct nn_xrep,
sockbase)->inpipes) ? NN_SOCKBASE_EVENT_IN : 0) | NN_SOCKBASE_EVENT_OUT;
}
int nn_xrep_send (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
uint32_t key;
struct nn_xrep *xrep;
struct nn_xrep_data *data;
xrep = nn_cont (self, struct nn_xrep, sockbase);
/* We treat invalid peer ID as if the peer was non-existent. */
if (nn_slow (nn_chunkref_size (&msg->sphdr) < sizeof (uint32_t))) {
nn_msg_term (msg);
return 0;
}
/* Retrieve the destination peer ID. Trim it from the header. */
key = nn_getl (nn_chunkref_data (&msg->sphdr));
nn_chunkref_trim (&msg->sphdr, 4);
/* Find the appropriate pipe to send the message to. If there's none,
or if it's not ready for sending, silently drop the message. */
data = nn_cont (nn_hash_get (&xrep->outpipes, key), struct nn_xrep_data,
outitem);
if (!data || !(data->flags & NN_XREP_OUT)) {
nn_msg_term (msg);
return 0;
}
/* Send the message. */
rc = nn_pipe_send (data->pipe, msg);
errnum_assert (rc >= 0, -rc);
if (rc & NN_PIPE_RELEASE)
data->flags &= ~NN_XREP_OUT;
return 0;
}
int nn_xrep_recv (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
struct nn_xrep *xrep;
struct nn_pipe *pipe;
int i;
void *data;
size_t sz;
struct nn_chunkref ref;
struct nn_xrep_data *pipedata;
xrep = nn_cont (self, struct nn_xrep, sockbase);
rc = nn_fq_recv (&xrep->inpipes, msg, &pipe);
if (nn_slow (rc < 0))
return rc;
if (!(rc & NN_PIPE_PARSED)) {
/* Determine the size of the message header. */
data = nn_chunkref_data (&msg->body);
sz = nn_chunkref_size (&msg->body);
i = 0;
while (1) {
/* Ignore the malformed requests without the bottom of the stack. */
if (nn_slow ((i + 1) * sizeof (uint32_t) > sz)) {
nn_msg_term (msg);
return -EAGAIN;
}
/* If the bottom of the backtrace stack is reached, proceed. */
if (nn_getl ((uint8_t*)(((uint32_t*) data) + i)) & 0x80000000)
break;
++i;
}
++i;
/* Split the header and the body. */
nn_assert (nn_chunkref_size (&msg->sphdr) == 0);
nn_chunkref_term (&msg->sphdr);
nn_chunkref_init (&msg->sphdr, i * sizeof (uint32_t));
memcpy (nn_chunkref_data (&msg->sphdr), data, i * sizeof (uint32_t));
nn_chunkref_trim (&msg->body, i * sizeof (uint32_t));
}
/* Prepend the header by the pipe key. */
pipedata = nn_pipe_getdata (pipe);
nn_chunkref_init (&ref,
nn_chunkref_size (&msg->sphdr) + sizeof (uint32_t));
nn_putl (nn_chunkref_data (&ref), pipedata->outitem.key);
memcpy (((uint8_t*) nn_chunkref_data (&ref)) + sizeof (uint32_t),
nn_chunkref_data (&msg->sphdr), nn_chunkref_size (&msg->sphdr));
nn_chunkref_term (&msg->sphdr);
nn_chunkref_mv (&msg->sphdr, &ref);
return 0;
}
int nn_xrep_setopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED const void *optval, NN_UNUSED size_t optvallen)
{
return -ENOPROTOOPT;
}
int nn_xrep_getopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED void *optval, NN_UNUSED size_t *optvallen)
{
return -ENOPROTOOPT;
}
static int nn_xrep_create (void *hint, struct nn_sockbase **sockbase)
{
struct nn_xrep *self;
self = nn_alloc (sizeof (struct nn_xrep), "socket (xrep)");
alloc_assert (self);
nn_xrep_init (self, &nn_xrep_sockbase_vfptr, hint);
*sockbase = &self->sockbase;
return 0;
}
int nn_xrep_ispeer (int socktype)
{
return socktype == NN_REQ ? 1 : 0;
}
static struct nn_socktype nn_xrep_socktype_struct = {
AF_SP_RAW,
NN_REP,
0,
nn_xrep_create,
nn_xrep_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_xrep_socktype = &nn_xrep_socktype_struct;
nanomsg-0.8-beta/src/protocols/reqrep/xreq.h0000664000175000017500000000447712623652600022117 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_XREQ_INCLUDED
#define NN_XREQ_INCLUDED
#include "../../protocol.h"
#include "../utils/lb.h"
#include "../utils/fq.h"
struct nn_xreq {
struct nn_sockbase sockbase;
struct nn_lb lb;
struct nn_fq fq;
};
void nn_xreq_init (struct nn_xreq *self, const struct nn_sockbase_vfptr *vfptr,
void *hint);
void nn_xreq_term (struct nn_xreq *self);
int nn_xreq_add (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_xreq_rm (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_xreq_in (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_xreq_out (struct nn_sockbase *self, struct nn_pipe *pipe);
int nn_xreq_events (struct nn_sockbase *self);
int nn_xreq_send (struct nn_sockbase *self, struct nn_msg *msg);
int nn_xreq_send_to (struct nn_sockbase *self, struct nn_msg *msg,
struct nn_pipe **to);
int nn_xreq_recv (struct nn_sockbase *self, struct nn_msg *msg);
int nn_xreq_setopt (struct nn_sockbase *self, int level, int option,
const void *optval, size_t optvallen);
int nn_xreq_getopt (struct nn_sockbase *self, int level, int option,
void *optval, size_t *optvallen);
int nn_xreq_ispeer (int socktype);
extern struct nn_socktype *nn_xreq_socktype;
#endif
nanomsg-0.8-beta/src/protocols/reqrep/xreq.c0000664000175000017500000001531712623652600022105 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2014 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "xreq.h"
#include "../../nn.h"
#include "../../reqrep.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/alloc.h"
#include "../../utils/list.h"
#include "../../utils/attr.h"
struct nn_xreq_data {
struct nn_lb_data lb;
struct nn_fq_data fq;
};
/* Private functions. */
static void nn_xreq_destroy (struct nn_sockbase *self);
static const struct nn_sockbase_vfptr nn_xreq_sockbase_vfptr = {
NULL,
nn_xreq_destroy,
nn_xreq_add,
nn_xreq_rm,
nn_xreq_in,
nn_xreq_out,
nn_xreq_events,
nn_xreq_send,
nn_xreq_recv,
nn_xreq_setopt,
nn_xreq_getopt
};
void nn_xreq_init (struct nn_xreq *self, const struct nn_sockbase_vfptr *vfptr,
void *hint)
{
nn_sockbase_init (&self->sockbase, vfptr, hint);
nn_lb_init (&self->lb);
nn_fq_init (&self->fq);
}
void nn_xreq_term (struct nn_xreq *self)
{
nn_fq_term (&self->fq);
nn_lb_term (&self->lb);
nn_sockbase_term (&self->sockbase);
}
static void nn_xreq_destroy (struct nn_sockbase *self)
{
struct nn_xreq *xreq;
xreq = nn_cont (self, struct nn_xreq, sockbase);
nn_xreq_term (xreq);
nn_free (xreq);
}
int nn_xreq_add (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xreq *xreq;
struct nn_xreq_data *data;
int sndprio;
int rcvprio;
size_t sz;
xreq = nn_cont (self, struct nn_xreq, sockbase);
sz = sizeof (sndprio);
nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_SNDPRIO, &sndprio, &sz);
nn_assert (sz == sizeof (sndprio));
nn_assert (sndprio >= 1 && sndprio <= 16);
sz = sizeof (rcvprio);
nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, &sz);
nn_assert (sz == sizeof (rcvprio));
nn_assert (rcvprio >= 1 && rcvprio <= 16);
data = nn_alloc (sizeof (struct nn_xreq_data), "pipe data (req)");
alloc_assert (data);
nn_pipe_setdata (pipe, data);
nn_lb_add (&xreq->lb, &data->lb, pipe, sndprio);
nn_fq_add (&xreq->fq, &data->fq, pipe, rcvprio);
return 0;
}
void nn_xreq_rm (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xreq *xreq;
struct nn_xreq_data *data;
xreq = nn_cont (self, struct nn_xreq, sockbase);
data = nn_pipe_getdata (pipe);
nn_lb_rm (&xreq->lb, &data->lb);
nn_fq_rm (&xreq->fq, &data->fq);
nn_free (data);
nn_sockbase_stat_increment (self, NN_STAT_CURRENT_SND_PRIORITY,
nn_lb_get_priority (&xreq->lb));
}
void nn_xreq_in (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xreq *xreq;
struct nn_xreq_data *data;
xreq = nn_cont (self, struct nn_xreq, sockbase);
data = nn_pipe_getdata (pipe);
nn_fq_in (&xreq->fq, &data->fq);
}
void nn_xreq_out (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xreq *xreq;
struct nn_xreq_data *data;
xreq = nn_cont (self, struct nn_xreq, sockbase);
data = nn_pipe_getdata (pipe);
nn_lb_out (&xreq->lb, &data->lb);
nn_sockbase_stat_increment (self, NN_STAT_CURRENT_SND_PRIORITY,
nn_lb_get_priority (&xreq->lb));
}
int nn_xreq_events (struct nn_sockbase *self)
{
struct nn_xreq *xreq;
xreq = nn_cont (self, struct nn_xreq, sockbase);
return (nn_fq_can_recv (&xreq->fq) ? NN_SOCKBASE_EVENT_IN : 0) |
(nn_lb_can_send (&xreq->lb) ? NN_SOCKBASE_EVENT_OUT : 0);
}
int nn_xreq_send (struct nn_sockbase *self, struct nn_msg *msg)
{
return nn_xreq_send_to (self, msg, NULL);
}
int nn_xreq_send_to (struct nn_sockbase *self, struct nn_msg *msg,
struct nn_pipe **to)
{
int rc;
/* If request cannot be sent due to the pushback, drop it silenly. */
rc = nn_lb_send (&nn_cont (self, struct nn_xreq, sockbase)->lb, msg, to);
if (nn_slow (rc == -EAGAIN))
return -EAGAIN;
errnum_assert (rc >= 0, -rc);
return 0;
}
int nn_xreq_recv (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
rc = nn_fq_recv (&nn_cont (self, struct nn_xreq, sockbase)->fq, msg, NULL);
if (rc == -EAGAIN)
return -EAGAIN;
errnum_assert (rc >= 0, -rc);
if (!(rc & NN_PIPE_PARSED)) {
/* Ignore malformed replies. */
if (nn_slow (nn_chunkref_size (&msg->body) < sizeof (uint32_t))) {
nn_msg_term (msg);
return -EAGAIN;
}
/* Split the message into the header and the body. */
nn_assert (nn_chunkref_size (&msg->sphdr) == 0);
nn_chunkref_term (&msg->sphdr);
nn_chunkref_init (&msg->sphdr, sizeof (uint32_t));
memcpy (nn_chunkref_data (&msg->sphdr), nn_chunkref_data (&msg->body),
sizeof (uint32_t));
nn_chunkref_trim (&msg->body, sizeof (uint32_t));
}
return 0;
}
int nn_xreq_setopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED const void *optval, NN_UNUSED size_t optvallen)
{
return -ENOPROTOOPT;
}
int nn_xreq_getopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED void *optval, NN_UNUSED size_t *optvallen)
{
return -ENOPROTOOPT;
}
static int nn_xreq_create (void *hint, struct nn_sockbase **sockbase)
{
struct nn_xreq *self;
self = nn_alloc (sizeof (struct nn_xreq), "socket (xreq)");
alloc_assert (self);
nn_xreq_init (self, &nn_xreq_sockbase_vfptr, hint);
*sockbase = &self->sockbase;
return 0;
}
int nn_xreq_ispeer (int socktype)
{
return socktype == NN_REP ? 1 : 0;
}
static struct nn_socktype nn_xreq_socktype_struct = {
AF_SP_RAW,
NN_REQ,
0,
nn_xreq_create,
nn_xreq_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_xreq_socktype = &nn_xreq_socktype_struct;
nanomsg-0.8-beta/src/protocols/survey/0000775000175000017500000000000012623652617021022 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/protocols/survey/respondent.h0000664000175000017500000000243312623652600023346 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_RESPONDENT_INCLUDED
#define NN_RESPONDENT_INCLUDED
#include "../../protocol.h"
extern struct nn_socktype *nn_respondent_socktype;
#endif
nanomsg-0.8-beta/src/protocols/survey/respondent.c0000664000175000017500000001356412623652600023350 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Copyright 2015 Garrett D'Amore
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "respondent.h"
#include "xrespondent.h"
#include "../../nn.h"
#include "../../survey.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/alloc.h"
#include "../../utils/wire.h"
#include "../../utils/list.h"
#include "../../utils/int.h"
#include
#define NN_RESPONDENT_INPROGRESS 1
struct nn_respondent {
struct nn_xrespondent xrespondent;
uint32_t flags;
struct nn_chunkref backtrace;
};
/* Private functions. */
static void nn_respondent_init (struct nn_respondent *self,
const struct nn_sockbase_vfptr *vfptr, void *hint);
static void nn_respondent_term (struct nn_respondent *self);
/* Implementation of nn_sockbase's virtual functions. */
static void nn_respondent_destroy (struct nn_sockbase *self);
static int nn_respondent_events (struct nn_sockbase *self);
static int nn_respondent_send (struct nn_sockbase *self, struct nn_msg *msg);
static int nn_respondent_recv (struct nn_sockbase *self, struct nn_msg *msg);
static const struct nn_sockbase_vfptr nn_respondent_sockbase_vfptr = {
NULL,
nn_respondent_destroy,
nn_xrespondent_add,
nn_xrespondent_rm,
nn_xrespondent_in,
nn_xrespondent_out,
nn_respondent_events,
nn_respondent_send,
nn_respondent_recv,
nn_xrespondent_setopt,
nn_xrespondent_getopt
};
static void nn_respondent_init (struct nn_respondent *self,
const struct nn_sockbase_vfptr *vfptr, void *hint)
{
nn_xrespondent_init (&self->xrespondent, vfptr, hint);
self->flags = 0;
}
static void nn_respondent_term (struct nn_respondent *self)
{
if (self->flags & NN_RESPONDENT_INPROGRESS)
nn_chunkref_term (&self->backtrace);
nn_xrespondent_term (&self->xrespondent);
}
void nn_respondent_destroy (struct nn_sockbase *self)
{
struct nn_respondent *respondent;
respondent = nn_cont (self, struct nn_respondent, xrespondent.sockbase);
nn_respondent_term (respondent);
nn_free (respondent);
}
static int nn_respondent_events (struct nn_sockbase *self)
{
int events;
struct nn_respondent *respondent;
respondent = nn_cont (self, struct nn_respondent, xrespondent.sockbase);
events = nn_xrespondent_events (&respondent->xrespondent.sockbase);
if (!(respondent->flags & NN_RESPONDENT_INPROGRESS))
events &= ~NN_SOCKBASE_EVENT_OUT;
return events;
}
static int nn_respondent_send (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
struct nn_respondent *respondent;
respondent = nn_cont (self, struct nn_respondent, xrespondent.sockbase);
/* If there's no survey going on, report EFSM error. */
if (nn_slow (!(respondent->flags & NN_RESPONDENT_INPROGRESS)))
return -EFSM;
/* Tag the message with survey ID. */
nn_assert (nn_chunkref_size (&msg->sphdr) == 0);
nn_chunkref_term (&msg->sphdr);
nn_chunkref_mv (&msg->sphdr, &respondent->backtrace);
/* Remember that no survey is being processed. */
respondent->flags &= ~NN_RESPONDENT_INPROGRESS;
/* Try to send the message. If it cannot be sent due to pushback, drop it
silently. */
rc = nn_xrespondent_send (&respondent->xrespondent.sockbase, msg);
errnum_assert (rc == 0 || rc == -EAGAIN, -rc);
return 0;
}
static int nn_respondent_recv (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
struct nn_respondent *respondent;
respondent = nn_cont (self, struct nn_respondent, xrespondent.sockbase);
/* Cancel current survey and clean up backtrace, if it exists. */
if (nn_slow (respondent->flags & NN_RESPONDENT_INPROGRESS)) {
nn_chunkref_term (&respondent->backtrace);
respondent->flags &= ~NN_RESPONDENT_INPROGRESS;
}
/* Get next survey. */
rc = nn_xrespondent_recv (&respondent->xrespondent.sockbase, msg);
if (nn_slow (rc == -EAGAIN))
return -EAGAIN;
errnum_assert (rc == 0, -rc);
/* Store the backtrace. */
nn_chunkref_mv (&respondent->backtrace, &msg->sphdr);
nn_chunkref_init (&msg->sphdr, 0);
/* Remember that survey is being processed. */
respondent->flags |= NN_RESPONDENT_INPROGRESS;
return 0;
}
static int nn_respondent_create (void *hint, struct nn_sockbase **sockbase)
{
struct nn_respondent *self;
self = nn_alloc (sizeof (struct nn_respondent), "socket (respondent)");
alloc_assert (self);
nn_respondent_init (self, &nn_respondent_sockbase_vfptr, hint);
*sockbase = &self->xrespondent.sockbase;
return 0;
}
static struct nn_socktype nn_respondent_socktype_struct = {
AF_SP,
NN_RESPONDENT,
0,
nn_respondent_create,
nn_xrespondent_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_respondent_socktype = &nn_respondent_socktype_struct;
nanomsg-0.8-beta/src/protocols/survey/surveyor.h0000664000175000017500000000242612623652600023065 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_SURVEYOR_INCLUDED
#define NN_SURVEYOR_INCLUDED
#include "../../protocol.h"
extern struct nn_socktype *nn_surveyor_socktype;
#endif
nanomsg-0.8-beta/src/protocols/survey/surveyor.c0000664000175000017500000004134612623652600023064 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Copyright 2015 Garrett D'Amore
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "surveyor.h"
#include "xsurveyor.h"
#include "../../nn.h"
#include "../../survey.h"
#include "../../aio/fsm.h"
#include "../../aio/timer.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/wire.h"
#include "../../utils/alloc.h"
#include "../../utils/random.h"
#include "../../utils/list.h"
#include "../../utils/int.h"
#include "../../utils/attr.h"
#include
#define NN_SURVEYOR_DEFAULT_DEADLINE 1000
#define NN_SURVEYOR_STATE_IDLE 1
#define NN_SURVEYOR_STATE_PASSIVE 2
#define NN_SURVEYOR_STATE_ACTIVE 3
#define NN_SURVEYOR_STATE_CANCELLING 4
#define NN_SURVEYOR_STATE_STOPPING_TIMER 5
#define NN_SURVEYOR_STATE_STOPPING 6
#define NN_SURVEYOR_ACTION_START 1
#define NN_SURVEYOR_ACTION_CANCEL 2
#define NN_SURVEYOR_SRC_DEADLINE_TIMER 1
#define NN_SURVEYOR_TIMEDOUT 1
struct nn_surveyor {
/* The underlying raw SP socket. */
struct nn_xsurveyor xsurveyor;
/* The state machine. */
struct nn_fsm fsm;
int state;
/* Survey ID of the current survey. */
uint32_t surveyid;
/* Timer for timing out the survey. */
struct nn_timer timer;
/* When starting the survey, the message is temporarily stored here. */
struct nn_msg tosend;
/* Protocol-specific socket options. */
int deadline;
/* Flag if surveyor has timed out */
int timedout;
};
/* Private functions. */
static void nn_surveyor_init (struct nn_surveyor *self,
const struct nn_sockbase_vfptr *vfptr, void *hint);
static void nn_surveyor_term (struct nn_surveyor *self);
static void nn_surveyor_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_surveyor_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
static int nn_surveyor_inprogress (struct nn_surveyor *self);
static void nn_surveyor_resend (struct nn_surveyor *self);
/* Implementation of nn_sockbase's virtual functions. */
static void nn_surveyor_stop (struct nn_sockbase *self);
static void nn_surveyor_destroy (struct nn_sockbase *self);
static int nn_surveyor_events (struct nn_sockbase *self);
static int nn_surveyor_send (struct nn_sockbase *self, struct nn_msg *msg);
static int nn_surveyor_recv (struct nn_sockbase *self, struct nn_msg *msg);
static int nn_surveyor_setopt (struct nn_sockbase *self, int level, int option,
const void *optval, size_t optvallen);
static int nn_surveyor_getopt (struct nn_sockbase *self, int level, int option,
void *optval, size_t *optvallen);
static const struct nn_sockbase_vfptr nn_surveyor_sockbase_vfptr = {
nn_surveyor_stop,
nn_surveyor_destroy,
nn_xsurveyor_add,
nn_xsurveyor_rm,
nn_xsurveyor_in,
nn_xsurveyor_out,
nn_surveyor_events,
nn_surveyor_send,
nn_surveyor_recv,
nn_surveyor_setopt,
nn_surveyor_getopt
};
static void nn_surveyor_init (struct nn_surveyor *self,
const struct nn_sockbase_vfptr *vfptr, void *hint)
{
nn_xsurveyor_init (&self->xsurveyor, vfptr, hint);
nn_fsm_init_root (&self->fsm, nn_surveyor_handler, nn_surveyor_shutdown,
nn_sockbase_getctx (&self->xsurveyor.sockbase));
self->state = NN_SURVEYOR_STATE_IDLE;
/* Start assigning survey IDs beginning with a random number. This way
there should be no key clashes even if the executable is re-started. */
nn_random_generate (&self->surveyid, sizeof (self->surveyid));
nn_timer_init (&self->timer, NN_SURVEYOR_SRC_DEADLINE_TIMER, &self->fsm);
nn_msg_init (&self->tosend, 0);
self->deadline = NN_SURVEYOR_DEFAULT_DEADLINE;
self->timedout = 0;
/* Start the state machine. */
nn_fsm_start (&self->fsm);
}
static void nn_surveyor_term (struct nn_surveyor *self)
{
nn_msg_term (&self->tosend);
nn_timer_term (&self->timer);
nn_fsm_term (&self->fsm);
nn_xsurveyor_term (&self->xsurveyor);
}
void nn_surveyor_stop (struct nn_sockbase *self)
{
struct nn_surveyor *surveyor;
surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase);
nn_fsm_stop (&surveyor->fsm);
}
void nn_surveyor_destroy (struct nn_sockbase *self)
{
struct nn_surveyor *surveyor;
surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase);
nn_surveyor_term (surveyor);
nn_free (surveyor);
}
static int nn_surveyor_inprogress (struct nn_surveyor *self)
{
/* Return 1 if there's a survey going on. 0 otherwise. */
return self->state == NN_SURVEYOR_STATE_IDLE ||
self->state == NN_SURVEYOR_STATE_PASSIVE ||
self->state == NN_SURVEYOR_STATE_STOPPING ? 0 : 1;
}
static int nn_surveyor_events (struct nn_sockbase *self)
{
int rc;
struct nn_surveyor *surveyor;
surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase);
/* Determine the actual readability/writability of the socket. */
rc = nn_xsurveyor_events (&surveyor->xsurveyor.sockbase);
/* If there's no survey going on we'll signal IN to interrupt polling
when the survey expires. nn_recv() will return -EFSM afterwards. */
if (!nn_surveyor_inprogress (surveyor))
rc |= NN_SOCKBASE_EVENT_IN;
return rc;
}
static int nn_surveyor_send (struct nn_sockbase *self, struct nn_msg *msg)
{
struct nn_surveyor *surveyor;
surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase);
/* Generate new survey ID. */
++surveyor->surveyid;
surveyor->surveyid |= 0x80000000;
/* Tag the survey body with survey ID. */
nn_assert (nn_chunkref_size (&msg->sphdr) == 0);
nn_chunkref_term (&msg->sphdr);
nn_chunkref_init (&msg->sphdr, 4);
nn_putl (nn_chunkref_data (&msg->sphdr), surveyor->surveyid);
/* Store the survey, so that it can be sent later on. */
nn_msg_term (&surveyor->tosend);
nn_msg_mv (&surveyor->tosend, msg);
nn_msg_init (msg, 0);
/* Cancel any ongoing survey, if any. */
if (nn_slow (nn_surveyor_inprogress (surveyor))) {
/* First check whether the survey can be sent at all. */
if (!(nn_xsurveyor_events (&surveyor->xsurveyor.sockbase) &
NN_SOCKBASE_EVENT_OUT))
return -EAGAIN;
/* Cancel the current survey. */
nn_fsm_action (&surveyor->fsm, NN_SURVEYOR_ACTION_CANCEL);
return 0;
}
/* Notify the state machine that the survey was started. */
nn_fsm_action (&surveyor->fsm, NN_SURVEYOR_ACTION_START);
return 0;
}
static int nn_surveyor_recv (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
struct nn_surveyor *surveyor;
uint32_t surveyid;
surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase);
/* If no survey is going on return EFSM error. */
if (nn_slow (!nn_surveyor_inprogress (surveyor))) {
if (surveyor->timedout == NN_SURVEYOR_TIMEDOUT) {
surveyor->timedout = 0;
return -ETIMEDOUT;
} else
return -EFSM;
}
while (1) {
/* Get next response. */
rc = nn_xsurveyor_recv (&surveyor->xsurveyor.sockbase, msg);
if (nn_slow (rc == -EAGAIN))
return -EAGAIN;
errnum_assert (rc == 0, -rc);
/* Get the survey ID. Ignore any stale responses. */
/* TODO: This should be done asynchronously! */
if (nn_slow (nn_chunkref_size (&msg->sphdr) != sizeof (uint32_t)))
continue;
surveyid = nn_getl (nn_chunkref_data (&msg->sphdr));
if (nn_slow (surveyid != surveyor->surveyid))
continue;
/* Discard the header and return the message to the user. */
nn_chunkref_term (&msg->sphdr);
nn_chunkref_init (&msg->sphdr, 0);
break;
}
return 0;
}
static int nn_surveyor_setopt (struct nn_sockbase *self, int level, int option,
const void *optval, size_t optvallen)
{
struct nn_surveyor *surveyor;
surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase);
if (level != NN_SURVEYOR)
return -ENOPROTOOPT;
if (option == NN_SURVEYOR_DEADLINE) {
if (nn_slow (optvallen != sizeof (int)))
return -EINVAL;
surveyor->deadline = *(int*) optval;
return 0;
}
return -ENOPROTOOPT;
}
static int nn_surveyor_getopt (struct nn_sockbase *self, int level, int option,
void *optval, size_t *optvallen)
{
struct nn_surveyor *surveyor;
surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase);
if (level != NN_SURVEYOR)
return -ENOPROTOOPT;
if (option == NN_SURVEYOR_DEADLINE) {
if (nn_slow (*optvallen < sizeof (int)))
return -EINVAL;
*(int*) optval = surveyor->deadline;
*optvallen = sizeof (int);
return 0;
}
return -ENOPROTOOPT;
}
static void nn_surveyor_shutdown (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_surveyor *surveyor;
surveyor = nn_cont (self, struct nn_surveyor, fsm);
if (nn_slow (src== NN_FSM_ACTION && type == NN_FSM_STOP)) {
nn_timer_stop (&surveyor->timer);
surveyor->state = NN_SURVEYOR_STATE_STOPPING;
}
if (nn_slow (surveyor->state == NN_SURVEYOR_STATE_STOPPING)) {
if (!nn_timer_isidle (&surveyor->timer))
return;
surveyor->state = NN_SURVEYOR_STATE_IDLE;
nn_fsm_stopped_noevent (&surveyor->fsm);
nn_sockbase_stopped (&surveyor->xsurveyor.sockbase);
return;
}
nn_fsm_bad_state(surveyor->state, src, type);
}
static void nn_surveyor_handler (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_surveyor *surveyor;
surveyor = nn_cont (self, struct nn_surveyor, fsm);
switch (surveyor->state) {
/******************************************************************************/
/* IDLE state. */
/* The socket was created recently. */
/******************************************************************************/
case NN_SURVEYOR_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
surveyor->state = NN_SURVEYOR_STATE_PASSIVE;
return;
default:
nn_fsm_bad_action (surveyor->state, src, type);
}
default:
nn_fsm_bad_source (surveyor->state, src, type);
}
/******************************************************************************/
/* PASSIVE state. */
/* There's no survey going on. */
/******************************************************************************/
case NN_SURVEYOR_STATE_PASSIVE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_SURVEYOR_ACTION_START:
nn_surveyor_resend (surveyor);
nn_timer_start (&surveyor->timer, surveyor->deadline);
surveyor->state = NN_SURVEYOR_STATE_ACTIVE;
return;
default:
nn_fsm_bad_action (surveyor->state, src, type);
}
default:
nn_fsm_bad_source (surveyor->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/* Survey was sent, waiting for responses. */
/******************************************************************************/
case NN_SURVEYOR_STATE_ACTIVE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_SURVEYOR_ACTION_CANCEL:
nn_timer_stop (&surveyor->timer);
surveyor->state = NN_SURVEYOR_STATE_CANCELLING;
return;
default:
nn_fsm_bad_action (surveyor->state, src, type);
}
case NN_SURVEYOR_SRC_DEADLINE_TIMER:
switch (type) {
case NN_TIMER_TIMEOUT:
nn_timer_stop (&surveyor->timer);
surveyor->state = NN_SURVEYOR_STATE_STOPPING_TIMER;
surveyor->timedout = NN_SURVEYOR_TIMEDOUT;
return;
default:
nn_fsm_bad_action (surveyor->state, src, type);
}
default:
nn_fsm_bad_source (surveyor->state, src, type);
}
/******************************************************************************/
/* CANCELLING state. */
/* Survey was cancelled, but the old timer haven't stopped yet. The new */
/* survey thus haven't been sent and is stored in 'tosend'. */
/******************************************************************************/
case NN_SURVEYOR_STATE_CANCELLING:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_SURVEYOR_ACTION_CANCEL:
return;
default:
nn_fsm_bad_action (surveyor->state, src, type);
}
case NN_SURVEYOR_SRC_DEADLINE_TIMER:
switch (type) {
case NN_TIMER_STOPPED:
nn_surveyor_resend (surveyor);
nn_timer_start (&surveyor->timer, surveyor->deadline);
surveyor->state = NN_SURVEYOR_STATE_ACTIVE;
return;
default:
nn_fsm_bad_action (surveyor->state, src, type);
}
default:
nn_fsm_bad_source (surveyor->state, src, type);
}
/******************************************************************************/
/* STOPPING_TIMER state. */
/* Survey timeout expired. Now we are stopping the timer. */
/******************************************************************************/
case NN_SURVEYOR_STATE_STOPPING_TIMER:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_SURVEYOR_ACTION_CANCEL:
surveyor->state = NN_SURVEYOR_STATE_CANCELLING;
return;
default:
nn_fsm_bad_action (surveyor->state, src, type);
}
case NN_SURVEYOR_SRC_DEADLINE_TIMER:
switch (type) {
case NN_TIMER_STOPPED:
surveyor->state = NN_SURVEYOR_STATE_PASSIVE;
return;
default:
nn_fsm_bad_action (surveyor->state, src, type);
}
default:
nn_fsm_bad_source (surveyor->state, src, type);
}
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (surveyor->state, src, type);
}
}
static void nn_surveyor_resend (struct nn_surveyor *self)
{
int rc;
struct nn_msg msg;
nn_msg_cp (&msg, &self->tosend);
rc = nn_xsurveyor_send (&self->xsurveyor.sockbase, &msg);
errnum_assert (rc == 0, -rc);
}
static int nn_surveyor_create (void *hint, struct nn_sockbase **sockbase)
{
struct nn_surveyor *self;
self = nn_alloc (sizeof (struct nn_surveyor), "socket (surveyor)");
alloc_assert (self);
nn_surveyor_init (self, &nn_surveyor_sockbase_vfptr, hint);
*sockbase = &self->xsurveyor.sockbase;
return 0;
}
static struct nn_socktype nn_surveyor_socktype_struct = {
AF_SP,
NN_SURVEYOR,
0,
nn_surveyor_create,
nn_xsurveyor_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_surveyor_socktype = &nn_surveyor_socktype_struct;
nanomsg-0.8-beta/src/protocols/survey/xrespondent.h0000664000175000017500000000545512623652600023545 0ustar00travistravis00000000000000/*
Copyright (c) 201-2013 Martin Sustrik All rights reserved.
Copyright 2015 Garrett D'Amore
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_XRESPONDENT_INCLUDED
#define NN_XRESPONDENT_INCLUDED
#include "../../protocol.h"
#include "../../utils/hash.h"
#include "../../utils/int.h"
#include "../utils/fq.h"
extern struct nn_socktype *nn_xrespondent_socktype;
#define NN_XRESPONDENT_OUT 1
struct nn_xrespondent_data {
struct nn_pipe *pipe;
struct nn_hash_item outitem;
struct nn_fq_data initem;
uint32_t flags;
};
struct nn_xrespondent {
struct nn_sockbase sockbase;
/* Key to be assigned to the next added pipe. */
uint32_t next_key;
/* Map of all registered pipes indexed by the peer ID. */
struct nn_hash outpipes;
/* Fair-queuer to get surveys from. */
struct nn_fq inpipes;
};
void nn_xrespondent_init (struct nn_xrespondent *self,
const struct nn_sockbase_vfptr *vfptr, void *hint);
void nn_xrespondent_term (struct nn_xrespondent *self);
int nn_xrespondent_add (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_xrespondent_rm (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_xrespondent_in (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_xrespondent_out (struct nn_sockbase *self, struct nn_pipe *pipe);
int nn_xrespondent_events (struct nn_sockbase *self);
int nn_xrespondent_send (struct nn_sockbase *self, struct nn_msg *msg);
int nn_xrespondent_recv (struct nn_sockbase *self, struct nn_msg *msg);
int nn_xrespondent_setopt (struct nn_sockbase *self, int level, int option,
const void *optval, size_t optvallen);
int nn_xrespondent_getopt (struct nn_sockbase *self, int level, int option,
void *optval, size_t *optvallen);
int nn_xrespondent_ispeer (int socktype);
#endif
nanomsg-0.8-beta/src/protocols/survey/xrespondent.c0000664000175000017500000002145512623652600023536 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Copyright 2015 Garrett D'Amore
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "xrespondent.h"
#include "../../nn.h"
#include "../../survey.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/alloc.h"
#include "../../utils/random.h"
#include "../../utils/wire.h"
#include "../../utils/list.h"
#include "../../utils/attr.h"
/* Private functions. */
static void nn_xrespondent_destroy (struct nn_sockbase *self);
/* Implementation of nn_sockbase's virtual functions. */
static const struct nn_sockbase_vfptr nn_xrespondent_sockbase_vfptr = {
NULL,
nn_xrespondent_destroy,
nn_xrespondent_add,
nn_xrespondent_rm,
nn_xrespondent_in,
nn_xrespondent_out,
nn_xrespondent_events,
nn_xrespondent_send,
nn_xrespondent_recv,
nn_xrespondent_setopt,
nn_xrespondent_getopt
};
void nn_xrespondent_init (struct nn_xrespondent *self,
const struct nn_sockbase_vfptr *vfptr, void *hint)
{
nn_sockbase_init (&self->sockbase, vfptr, hint);
/* Pipes IDs should be random. See RFC for info. */
nn_random_generate (&self->next_key, sizeof (self->next_key));
nn_hash_init (&self->outpipes);
nn_fq_init (&self->inpipes);
}
void nn_xrespondent_term (struct nn_xrespondent *self)
{
nn_fq_term (&self->inpipes);
nn_hash_term (&self->outpipes);
nn_sockbase_term (&self->sockbase);
}
static void nn_xrespondent_destroy (struct nn_sockbase *self)
{
struct nn_xrespondent *xrespondent;
xrespondent = nn_cont (self, struct nn_xrespondent, sockbase);
nn_xrespondent_term (xrespondent);
nn_free (xrespondent);
}
int nn_xrespondent_add (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xrespondent *xrespondent;
struct nn_xrespondent_data *data;
int rcvprio;
size_t sz;
xrespondent = nn_cont (self, struct nn_xrespondent, sockbase);
sz = sizeof (rcvprio);
nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, &sz);
nn_assert (sz == sizeof (rcvprio));
nn_assert (rcvprio >= 1 && rcvprio <= 16);
data = nn_alloc (sizeof (*data), "pipe data (xrespondent)");
alloc_assert (data);
data->pipe = pipe;
nn_hash_item_init (&data->outitem);
data->flags = 0;
nn_hash_insert (&xrespondent->outpipes, xrespondent->next_key & 0x7fffffff,
&data->outitem);
xrespondent->next_key++;
nn_fq_add (&xrespondent->inpipes, &data->initem, pipe, rcvprio);
nn_pipe_setdata (pipe, data);
return 0;
}
void nn_xrespondent_rm (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xrespondent *xrespondent;
struct nn_xrespondent_data *data;
xrespondent = nn_cont (self, struct nn_xrespondent, sockbase);
data = nn_pipe_getdata (pipe);
nn_fq_rm (&xrespondent->inpipes, &data->initem);
nn_hash_erase (&xrespondent->outpipes, &data->outitem);
nn_hash_item_term (&data->outitem);
nn_free (data);
}
void nn_xrespondent_in (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xrespondent *xrespondent;
struct nn_xrespondent_data *data;
xrespondent = nn_cont (self, struct nn_xrespondent, sockbase);
data = nn_pipe_getdata (pipe);
nn_fq_in (&xrespondent->inpipes, &data->initem);
}
void nn_xrespondent_out (NN_UNUSED struct nn_sockbase *self,
struct nn_pipe *pipe)
{
struct nn_xrespondent_data *data;
data = nn_pipe_getdata (pipe);
data->flags |= NN_XRESPONDENT_OUT;
}
int nn_xrespondent_events (struct nn_sockbase *self)
{
return (nn_fq_can_recv (&nn_cont (self, struct nn_xrespondent,
sockbase)->inpipes) ? NN_SOCKBASE_EVENT_IN : 0) | NN_SOCKBASE_EVENT_OUT;
}
int nn_xrespondent_send (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
uint32_t key;
struct nn_xrespondent *xrespondent;
struct nn_xrespondent_data *data;
xrespondent = nn_cont (self, struct nn_xrespondent, sockbase);
/* We treat invalid peer ID as if the peer was non-existent. */
if (nn_slow (nn_chunkref_size (&msg->sphdr) < sizeof (uint32_t))) {
nn_msg_term (msg);
return 0;
}
/* Retrieve destination peer ID. Trim it from the header. */
key = nn_getl (nn_chunkref_data (&msg->sphdr));
nn_chunkref_trim (&msg->sphdr, 4);
/* Find the appropriate pipe to send the message to. If there's none,
or if it's not ready for sending, silently drop the message. */
data = nn_cont (nn_hash_get (&xrespondent->outpipes, key),
struct nn_xrespondent_data, outitem);
if (!data || !(data->flags & NN_XRESPONDENT_OUT)) {
nn_msg_term (msg);
return 0;
}
/* Send the message. */
rc = nn_pipe_send (data->pipe, msg);
errnum_assert (rc >= 0, -rc);
if (rc & NN_PIPE_RELEASE)
data->flags &= ~NN_XRESPONDENT_OUT;
return 0;
}
int nn_xrespondent_recv (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
struct nn_xrespondent *xrespondent;
struct nn_pipe *pipe;
int i;
size_t sz;
void *data;
struct nn_chunkref ref;
struct nn_xrespondent_data *pipedata;
xrespondent = nn_cont (self, struct nn_xrespondent, sockbase);
rc = nn_fq_recv (&xrespondent->inpipes, msg, &pipe);
if (nn_slow (rc < 0))
return rc;
/* Split the header (including survey ID) from the body, if needed. */
if (!(rc & NN_PIPE_PARSED)) {
/* Determine the size of the message header. */
data = nn_chunkref_data (&msg->body);
sz = nn_chunkref_size (&msg->body);
i = 0;
while (1) {
/* Ignore the malformed surveys without the bottom of the stack. */
if (nn_slow ((i + 1) * sizeof (uint32_t) > sz)) {
nn_msg_term (msg);
return -EAGAIN;
}
/* If the bottom of the backtrace stack is reached, proceed. */
if (nn_getl ((uint8_t*)(((uint32_t*) data) + i)) & 0x80000000)
break;
++i;
}
++i;
nn_assert (nn_chunkref_size (&msg->sphdr) == 0);
nn_chunkref_term (&msg->sphdr);
nn_chunkref_init (&msg->sphdr, i * sizeof (uint32_t));
memcpy (nn_chunkref_data (&msg->sphdr), data, i * sizeof (uint32_t));
nn_chunkref_trim (&msg->body, i * sizeof (uint32_t));
}
/* Prepend the header by the pipe key. */
pipedata = nn_pipe_getdata (pipe);
nn_chunkref_init (&ref, nn_chunkref_size (&msg->sphdr) + sizeof (uint32_t));
nn_putl (nn_chunkref_data (&ref), pipedata->outitem.key);
memcpy (((uint8_t *) nn_chunkref_data (&ref)) + sizeof (uint32_t),
nn_chunkref_data (&msg->sphdr), nn_chunkref_size (&msg->sphdr));
nn_chunkref_term (&msg->sphdr);
nn_chunkref_mv (&msg->sphdr, &ref);
return 0;
}
int nn_xrespondent_setopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED const void *optval, NN_UNUSED size_t optvallen)
{
return -ENOPROTOOPT;
}
int nn_xrespondent_getopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED void *optval, NN_UNUSED size_t *optvallen)
{
return -ENOPROTOOPT;
}
static int nn_xrespondent_create (void *hint, struct nn_sockbase **sockbase)
{
struct nn_xrespondent *self;
self = nn_alloc (sizeof (struct nn_xrespondent), "socket (xrespondent)");
alloc_assert (self);
nn_xrespondent_init (self, &nn_xrespondent_sockbase_vfptr, hint);
*sockbase = &self->sockbase;
return 0;
}
int nn_xrespondent_ispeer (int socktype)
{
return socktype == NN_SURVEYOR ? 1 : 0;
}
static struct nn_socktype nn_xrespondent_socktype_struct = {
AF_SP_RAW,
NN_RESPONDENT,
0,
nn_xrespondent_create,
nn_xrespondent_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_xrespondent_socktype = &nn_xrespondent_socktype_struct;
nanomsg-0.8-beta/src/protocols/survey/xsurveyor.h0000664000175000017500000000510612623652600023253 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_XSURVEYOR_INCLUDED
#define NN_XSURVEYOR_INCLUDED
#include "../../protocol.h"
#include "../utils/dist.h"
#include "../utils/fq.h"
extern struct nn_socktype *nn_xsurveyor_socktype;
struct nn_xsurveyor_data {
struct nn_pipe *pipe;
struct nn_dist_data outitem;
struct nn_fq_data initem;
};
struct nn_xsurveyor {
/* The generic socket base class. */
struct nn_sockbase sockbase;
/* Distributor to send messages. */
struct nn_dist outpipes;
/* Fair-queuer to receive messages. */
struct nn_fq inpipes;
};
void nn_xsurveyor_init (struct nn_xsurveyor *self,
const struct nn_sockbase_vfptr *vfptr, void *hint);
void nn_xsurveyor_term (struct nn_xsurveyor *self);
int nn_xsurveyor_add (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_xsurveyor_rm (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_xsurveyor_in (struct nn_sockbase *self, struct nn_pipe *pipe);
void nn_xsurveyor_out (struct nn_sockbase *self, struct nn_pipe *pipe);
int nn_xsurveyor_events (struct nn_sockbase *self);
int nn_xsurveyor_send (struct nn_sockbase *self, struct nn_msg *msg);
int nn_xsurveyor_recv (struct nn_sockbase *self, struct nn_msg *msg);
int nn_xsurveyor_setopt (struct nn_sockbase *self, int level, int option,
const void *optval, size_t optvallen);
int nn_xsurveyor_getopt (struct nn_sockbase *self, int level, int option,
void *optval, size_t *optvallen);
int nn_xsurveyor_ispeer (int socktype);
#endif
nanomsg-0.8-beta/src/protocols/survey/xsurveyor.c0000664000175000017500000001504212623652600023246 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "xsurveyor.h"
#include "../../nn.h"
#include "../../survey.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/list.h"
#include "../../utils/alloc.h"
#include "../../utils/list.h"
#include "../../utils/attr.h"
#include
/* Private functions. */
static void nn_xsurveyor_destroy (struct nn_sockbase *self);
/* Implementation of nn_sockbase's virtual functions. */
static const struct nn_sockbase_vfptr nn_xsurveyor_sockbase_vfptr = {
NULL,
nn_xsurveyor_destroy,
nn_xsurveyor_add,
nn_xsurveyor_rm,
nn_xsurveyor_in,
nn_xsurveyor_out,
nn_xsurveyor_events,
nn_xsurveyor_send,
nn_xsurveyor_recv,
nn_xsurveyor_setopt,
nn_xsurveyor_getopt
};
void nn_xsurveyor_init (struct nn_xsurveyor *self,
const struct nn_sockbase_vfptr *vfptr, void *hint)
{
nn_sockbase_init (&self->sockbase, vfptr, hint);
nn_dist_init (&self->outpipes);
nn_fq_init (&self->inpipes);
}
void nn_xsurveyor_term (struct nn_xsurveyor *self)
{
nn_fq_term (&self->inpipes);
nn_dist_term (&self->outpipes);
nn_sockbase_term (&self->sockbase);
}
static void nn_xsurveyor_destroy (struct nn_sockbase *self)
{
struct nn_xsurveyor *xsurveyor;
xsurveyor = nn_cont (self, struct nn_xsurveyor, sockbase);
nn_xsurveyor_term (xsurveyor);
nn_free (xsurveyor);
}
int nn_xsurveyor_add (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xsurveyor *xsurveyor;
struct nn_xsurveyor_data *data;
int rcvprio;
size_t sz;
xsurveyor = nn_cont (self, struct nn_xsurveyor, sockbase);
sz = sizeof (rcvprio);
nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, &sz);
nn_assert (sz == sizeof (rcvprio));
nn_assert (rcvprio >= 1 && rcvprio <= 16);
data = nn_alloc (sizeof (struct nn_xsurveyor_data),
"pipe data (xsurveyor)");
alloc_assert (data);
data->pipe = pipe;
nn_fq_add (&xsurveyor->inpipes, &data->initem, pipe, rcvprio);
nn_dist_add (&xsurveyor->outpipes, &data->outitem, pipe);
nn_pipe_setdata (pipe, data);
return 0;
}
void nn_xsurveyor_rm (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xsurveyor *xsurveyor;
struct nn_xsurveyor_data *data;
xsurveyor = nn_cont (self, struct nn_xsurveyor, sockbase);
data = nn_pipe_getdata (pipe);
nn_fq_rm (&xsurveyor->inpipes, &data->initem);
nn_dist_rm (&xsurveyor->outpipes, &data->outitem);
nn_free (data);
}
void nn_xsurveyor_in (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xsurveyor *xsurveyor;
struct nn_xsurveyor_data *data;
xsurveyor = nn_cont (self, struct nn_xsurveyor, sockbase);
data = nn_pipe_getdata (pipe);
nn_fq_in (&xsurveyor->inpipes, &data->initem);
}
void nn_xsurveyor_out (struct nn_sockbase *self, struct nn_pipe *pipe)
{
struct nn_xsurveyor *xsurveyor;
struct nn_xsurveyor_data *data;
xsurveyor = nn_cont (self, struct nn_xsurveyor, sockbase);
data = nn_pipe_getdata (pipe);
nn_dist_out (&xsurveyor->outpipes, &data->outitem);
}
int nn_xsurveyor_events (struct nn_sockbase *self)
{
struct nn_xsurveyor *xsurveyor;
int events;
xsurveyor = nn_cont (self, struct nn_xsurveyor, sockbase);
events = NN_SOCKBASE_EVENT_OUT;
if (nn_fq_can_recv (&xsurveyor->inpipes))
events |= NN_SOCKBASE_EVENT_IN;
return events;
}
int nn_xsurveyor_send (struct nn_sockbase *self, struct nn_msg *msg)
{
return nn_dist_send (
&nn_cont (self, struct nn_xsurveyor, sockbase)->outpipes, msg, NULL);
}
int nn_xsurveyor_recv (struct nn_sockbase *self, struct nn_msg *msg)
{
int rc;
struct nn_xsurveyor *xsurveyor;
xsurveyor = nn_cont (self, struct nn_xsurveyor, sockbase);
rc = nn_fq_recv (&xsurveyor->inpipes, msg, NULL);
if (nn_slow (rc < 0))
return rc;
/* Split the header from the body, if needed. */
if (!(rc & NN_PIPE_PARSED)) {
if (nn_slow (nn_chunkref_size (&msg->body) < sizeof (uint32_t))) {
nn_msg_term (msg);
return -EAGAIN;
}
nn_assert (nn_chunkref_size (&msg->sphdr) == 0);
nn_chunkref_term (&msg->sphdr);
nn_chunkref_init (&msg->sphdr, sizeof (uint32_t));
memcpy (nn_chunkref_data (&msg->sphdr), nn_chunkref_data (&msg->body),
sizeof (uint32_t));
nn_chunkref_trim (&msg->body, sizeof (uint32_t));
}
return 0;
}
int nn_xsurveyor_setopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED const void *optval, NN_UNUSED size_t optvallen)
{
return -ENOPROTOOPT;
}
int nn_xsurveyor_getopt (NN_UNUSED struct nn_sockbase *self,
NN_UNUSED int level, NN_UNUSED int option,
NN_UNUSED void *optval, NN_UNUSED size_t *optvallen)
{
return -ENOPROTOOPT;
}
static int nn_xsurveyor_create (void *hint, struct nn_sockbase **sockbase)
{
struct nn_xsurveyor *self;
self = nn_alloc (sizeof (struct nn_xsurveyor), "socket (xsurveyor)");
alloc_assert (self);
nn_xsurveyor_init (self, &nn_xsurveyor_sockbase_vfptr, hint);
*sockbase = &self->sockbase;
return 0;
}
int nn_xsurveyor_ispeer (int socktype)
{
return socktype == NN_RESPONDENT ? 1 : 0;
}
static struct nn_socktype nn_xsurveyor_socktype_struct = {
AF_SP_RAW,
NN_SURVEYOR,
0,
nn_xsurveyor_create,
nn_xsurveyor_ispeer,
NN_LIST_ITEM_INITIALIZER
};
struct nn_socktype *nn_xsurveyor_socktype = &nn_xsurveyor_socktype_struct;
nanomsg-0.8-beta/src/protocols/utils/0000775000175000017500000000000012623652617020625 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/protocols/utils/dist.h0000664000175000017500000000377712623652600021747 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_DIST_INCLUDED
#define NN_DIST_INCLUDED
#include "../../protocol.h"
#include "../../utils/list.h"
/* Distributor. Sends messages to all the pipes. */
struct nn_dist_data {
struct nn_list_item item;
struct nn_pipe *pipe;
};
struct nn_dist {
uint32_t count;
struct nn_list pipes;
};
void nn_dist_init (struct nn_dist *self);
void nn_dist_term (struct nn_dist *self);
void nn_dist_add (struct nn_dist *self,
struct nn_dist_data *data, struct nn_pipe *pipe);
void nn_dist_rm (struct nn_dist *self, struct nn_dist_data *data);
void nn_dist_out (struct nn_dist *self, struct nn_dist_data *data);
/* Sends the message to all the attached pipes except the one specified
by 'exclude' parameter. If 'exclude' is NULL, message is sent to all
attached pipes. */
int nn_dist_send (struct nn_dist *self, struct nn_msg *msg,
struct nn_pipe *exclude);
#endif
nanomsg-0.8-beta/src/protocols/utils/dist.c0000664000175000017500000000645612623652600021737 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "dist.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/attr.h"
#include
void nn_dist_init (struct nn_dist *self)
{
self->count = 0;
nn_list_init (&self->pipes);
}
void nn_dist_term (struct nn_dist *self)
{
nn_assert (self->count == 0);
nn_list_term (&self->pipes);
}
void nn_dist_add (NN_UNUSED struct nn_dist *self,
struct nn_dist_data *data, struct nn_pipe *pipe)
{
data->pipe = pipe;
nn_list_item_init (&data->item);
}
void nn_dist_rm (struct nn_dist *self, struct nn_dist_data *data)
{
if (nn_list_item_isinlist (&data->item)) {
--self->count;
nn_list_erase (&self->pipes, &data->item);
}
nn_list_item_term (&data->item);
}
void nn_dist_out (struct nn_dist *self, struct nn_dist_data *data)
{
++self->count;
nn_list_insert (&self->pipes, &data->item, nn_list_end (&self->pipes));
}
int nn_dist_send (struct nn_dist *self, struct nn_msg *msg,
struct nn_pipe *exclude)
{
int rc;
struct nn_list_item *it;
struct nn_dist_data *data;
struct nn_msg copy;
/* TODO: We can optimise for the case when there's only one outbound
pipe here. No message copying is needed in such case. */
/* In the specific case when there are no outbound pipes. There's nowhere
to send the message to. Deallocate it. */
if (nn_slow (self->count) == 0) {
nn_msg_term (msg);
return 0;
}
/* Send the message to all the subscribers. */
nn_msg_bulkcopy_start (msg, self->count);
it = nn_list_begin (&self->pipes);
while (it != nn_list_end (&self->pipes)) {
data = nn_cont (it, struct nn_dist_data, item);
nn_msg_bulkcopy_cp (©, msg);
if (nn_fast (data->pipe == exclude)) {
nn_msg_term (©);
}
else {
rc = nn_pipe_send (data->pipe, ©);
errnum_assert (rc >= 0, -rc);
if (rc & NN_PIPE_RELEASE) {
--self->count;
it = nn_list_erase (&self->pipes, it);
continue;
}
}
it = nn_list_next (&self->pipes, it);
}
nn_msg_term (msg);
return 0;
}
nanomsg-0.8-beta/src/protocols/utils/excl.h0000664000175000017500000000446012623652600021725 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_EXCL_INCLUDED
#define NN_EXCL_INCLUDED
#include "../../protocol.h"
#include
/* This is an object to handle a single pipe. To be used by socket types that
can work with precisely one connection, e.g. PAIR. */
struct nn_excl {
/* The pipe being used at the moment. All other pipes will be rejected
until this one terminates. NULL if there is no connected pipe. */
struct nn_pipe *pipe;
/* Pipe ready for receiving. It's either equal to 'pipe' or NULL. */
struct nn_pipe *inpipe;
/* Pipe ready for sending. It's either equal to 'pipe' or NULL. */
struct nn_pipe *outpipe;
};
void nn_excl_init (struct nn_excl *self);
void nn_excl_term (struct nn_excl *self);
int nn_excl_add (struct nn_excl *self, struct nn_pipe *pipe);
void nn_excl_rm (struct nn_excl *self, struct nn_pipe *pipe);
void nn_excl_in (struct nn_excl *self, struct nn_pipe *pipe);
void nn_excl_out (struct nn_excl *self, struct nn_pipe *pipe);
int nn_excl_send (struct nn_excl *self, struct nn_msg *msg);
int nn_excl_recv (struct nn_excl *self, struct nn_msg *msg);
int nn_excl_can_send (struct nn_excl *self);
int nn_excl_can_recv (struct nn_excl *self);
#endif
nanomsg-0.8-beta/src/protocols/utils/excl.c0000664000175000017500000000600612623652600021716 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "excl.h"
#include "../../utils/fast.h"
#include "../../utils/err.h"
#include "../../utils/attr.h"
void nn_excl_init (struct nn_excl *self)
{
self->pipe = NULL;
self->inpipe = NULL;
self->outpipe = NULL;
}
void nn_excl_term (struct nn_excl *self)
{
nn_assert (!self->pipe);
nn_assert (!self->inpipe);
nn_assert (!self->outpipe);
}
int nn_excl_add (struct nn_excl *self, struct nn_pipe *pipe)
{
/* If there's a connection being used, reject any new connection. */
if (self->pipe)
return -EISCONN;
/* Remember that this pipe is the active one. */
self->pipe = pipe;
return 0;
}
void nn_excl_rm (struct nn_excl *self, NN_UNUSED struct nn_pipe *pipe)
{
nn_assert (self->pipe);
self->pipe = NULL;
self->inpipe = NULL;
self->outpipe = NULL;
}
void nn_excl_in (struct nn_excl *self, struct nn_pipe *pipe)
{
nn_assert (!self->inpipe);
nn_assert (pipe == self->pipe);
self->inpipe = pipe;
}
void nn_excl_out (struct nn_excl *self, struct nn_pipe *pipe)
{
nn_assert (!self->outpipe);
nn_assert (pipe == self->pipe);
self->outpipe = pipe;
}
int nn_excl_send (struct nn_excl *self, struct nn_msg *msg)
{
int rc;
if (nn_slow (!self->outpipe))
return -EAGAIN;
rc = nn_pipe_send (self->outpipe, msg);
errnum_assert (rc >= 0, -rc);
if (rc & NN_PIPE_RELEASE)
self->outpipe = NULL;
return rc & ~NN_PIPE_RELEASE;
}
int nn_excl_recv (struct nn_excl *self, struct nn_msg *msg)
{
int rc;
if (nn_slow (!self->inpipe))
return -EAGAIN;
rc = nn_pipe_recv (self->inpipe, msg);
errnum_assert (rc >= 0, -rc);
if (rc & NN_PIPE_RELEASE)
self->inpipe = NULL;
return rc & ~NN_PIPE_RELEASE;
}
int nn_excl_can_send (struct nn_excl *self)
{
return self->outpipe ? 1 : 0;
}
int nn_excl_can_recv (struct nn_excl *self)
{
return self->inpipe ? 1 : 0;
}
nanomsg-0.8-beta/src/protocols/utils/fq.h0000664000175000017500000000353012623652600021375 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_FQ_INCLUDED
#define NN_FQ_INCLUDED
#include "../../protocol.h"
#include "priolist.h"
/* Fair-queuer. Retrieves messages from a set of pipes in round-robin
manner. */
struct nn_fq_data {
struct nn_priolist_data priodata;
};
struct nn_fq {
struct nn_priolist priolist;
};
void nn_fq_init (struct nn_fq *self);
void nn_fq_term (struct nn_fq *self);
void nn_fq_add (struct nn_fq *self, struct nn_fq_data *data,
struct nn_pipe *pipe, int priority);
void nn_fq_rm (struct nn_fq *self, struct nn_fq_data *data);
void nn_fq_in (struct nn_fq *self, struct nn_fq_data *data);
int nn_fq_can_recv (struct nn_fq *self);
int nn_fq_recv (struct nn_fq *self, struct nn_msg *msg, struct nn_pipe **pipe);
#endif
nanomsg-0.8-beta/src/protocols/utils/fq.c0000664000175000017500000000475212623652600021377 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "fq.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include
void nn_fq_init (struct nn_fq *self)
{
nn_priolist_init (&self->priolist);
}
void nn_fq_term (struct nn_fq *self)
{
nn_priolist_term (&self->priolist);
}
void nn_fq_add (struct nn_fq *self, struct nn_fq_data *data,
struct nn_pipe *pipe, int priority)
{
nn_priolist_add (&self->priolist, &data->priodata, pipe, priority);
}
void nn_fq_rm (struct nn_fq *self, struct nn_fq_data *data)
{
nn_priolist_rm (&self->priolist, &data->priodata);
}
void nn_fq_in (struct nn_fq *self, struct nn_fq_data *data)
{
nn_priolist_activate (&self->priolist, &data->priodata);
}
int nn_fq_can_recv (struct nn_fq *self)
{
return nn_priolist_is_active (&self->priolist);
}
int nn_fq_recv (struct nn_fq *self, struct nn_msg *msg, struct nn_pipe **pipe)
{
int rc;
struct nn_pipe *p;
/* Pipe is NULL only when there are no avialable pipes. */
p = nn_priolist_getpipe (&self->priolist);
if (nn_slow (!p))
return -EAGAIN;
/* Receive the messsage. */
rc = nn_pipe_recv (p, msg);
errnum_assert (rc >= 0, -rc);
/* Return the pipe data to the user, if required. */
if (pipe)
*pipe = p;
/* Move to the next pipe. */
nn_priolist_advance (&self->priolist, rc & NN_PIPE_RELEASE);
return rc & ~NN_PIPE_RELEASE;
}
nanomsg-0.8-beta/src/protocols/utils/lb.h0000664000175000017500000000355712623652600021375 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_LB_INCLUDED
#define NN_LB_INCLUDED
#include "../../protocol.h"
#include "priolist.h"
/* A load balancer. Round-robins messages to a set of pipes. */
struct nn_lb_data {
struct nn_priolist_data priodata;
};
struct nn_lb {
struct nn_priolist priolist;
};
void nn_lb_init (struct nn_lb *self);
void nn_lb_term (struct nn_lb *self);
void nn_lb_add (struct nn_lb *self, struct nn_lb_data *data,
struct nn_pipe *pipe, int priority);
void nn_lb_rm (struct nn_lb *self, struct nn_lb_data *data);
void nn_lb_out (struct nn_lb *self, struct nn_lb_data *data);
int nn_lb_can_send (struct nn_lb *self);
int nn_lb_get_priority (struct nn_lb *self);
int nn_lb_send (struct nn_lb *self, struct nn_msg *msg, struct nn_pipe **to);
#endif
nanomsg-0.8-beta/src/protocols/utils/lb.c0000664000175000017500000000504712623652600021364 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "lb.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include
void nn_lb_init (struct nn_lb *self)
{
nn_priolist_init (&self->priolist);
}
void nn_lb_term (struct nn_lb *self)
{
nn_priolist_term (&self->priolist);
}
void nn_lb_add (struct nn_lb *self, struct nn_lb_data *data,
struct nn_pipe *pipe, int priority)
{
nn_priolist_add (&self->priolist, &data->priodata, pipe, priority);
}
void nn_lb_rm (struct nn_lb *self, struct nn_lb_data *data)
{
nn_priolist_rm (&self->priolist, &data->priodata);
}
void nn_lb_out (struct nn_lb *self, struct nn_lb_data *data)
{
nn_priolist_activate (&self->priolist, &data->priodata);
}
int nn_lb_can_send (struct nn_lb *self)
{
return nn_priolist_is_active (&self->priolist);
}
int nn_lb_get_priority (struct nn_lb *self)
{
return nn_priolist_get_priority (&self->priolist);
}
int nn_lb_send (struct nn_lb *self, struct nn_msg *msg, struct nn_pipe **to)
{
int rc;
struct nn_pipe *pipe;
/* Pipe is NULL only when there are no avialable pipes. */
pipe = nn_priolist_getpipe (&self->priolist);
if (nn_slow (!pipe))
return -EAGAIN;
/* Send the messsage. */
rc = nn_pipe_send (pipe, msg);
errnum_assert (rc >= 0, -rc);
/* Move to the next pipe. */
nn_priolist_advance (&self->priolist, rc & NN_PIPE_RELEASE);
if (to != NULL)
*to = pipe;
return rc & ~NN_PIPE_RELEASE;
}
nanomsg-0.8-beta/src/protocols/utils/priolist.h0000664000175000017500000000731712623652600022643 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_PRIOLIST_INCLUDED
#define NN_PRIOLIST_INCLUDED
#include "../../protocol.h"
#include "../../utils/list.h"
/* Prioritised list of pipes. */
#define NN_PRIOLIST_SLOTS 16
struct nn_priolist_data {
/* The underlying pipe itself. */
struct nn_pipe *pipe;
/* Priority the pipe is assigned. Using this value we can find the
nn_priolist_slot object that owns this pipe. */
int priority;
/* The structure is a member in nn_priolist_slot's 'pipes' list. */
struct nn_list_item item;
};
struct nn_priolist_slot {
/* The list of pipes on particular priority level. */
struct nn_list pipes;
/* Pointer to the current pipe within the priority level. If there's no
pipe available, the field is set to NULL. */
struct nn_priolist_data *current;
};
struct nn_priolist {
/* Each slot holds pipes for a particular priority level. */
struct nn_priolist_slot slots [NN_PRIOLIST_SLOTS];
/* The index of the slot holding the current pipe. It should be the
highest-priority non-empty slot available. If there's no available
pipe, this field is set to -1. */
int current;
};
/* Initialise the list. */
void nn_priolist_init (struct nn_priolist *self);
/* Terminate the list. The list must be empty before it's terminated. */
void nn_priolist_term (struct nn_priolist *self);
/* Add a new pipe to the list with a particular priority level. The pipe
is not active at this point. Use nn_priolist_activate to activate it. */
void nn_priolist_add (struct nn_priolist *self, struct nn_priolist_data *data,
struct nn_pipe *pipe, int priority);
/* Remove the pipe from the list. */
void nn_priolist_rm (struct nn_priolist *self, struct nn_priolist_data *data);
/* Activates a non-active pipe. The pipe must be added to the list prior to
calling this function. */
void nn_priolist_activate (struct nn_priolist *self, struct nn_priolist_data *data);
/* Returns 1 if there's at least a single active pipe in the list,
0 otherwise. */
int nn_priolist_is_active (struct nn_priolist *self);
/* Get the pointer to the current pipe. If there's no pipe in the list,
NULL is returned. */
struct nn_pipe *nn_priolist_getpipe (struct nn_priolist *self);
/* Moves to the next pipe in the list. If 'release' is set to 1, the current
pipe is removed from the list. To re-insert it into the list use
nn_priolist_activate function. */
void nn_priolist_advance (struct nn_priolist *self, int release);
/* Returns current priority. Used for statistics only */
int nn_priolist_get_priority (struct nn_priolist *self);
#endif
nanomsg-0.8-beta/src/protocols/utils/priolist.c0000664000175000017500000001305412623652600022631 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "priolist.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/err.h"
#include "../../utils/attr.h"
#include
void nn_priolist_init (struct nn_priolist *self)
{
int i;
for (i = 0; i != NN_PRIOLIST_SLOTS; ++i) {
nn_list_init (&self->slots [i].pipes);
self->slots [i].current = NULL;
}
self->current = -1;
}
void nn_priolist_term (struct nn_priolist *self)
{
int i;
for (i = 0; i != NN_PRIOLIST_SLOTS; ++i)
nn_list_term (&self->slots [i].pipes);
}
void nn_priolist_add (NN_UNUSED struct nn_priolist *self,
struct nn_priolist_data *data, struct nn_pipe *pipe, int priority)
{
data->pipe = pipe;
data->priority = priority;
nn_list_item_init (&data->item);
}
void nn_priolist_rm (struct nn_priolist *self, struct nn_priolist_data *data)
{
struct nn_priolist_slot *slot;
struct nn_list_item *it;
/* Non-active pipes don't need any special processing. */
if (!nn_list_item_isinlist (&data->item)) {
nn_list_item_term (&data->item);
return;
}
/* If the pipe being removed is not current, we can simply erase it
from the list. */
slot = &self->slots [data->priority - 1];
if (slot->current != data) {
nn_list_erase (&slot->pipes, &data->item);
nn_list_item_term (&data->item);
return;
}
/* Advance the current pointer (with wrap-over). */
it = nn_list_erase (&slot->pipes, &data->item);
slot->current = nn_cont (it, struct nn_priolist_data, item);
nn_list_item_term (&data->item);
if (!slot->current) {
it = nn_list_begin (&slot->pipes);
slot->current = nn_cont (it, struct nn_priolist_data, item);
}
/* If we are not messing with the current slot, we are done. */
if (self->current != data->priority)
return;
/* Otherwise, the current slot may have become empty and we have switch
to lower priority slots. */
while (nn_list_empty (&self->slots [self->current - 1].pipes)) {
++self->current;
if (self->current > NN_PRIOLIST_SLOTS) {
self->current = -1;
return;
}
}
}
void nn_priolist_activate (struct nn_priolist *self,
struct nn_priolist_data *data)
{
struct nn_priolist_slot *slot;
slot = &self->slots [data->priority - 1];
/* If there are already some elements in this slot, current pipe is not
going to change. */
if (!nn_list_empty (&slot->pipes)) {
nn_list_insert (&slot->pipes, &data->item, nn_list_end (&slot->pipes));
return;
}
/* Add first pipe into the slot. If there are no pipes in priolist at all
this slot becomes current. */
nn_list_insert (&slot->pipes, &data->item, nn_list_end (&slot->pipes));
slot->current = data;
if (self->current == -1) {
self->current = data->priority;
return;
}
/* If the current priority is lower than the one of the newly activated
pipe, this slot becomes current. */
if (self->current > data->priority) {
self->current = data->priority;
return;
}
/* Current doesn't change otherwise. */
}
int nn_priolist_is_active (struct nn_priolist *self)
{
return self->current == -1 ? 0 : 1;
}
struct nn_pipe *nn_priolist_getpipe (struct nn_priolist *self)
{
if (nn_slow (self->current == -1))
return NULL;
return self->slots [self->current - 1].current->pipe;
}
void nn_priolist_advance (struct nn_priolist *self, int release)
{
struct nn_priolist_slot *slot;
struct nn_list_item *it;
nn_assert (self->current > 0);
slot = &self->slots [self->current - 1];
/* Move slot's current pointer to the next pipe. */
if (release)
it = nn_list_erase (&slot->pipes, &slot->current->item);
else
it = nn_list_next (&slot->pipes, &slot->current->item);
if (!it)
it = nn_list_begin (&slot->pipes);
slot->current = nn_cont (it, struct nn_priolist_data, item);
/* If there are no more pipes in this slot, find a non-empty slot with
lower priority. */
while (nn_list_empty (&slot->pipes)) {
++self->current;
if (self->current > NN_PRIOLIST_SLOTS) {
self->current = -1;
return;
}
slot = &self->slots [self->current - 1];
}
}
int nn_priolist_get_priority (struct nn_priolist *self) {
return self->current;
}
nanomsg-0.8-beta/src/transports/0000775000175000017500000000000012623652617017660 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/transports/inproc/0000775000175000017500000000000012623652617021152 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/transports/inproc/binproc.h0000664000175000017500000000321312623652600022746 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_BINPROC_INCLUDED
#define NN_BINPROC_INCLUDED
#include "ins.h"
#include "../../transport.h"
#include "../../aio/fsm.h"
#include "../../utils/list.h"
struct nn_cinproc;
struct nn_binproc {
/* The state machine. */
struct nn_fsm fsm;
int state;
/* This object is registered with nn_ins. */
struct nn_ins_item item;
/* The list of inproc sessions owned by this object. */
struct nn_list sinprocs;
};
int nn_binproc_create (void *hint, struct nn_epbase **epbase);
#endif
nanomsg-0.8-beta/src/transports/inproc/binproc.c0000664000175000017500000002025512623652600022746 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "binproc.h"
#include "sinproc.h"
#include "cinproc.h"
#include "ins.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/alloc.h"
#define NN_BINPROC_STATE_IDLE 1
#define NN_BINPROC_STATE_ACTIVE 2
#define NN_BINPROC_STATE_STOPPING 3
#define NN_BINPROC_SRC_SINPROC 1
/* Implementation of nn_epbase interface. */
static void nn_binproc_stop (struct nn_epbase *self);
static void nn_binproc_destroy (struct nn_epbase *self);
static const struct nn_epbase_vfptr nn_binproc_vfptr = {
nn_binproc_stop,
nn_binproc_destroy
};
/* Private functions. */
static void nn_binproc_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_binproc_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_binproc_connect (struct nn_ins_item *self,
struct nn_ins_item *peer);
int nn_binproc_create (void *hint, struct nn_epbase **epbase)
{
int rc;
struct nn_binproc *self;
self = nn_alloc (sizeof (struct nn_binproc), "binproc");
alloc_assert (self);
nn_ins_item_init (&self->item, &nn_binproc_vfptr, hint);
nn_fsm_init_root (&self->fsm, nn_binproc_handler, nn_binproc_shutdown,
nn_epbase_getctx (&self->item.epbase));
self->state = NN_BINPROC_STATE_IDLE;
nn_list_init (&self->sinprocs);
/* Start the state machine. */
nn_fsm_start (&self->fsm);
/* Register the inproc endpoint into a global repository. */
rc = nn_ins_bind (&self->item, nn_binproc_connect);
if (nn_slow (rc < 0)) {
nn_list_term (&self->sinprocs);
/* TODO: Now, this is ugly! We are getting the state machine into
the idle state manually. How should it be done correctly? */
self->fsm.state = 1;
nn_fsm_term (&self->fsm);
nn_ins_item_term (&self->item);
nn_free (self);
return rc;
}
*epbase = &self->item.epbase;
return 0;
}
static void nn_binproc_stop (struct nn_epbase *self)
{
struct nn_binproc *binproc;
binproc = nn_cont (self, struct nn_binproc, item.epbase);
nn_fsm_stop (&binproc->fsm);
}
static void nn_binproc_destroy (struct nn_epbase *self)
{
struct nn_binproc *binproc;
binproc = nn_cont (self, struct nn_binproc, item.epbase);
nn_list_term (&binproc->sinprocs);
nn_fsm_term (&binproc->fsm);
nn_ins_item_term (&binproc->item);
nn_free (binproc);
}
static void nn_binproc_connect (struct nn_ins_item *self,
struct nn_ins_item *peer)
{
struct nn_binproc *binproc;
struct nn_cinproc *cinproc;
struct nn_sinproc *sinproc;
binproc = nn_cont (self, struct nn_binproc, item);
cinproc = nn_cont (peer, struct nn_cinproc, item);
nn_assert_state (binproc, NN_BINPROC_STATE_ACTIVE);
sinproc = nn_alloc (sizeof (struct nn_sinproc), "sinproc");
alloc_assert (sinproc);
nn_sinproc_init (sinproc, NN_BINPROC_SRC_SINPROC,
&binproc->item.epbase, &binproc->fsm);
nn_list_insert (&binproc->sinprocs, &sinproc->item,
nn_list_end (&binproc->sinprocs));
nn_sinproc_connect (sinproc, &cinproc->fsm);
nn_epbase_stat_increment (&binproc->item.epbase,
NN_STAT_ACCEPTED_CONNECTIONS, 1);
}
static void nn_binproc_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr)
{
struct nn_binproc *binproc;
struct nn_list_item *it;
struct nn_sinproc *sinproc;
binproc = nn_cont (self, struct nn_binproc, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
/* First, unregister the endpoint from the global repository of inproc
endpoints. This way, new connections cannot be created anymore. */
nn_ins_unbind (&binproc->item);
/* Stop the existing connections. */
for (it = nn_list_begin (&binproc->sinprocs);
it != nn_list_end (&binproc->sinprocs);
it = nn_list_next (&binproc->sinprocs, it)) {
sinproc = nn_cont (it, struct nn_sinproc, item);
nn_sinproc_stop (sinproc);
}
binproc->state = NN_BINPROC_STATE_STOPPING;
goto finish;
}
if (nn_slow (binproc->state == NN_BINPROC_STATE_STOPPING)) {
nn_assert (src == NN_BINPROC_SRC_SINPROC && type == NN_SINPROC_STOPPED);
sinproc = (struct nn_sinproc*) srcptr;
nn_list_erase (&binproc->sinprocs, &sinproc->item);
nn_sinproc_term (sinproc);
nn_free (sinproc);
finish:
if (!nn_list_empty (&binproc->sinprocs))
return;
binproc->state = NN_BINPROC_STATE_IDLE;
nn_fsm_stopped_noevent (&binproc->fsm);
nn_epbase_stopped (&binproc->item.epbase);
return;
}
nn_fsm_bad_state(binproc->state, src, type);
}
static void nn_binproc_handler (struct nn_fsm *self, int src, int type,
void *srcptr)
{
struct nn_binproc *binproc;
struct nn_sinproc *peer;
struct nn_sinproc *sinproc;
binproc = nn_cont (self, struct nn_binproc, fsm);
switch (binproc->state) {
/******************************************************************************/
/* IDLE state. */
/******************************************************************************/
case NN_BINPROC_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
binproc->state = NN_BINPROC_STATE_ACTIVE;
return;
default:
nn_fsm_bad_action (binproc->state, src, type);
}
default:
nn_fsm_bad_source (binproc->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/******************************************************************************/
case NN_BINPROC_STATE_ACTIVE:
switch (src) {
case NN_SINPROC_SRC_PEER:
switch (type) {
case NN_SINPROC_CONNECT:
peer = (struct nn_sinproc*) srcptr;
sinproc = nn_alloc (sizeof (struct nn_sinproc), "sinproc");
alloc_assert (sinproc);
nn_sinproc_init (sinproc, NN_BINPROC_SRC_SINPROC,
&binproc->item.epbase, &binproc->fsm);
nn_list_insert (&binproc->sinprocs, &sinproc->item,
nn_list_end (&binproc->sinprocs));
nn_sinproc_accept (sinproc, peer);
return;
default:
nn_fsm_bad_action (binproc->state, src, type);
}
case NN_BINPROC_SRC_SINPROC:
return;
default:
nn_fsm_bad_source (binproc->state, src, type);
}
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (binproc->state, src, type);
}
}
nanomsg-0.8-beta/src/transports/inproc/cinproc.h0000664000175000017500000000313112623652600022746 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_CINPROC_INCLUDED
#define NN_CINPROC_INCLUDED
#include "ins.h"
#include "sinproc.h"
#include "../../transport.h"
#include "../../aio/fsm.h"
struct nn_cinproc {
/* The state machine. */
struct nn_fsm fsm;
int state;
/* This object is registered with nn_ins. */
struct nn_ins_item item;
/* The actual inproc session. */
struct nn_sinproc sinproc;
};
int nn_cinproc_create (void *hint, struct nn_epbase **epbase);
#endif
nanomsg-0.8-beta/src/transports/inproc/cinproc.c0000664000175000017500000002076512623652600022755 0ustar00travistravis00000000000000 /*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "cinproc.h"
#include "binproc.h"
#include "ins.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/alloc.h"
#include "../../utils/attr.h"
#include
#define NN_CINPROC_STATE_IDLE 1
#define NN_CINPROC_STATE_DISCONNECTED 2
#define NN_CINPROC_STATE_ACTIVE 3
#define NN_CINPROC_STATE_STOPPING 4
#define NN_CINPROC_ACTION_CONNECT 1
#define NN_CINPROC_SRC_SINPROC 1
/* Implementation of nn_epbase callback interface. */
static void nn_cinproc_stop (struct nn_epbase *self);
static void nn_cinproc_destroy (struct nn_epbase *self);
static const struct nn_epbase_vfptr nn_cinproc_vfptr = {
nn_cinproc_stop,
nn_cinproc_destroy
};
/* Private functions. */
static void nn_cinproc_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_cinproc_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_cinproc_connect (struct nn_ins_item *self,
struct nn_ins_item *peer);
int nn_cinproc_create (void *hint, struct nn_epbase **epbase)
{
struct nn_cinproc *self;
self = nn_alloc (sizeof (struct nn_cinproc), "cinproc");
alloc_assert (self);
nn_ins_item_init (&self->item, &nn_cinproc_vfptr, hint);
nn_fsm_init_root (&self->fsm, nn_cinproc_handler, nn_cinproc_shutdown,
nn_epbase_getctx (&self->item.epbase));
self->state = NN_CINPROC_STATE_IDLE;
nn_sinproc_init (&self->sinproc, NN_CINPROC_SRC_SINPROC,
&self->item.epbase, &self->fsm);
/* Start the state machine. */
nn_fsm_start (&self->fsm);
/* Register the inproc endpoint into a global repository. */
nn_ins_connect (&self->item, nn_cinproc_connect);
*epbase = &self->item.epbase;
return 0;
}
static void nn_cinproc_stop (struct nn_epbase *self)
{
struct nn_cinproc *cinproc;
cinproc = nn_cont (self, struct nn_cinproc, item.epbase);
nn_fsm_stop (&cinproc->fsm);
}
static void nn_cinproc_destroy (struct nn_epbase *self)
{
struct nn_cinproc *cinproc;
cinproc = nn_cont (self, struct nn_cinproc, item.epbase);
nn_sinproc_term (&cinproc->sinproc);
nn_fsm_term (&cinproc->fsm);
nn_ins_item_term (&cinproc->item);
nn_free (cinproc);
}
static void nn_cinproc_connect (struct nn_ins_item *self,
struct nn_ins_item *peer)
{
struct nn_cinproc *cinproc;
struct nn_binproc *binproc;
cinproc = nn_cont (self, struct nn_cinproc, item);
binproc = nn_cont (peer, struct nn_binproc, item);
nn_assert_state (cinproc, NN_CINPROC_STATE_DISCONNECTED);
nn_sinproc_connect (&cinproc->sinproc, &binproc->fsm);
nn_fsm_action (&cinproc->fsm, NN_CINPROC_ACTION_CONNECT);
}
static void nn_cinproc_shutdown (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_cinproc *cinproc;
cinproc = nn_cont (self, struct nn_cinproc, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
/* First, unregister the endpoint from the global repository of inproc
endpoints. This way, new connections cannot be created anymore. */
nn_ins_disconnect (&cinproc->item);
/* Stop the existing connection. */
nn_sinproc_stop (&cinproc->sinproc);
cinproc->state = NN_CINPROC_STATE_STOPPING;
}
if (nn_slow (cinproc->state == NN_CINPROC_STATE_STOPPING)) {
if (!nn_sinproc_isidle (&cinproc->sinproc))
return;
cinproc->state = NN_CINPROC_STATE_IDLE;
nn_fsm_stopped_noevent (&cinproc->fsm);
nn_epbase_stopped (&cinproc->item.epbase);
return;
}
nn_fsm_bad_state(cinproc->state, src, type);
}
static void nn_cinproc_handler (struct nn_fsm *self, int src, int type,
void *srcptr)
{
struct nn_cinproc *cinproc;
struct nn_sinproc *sinproc;
cinproc = nn_cont (self, struct nn_cinproc, fsm);
switch (cinproc->state) {
/******************************************************************************/
/* IDLE state. */
/******************************************************************************/
case NN_CINPROC_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
cinproc->state = NN_CINPROC_STATE_DISCONNECTED;
nn_epbase_stat_increment (&cinproc->item.epbase,
NN_STAT_INPROGRESS_CONNECTIONS, 1);
return;
default:
nn_fsm_bad_action (cinproc->state, src, type);
}
default:
nn_fsm_bad_source (cinproc->state, src, type);
}
/******************************************************************************/
/* DISCONNECTED state. */
/******************************************************************************/
case NN_CINPROC_STATE_DISCONNECTED:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_CINPROC_ACTION_CONNECT:
cinproc->state = NN_CINPROC_STATE_ACTIVE;
nn_epbase_stat_increment (&cinproc->item.epbase,
NN_STAT_INPROGRESS_CONNECTIONS, -1);
nn_epbase_stat_increment (&cinproc->item.epbase,
NN_STAT_ESTABLISHED_CONNECTIONS, 1);
return;
default:
nn_fsm_bad_action (cinproc->state, src, type);
}
case NN_SINPROC_SRC_PEER:
sinproc = (struct nn_sinproc*) srcptr;
switch (type) {
case NN_SINPROC_CONNECT:
nn_sinproc_accept (&cinproc->sinproc, sinproc);
cinproc->state = NN_CINPROC_STATE_ACTIVE;
nn_epbase_stat_increment (&cinproc->item.epbase,
NN_STAT_INPROGRESS_CONNECTIONS, -1);
nn_epbase_stat_increment (&cinproc->item.epbase,
NN_STAT_ESTABLISHED_CONNECTIONS, 1);
return;
default:
nn_fsm_bad_action (cinproc->state, src, type);
}
default:
nn_fsm_bad_source (cinproc->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/******************************************************************************/
case NN_CINPROC_STATE_ACTIVE:
switch (src) {
case NN_CINPROC_SRC_SINPROC:
switch (type) {
case NN_SINPROC_DISCONNECT:
cinproc->state = NN_CINPROC_STATE_DISCONNECTED;
nn_epbase_stat_increment (&cinproc->item.epbase,
NN_STAT_INPROGRESS_CONNECTIONS, 1);
nn_sinproc_init (&cinproc->sinproc, NN_CINPROC_SRC_SINPROC,
&cinproc->item.epbase, &cinproc->fsm);
return;
default:
nn_fsm_bad_action (cinproc->state, src, type);
}
default:
nn_fsm_bad_source (cinproc->state, src, type);
}
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (cinproc->state, src, type);
}
}
nanomsg-0.8-beta/src/transports/inproc/inproc.h0000664000175000017500000000240312623652600022604 0ustar00travistravis00000000000000/*
Copyright (c) 2012 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_INPROC_INCLUDED
#define NN_INPROC_INCLUDED
#include "../../transport.h"
extern struct nn_transport *nn_inproc;
#endif
nanomsg-0.8-beta/src/transports/inproc/inproc.c0000664000175000017500000000421712623652600022604 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "inproc.h"
#include "ins.h"
#include "binproc.h"
#include "cinproc.h"
#include "../../inproc.h"
#include
/* nn_transport interface. */
static void nn_inproc_init (void);
static void nn_inproc_term (void);
static int nn_inproc_bind (void *hint, struct nn_epbase **epbase);
static int nn_inproc_connect (void *hint, struct nn_epbase **epbase);
static struct nn_transport nn_inproc_vfptr = {
"inproc",
NN_INPROC,
nn_inproc_init,
nn_inproc_term,
nn_inproc_bind,
nn_inproc_connect,
NULL,
NN_LIST_ITEM_INITIALIZER
};
struct nn_transport *nn_inproc = &nn_inproc_vfptr;
static void nn_inproc_init (void)
{
nn_ins_init ();
}
static void nn_inproc_term (void)
{
nn_ins_term ();
}
static int nn_inproc_bind (void *hint, struct nn_epbase **epbase)
{
return nn_binproc_create (hint, epbase);
}
static int nn_inproc_connect (void *hint, struct nn_epbase **epbase)
{
return nn_cinproc_create (hint, epbase);
}
nanomsg-0.8-beta/src/transports/inproc/ins.h0000664000175000017500000000425012623652600022105 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_INS_INCLUDED
#define NN_INS_INCLUDED
#include "../../transport.h"
#include "../../utils/list.h"
/* Inproc naming system. A global repository of inproc endpoints. */
struct nn_ins_item {
/* Every ins_item is an endpoint. */
struct nn_epbase epbase;
/* Every ins_item is either in the list of bound or connected endpoints. */
struct nn_list_item item;
/* This is the local cache of the endpoint's protocol ID. This way we can
check the value without actually locking the object. */
int protocol;
};
void nn_ins_item_init (struct nn_ins_item *self,
const struct nn_epbase_vfptr *vfptr, void *hint);
void nn_ins_item_term (struct nn_ins_item *self);
void nn_ins_init (void);
void nn_ins_term (void);
typedef void (*nn_ins_fn) (struct nn_ins_item *self, struct nn_ins_item *peer);
int nn_ins_bind (struct nn_ins_item *item, nn_ins_fn fn);
void nn_ins_connect (struct nn_ins_item *item, nn_ins_fn fn);
void nn_ins_disconnect (struct nn_ins_item *item);
void nn_ins_unbind (struct nn_ins_item *item);
#endif
nanomsg-0.8-beta/src/transports/inproc/ins.c0000664000175000017500000001263112623652600022102 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "ins.h"
#include "../../utils/mutex.h"
#include "../../utils/alloc.h"
#include "../../utils/list.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/err.h"
struct nn_ins {
/* Synchronises access to this object. */
struct nn_mutex sync;
/* List of all bound inproc endpoints. */
/* TODO: O(n) lookup, shouldn't we do better? Hash? */
struct nn_list bound;
/* List of all connected inproc endpoints. */
/* TODO: O(n) lookup, shouldn't we do better? Hash? */
struct nn_list connected;
};
/* Global instance of the nn_ins object. It contains the lists of all
inproc endpoints in the current process. */
static struct nn_ins self;
void nn_ins_item_init (struct nn_ins_item *self,
const struct nn_epbase_vfptr *vfptr, void *hint)
{
size_t sz;
nn_epbase_init (&self->epbase, vfptr, hint);
nn_list_item_init (&self->item);
sz = sizeof (self->protocol);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_PROTOCOL,
&self->protocol, &sz);
nn_assert (sz == sizeof (self->protocol));
}
void nn_ins_item_term (struct nn_ins_item *self)
{
nn_list_item_term (&self->item);
nn_epbase_term (&self->epbase);
}
void nn_ins_init (void)
{
nn_mutex_init (&self.sync);
nn_list_init (&self.bound);
nn_list_init (&self.connected);
}
void nn_ins_term (void)
{
nn_list_term (&self.connected);
nn_list_term (&self.bound);
nn_mutex_term (&self.sync);
}
int nn_ins_bind (struct nn_ins_item *item, nn_ins_fn fn)
{
struct nn_list_item *it;
struct nn_ins_item *bitem;
struct nn_ins_item *citem;
nn_mutex_lock (&self.sync);
/* Check whether the endpoint isn't already bound. */
/* TODO: This is an O(n) algorithm! */
for (it = nn_list_begin (&self.bound); it != nn_list_end (&self.bound);
it = nn_list_next (&self.bound, it)) {
bitem = nn_cont (it, struct nn_ins_item, item);
if (strncmp (nn_epbase_getaddr (&item->epbase),
nn_epbase_getaddr (&bitem->epbase), NN_SOCKADDR_MAX) == 0) {
nn_mutex_unlock (&self.sync);
return -EADDRINUSE;
}
}
/* Insert the entry into the endpoint repository. */
nn_list_insert (&self.bound, &item->item,
nn_list_end (&self.bound));
/* During this process new pipes may be created. */
for (it = nn_list_begin (&self.connected);
it != nn_list_end (&self.connected);
it = nn_list_next (&self.connected, it)) {
citem = nn_cont (it, struct nn_ins_item, item);
if (strncmp (nn_epbase_getaddr (&item->epbase),
nn_epbase_getaddr (&citem->epbase), NN_SOCKADDR_MAX) == 0) {
/* Check whether the two sockets are compatible. */
if (!nn_epbase_ispeer (&item->epbase, citem->protocol))
continue;
fn (item, citem);
}
}
nn_mutex_unlock (&self.sync);
return 0;
}
void nn_ins_connect (struct nn_ins_item *item, nn_ins_fn fn)
{
struct nn_list_item *it;
struct nn_ins_item *bitem;
nn_mutex_lock (&self.sync);
/* Insert the entry into the endpoint repository. */
nn_list_insert (&self.connected, &item->item,
nn_list_end (&self.connected));
/* During this process a pipe may be created. */
for (it = nn_list_begin (&self.bound);
it != nn_list_end (&self.bound);
it = nn_list_next (&self.bound, it)) {
bitem = nn_cont (it, struct nn_ins_item, item);
if (strncmp (nn_epbase_getaddr (&item->epbase),
nn_epbase_getaddr (&bitem->epbase), NN_SOCKADDR_MAX) == 0) {
/* Check whether the two sockets are compatible. */
if (!nn_epbase_ispeer (&item->epbase, bitem->protocol))
break;
/* Call back to cinproc to create actual connection. */
fn (item, bitem);
break;
}
}
nn_mutex_unlock (&self.sync);
}
void nn_ins_disconnect (struct nn_ins_item *item)
{
nn_mutex_lock (&self.sync);
nn_list_erase (&self.connected, &item->item);
nn_mutex_unlock (&self.sync);
}
void nn_ins_unbind (struct nn_ins_item *item)
{
nn_mutex_lock (&self.sync);
nn_list_erase (&self.bound, &item->item);
nn_mutex_unlock (&self.sync);
}
nanomsg-0.8-beta/src/transports/inproc/msgqueue.h0000664000175000017500000000572012623652600023152 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_MSGQUEUE_INCLUDED
#define NN_MSGQUEUE_INCLUDED
#include "../../utils/msg.h"
#include
/* This class is a simple uni-directional message queue. */
/* It's not 128 so that chunk including its footer fits into a memory page. */
#define NN_MSGQUEUE_GRANULARITY 126
struct nn_msgqueue_chunk {
struct nn_msg msgs [NN_MSGQUEUE_GRANULARITY];
struct nn_msgqueue_chunk *next;
};
struct nn_msgqueue {
/* Pointer to the position where next message should be written into
the message queue. */
struct {
struct nn_msgqueue_chunk *chunk;
int pos;
} out;
/* Pointer to the first unread message in the message queue. */
struct {
struct nn_msgqueue_chunk *chunk;
int pos;
} in;
/* Number of messages in the queue. */
size_t count;
/* Amount of memory used by messages in the queue. */
size_t mem;
/* Maximal queue size (in bytes). */
size_t maxmem;
/* One empty chunk is always cached so that in case of steady stream
of messages through the pipe there are no memory allocations. */
struct nn_msgqueue_chunk *cache;
};
/* Initialise the message pipe. maxmem is the maximal queue size in bytes. */
void nn_msgqueue_init (struct nn_msgqueue *self, size_t maxmem);
/* Terminate the message pipe. */
void nn_msgqueue_term (struct nn_msgqueue *self);
/* Returns 1 if there are no messages in the queue, 0 otherwise. */
int nn_msgqueue_empty (struct nn_msgqueue *self);
/* Writes a message to the pipe. -EAGAIN is returned if the message cannot
be sent because the queue is full. */
int nn_msgqueue_send (struct nn_msgqueue *self, struct nn_msg *msg);
/* Reads a message from the pipe. -EAGAIN is returned if there's no message
to receive. */
int nn_msgqueue_recv (struct nn_msgqueue *self, struct nn_msg *msg);
#endif
nanomsg-0.8-beta/src/transports/inproc/msgqueue.c0000664000175000017500000001071012623652600023140 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "msgqueue.h"
#include "../../utils/alloc.h"
#include "../../utils/fast.h"
#include "../../utils/err.h"
#include
void nn_msgqueue_init (struct nn_msgqueue *self, size_t maxmem)
{
struct nn_msgqueue_chunk *chunk;
self->count = 0;
self->mem = 0;
self->maxmem = maxmem;
chunk = nn_alloc (sizeof (struct nn_msgqueue_chunk), "msgqueue chunk");
alloc_assert (chunk);
chunk->next = NULL;
self->out.chunk = chunk;
self->out.pos = 0;
self->in.chunk = chunk;
self->in.pos = 0;
self->cache = NULL;
}
void nn_msgqueue_term (struct nn_msgqueue *self)
{
int rc;
struct nn_msg msg;
/* Deallocate messages in the pipe. */
while (1) {
rc = nn_msgqueue_recv (self, &msg);
if (rc == -EAGAIN)
break;
errnum_assert (rc >= 0, -rc);
nn_msg_term (&msg);
}
/* There are no more messages in the pipe so there's at most one chunk
in the queue. Deallocate it. */
nn_assert (self->in.chunk == self->out.chunk);
nn_free (self->in.chunk);
/* Deallocate the cached chunk, if any. */
if (self->cache)
nn_free (self->cache);
}
int nn_msgqueue_empty (struct nn_msgqueue *self)
{
return self->count == 0 ? 1 : 0;
}
int nn_msgqueue_send (struct nn_msgqueue *self, struct nn_msg *msg)
{
size_t msgsz;
/* By allowing one message of arbitrary size to be written to the queue,
we allow even messages that exceed max buffer size to pass through.
Beyond that we'll apply the buffer limit as specified by the user. */
msgsz = nn_chunkref_size (&msg->sphdr) + nn_chunkref_size (&msg->body);
if (nn_slow (self->count > 0 && self->mem + msgsz >= self->maxmem))
return -EAGAIN;
/* Adjust the statistics. */
++self->count;
self->mem += msgsz;
/* Move the content of the message to the pipe. */
nn_msg_mv (&self->out.chunk->msgs [self->out.pos], msg);
++self->out.pos;
/* If there's no space for a new message in the pipe, either re-use
the cache chunk or allocate a new chunk if it does not exist. */
if (nn_slow (self->out.pos == NN_MSGQUEUE_GRANULARITY)) {
if (nn_slow (!self->cache)) {
self->cache = nn_alloc (sizeof (struct nn_msgqueue_chunk),
"msgqueue chunk");
alloc_assert (self->cache);
self->cache->next = NULL;
}
self->out.chunk->next = self->cache;
self->out.chunk = self->cache;
self->cache = NULL;
self->out.pos = 0;
}
return 0;
}
int nn_msgqueue_recv (struct nn_msgqueue *self, struct nn_msg *msg)
{
struct nn_msgqueue_chunk *o;
/* If there is no message in the queue. */
if (nn_slow (!self->count))
return -EAGAIN;
/* Move the message from the pipe to the user. */
nn_msg_mv (msg, &self->in.chunk->msgs [self->in.pos]);
/* Move to the next position. */
++self->in.pos;
if (nn_slow (self->in.pos == NN_MSGQUEUE_GRANULARITY)) {
o = self->in.chunk;
self->in.chunk = self->in.chunk->next;
self->in.pos = 0;
if (nn_fast (!self->cache))
self->cache = o;
else
nn_free (o);
}
/* Adjust the statistics. */
--self->count;
self->mem -= (nn_chunkref_size (&msg->sphdr) +
nn_chunkref_size (&msg->body));
return 0;
}
nanomsg-0.8-beta/src/transports/inproc/sinproc.h0000664000175000017500000000647312623652600023002 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_SINPROC_INCLUDED
#define NN_SINPROC_INCLUDED
#include "msgqueue.h"
#include "../../transport.h"
#include "../../aio/fsm.h"
#include "../../utils/msg.h"
#include "../../utils/list.h"
#define NN_SINPROC_CONNECT 1
#define NN_SINPROC_READY 2
#define NN_SINPROC_ACCEPTED 3
#define NN_SINPROC_SENT 4
#define NN_SINPROC_RECEIVED 5
#define NN_SINPROC_DISCONNECT 6
#define NN_SINPROC_STOPPED 7
/* We use a random value here to prevent accidental clashes with the peer's
internal source IDs. */
#define NN_SINPROC_SRC_PEER 27713
struct nn_sinproc {
/* The state machine. */
struct nn_fsm fsm;
int state;
/* Any combination of the flags defined in the .c file. */
int flags;
/* Pointer to the peer inproc session, if connected. NULL otherwise. */
struct nn_sinproc *peer;
/* Pipe connecting this inproc connection to the nanomsg core. */
struct nn_pipebase pipebase;
/* Inbound message queue. The messages contained are meant to be received
by the user later on. */
struct nn_msgqueue msgqueue;
/* This message is the one being sent from this session to the peer
session. It holds the data only temporarily, until the peer moves
it to its msgqueue. */
struct nn_msg msg;
/* Outbound events. I.e. event sent by this sinproc to the peer sinproc. */
struct nn_fsm_event event_connect;
/* Inbound events. I.e. events sent by the peer sinproc to this inproc. */
struct nn_fsm_event event_sent;
struct nn_fsm_event event_received;
struct nn_fsm_event event_disconnect;
/* This member is used only if we are on the bound side. binproc object
has a list of sinprocs it handles. */
struct nn_list_item item;
};
void nn_sinproc_init (struct nn_sinproc *self, int src,
struct nn_epbase *epbase, struct nn_fsm *owner);
void nn_sinproc_term (struct nn_sinproc *self);
int nn_sinproc_isidle (struct nn_sinproc *self);
/* Connect and accept are two different ways to start the state machine. */
void nn_sinproc_connect (struct nn_sinproc *self, struct nn_fsm *peer);
void nn_sinproc_accept (struct nn_sinproc *self, struct nn_sinproc *peer);
void nn_sinproc_stop (struct nn_sinproc *self);
#endif
nanomsg-0.8-beta/src/transports/inproc/sinproc.c0000664000175000017500000004104112623652600022763 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "sinproc.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/attr.h"
#include
#define NN_SINPROC_STATE_IDLE 1
#define NN_SINPROC_STATE_CONNECTING 2
#define NN_SINPROC_STATE_READY 3
#define NN_SINPROC_STATE_ACTIVE 4
#define NN_SINPROC_STATE_DISCONNECTED 5
#define NN_SINPROC_STATE_STOPPING_PEER 6
#define NN_SINPROC_STATE_STOPPING 7
#define NN_SINPROC_ACTION_READY 1
#define NN_SINPROC_ACTION_ACCEPTED 2
/* Set when SENT event was sent to the peer but RECEIVED haven't been
passed back yet. */
#define NN_SINPROC_FLAG_SENDING 1
/* Set when SENT event was received, but the new message cannot be written
to the queue yet, i.e. RECEIVED event haven't been returned
to the peer yet. */
#define NN_SINPROC_FLAG_RECEIVING 2
/* Private functions. */
static void nn_sinproc_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_sinproc_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
static int nn_sinproc_send (struct nn_pipebase *self, struct nn_msg *msg);
static int nn_sinproc_recv (struct nn_pipebase *self, struct nn_msg *msg);
const struct nn_pipebase_vfptr nn_sinproc_pipebase_vfptr = {
nn_sinproc_send,
nn_sinproc_recv
};
void nn_sinproc_init (struct nn_sinproc *self, int src,
struct nn_epbase *epbase, struct nn_fsm *owner)
{
int rcvbuf;
size_t sz;
nn_fsm_init (&self->fsm, nn_sinproc_handler, nn_sinproc_shutdown,
src, self, owner);
self->state = NN_SINPROC_STATE_IDLE;
self->flags = 0;
self->peer = NULL;
nn_pipebase_init (&self->pipebase, &nn_sinproc_pipebase_vfptr, epbase);
sz = sizeof (rcvbuf);
nn_epbase_getopt (epbase, NN_SOL_SOCKET, NN_RCVBUF, &rcvbuf, &sz);
nn_assert (sz == sizeof (rcvbuf));
nn_msgqueue_init (&self->msgqueue, rcvbuf);
nn_msg_init (&self->msg, 0);
nn_fsm_event_init (&self->event_connect);
nn_fsm_event_init (&self->event_sent);
nn_fsm_event_init (&self->event_received);
nn_fsm_event_init (&self->event_disconnect);
nn_list_item_init (&self->item);
}
void nn_sinproc_term (struct nn_sinproc *self)
{
nn_list_item_term (&self->item);
nn_fsm_event_term (&self->event_disconnect);
nn_fsm_event_term (&self->event_received);
nn_fsm_event_term (&self->event_sent);
nn_fsm_event_term (&self->event_connect);
nn_msg_term (&self->msg);
nn_msgqueue_term (&self->msgqueue);
nn_pipebase_term (&self->pipebase);
nn_fsm_term (&self->fsm);
}
int nn_sinproc_isidle (struct nn_sinproc *self)
{
return nn_fsm_isidle (&self->fsm);
}
void nn_sinproc_connect (struct nn_sinproc *self, struct nn_fsm *peer)
{
nn_fsm_start (&self->fsm);
/* Start the connecting handshake with the peer. */
nn_fsm_raiseto (&self->fsm, peer, &self->event_connect,
NN_SINPROC_SRC_PEER, NN_SINPROC_CONNECT, self);
}
void nn_sinproc_accept (struct nn_sinproc *self, struct nn_sinproc *peer)
{
nn_assert (!self->peer);
self->peer = peer;
/* Start the connecting handshake with the peer. */
nn_fsm_raiseto (&self->fsm, &peer->fsm, &self->event_connect,
NN_SINPROC_SRC_PEER, NN_SINPROC_READY, self);
/* Notify the state machine. */
nn_fsm_start (&self->fsm);
nn_fsm_action (&self->fsm, NN_SINPROC_ACTION_READY);
}
void nn_sinproc_stop (struct nn_sinproc *self)
{
nn_fsm_stop (&self->fsm);
}
static int nn_sinproc_send (struct nn_pipebase *self, struct nn_msg *msg)
{
struct nn_sinproc *sinproc;
sinproc = nn_cont (self, struct nn_sinproc, pipebase);
/* If the peer have already closed the connection, we cannot send
anymore. */
if (sinproc->state == NN_SINPROC_STATE_DISCONNECTED)
return -ECONNRESET;
/* Sanity checks. */
nn_assert_state (sinproc, NN_SINPROC_STATE_ACTIVE);
nn_assert (!(sinproc->flags & NN_SINPROC_FLAG_SENDING));
/* Expose the message to the peer. */
nn_msg_term (&sinproc->msg);
nn_msg_mv (&sinproc->msg, msg);
/* Notify the peer that there's a message to get. */
sinproc->flags |= NN_SINPROC_FLAG_SENDING;
nn_fsm_raiseto (&sinproc->fsm, &sinproc->peer->fsm,
&sinproc->peer->event_sent, NN_SINPROC_SRC_PEER,
NN_SINPROC_SENT, sinproc);
return 0;
}
static int nn_sinproc_recv (struct nn_pipebase *self, struct nn_msg *msg)
{
int rc;
struct nn_sinproc *sinproc;
sinproc = nn_cont (self, struct nn_sinproc, pipebase);
/* Sanity check. */
nn_assert (sinproc->state == NN_SINPROC_STATE_ACTIVE ||
sinproc->state == NN_SINPROC_STATE_DISCONNECTED);
/* Move the message to the caller. */
rc = nn_msgqueue_recv (&sinproc->msgqueue, msg);
errnum_assert (rc == 0, -rc);
/* If there was a message from peer lingering because of the exceeded
buffer limit, try to enqueue it once again. */
if (sinproc->state != NN_SINPROC_STATE_DISCONNECTED) {
if (nn_slow (sinproc->flags & NN_SINPROC_FLAG_RECEIVING)) {
rc = nn_msgqueue_send (&sinproc->msgqueue, &sinproc->peer->msg);
nn_assert (rc == 0 || rc == -EAGAIN);
if (rc == 0) {
errnum_assert (rc == 0, -rc);
nn_msg_init (&sinproc->peer->msg, 0);
nn_fsm_raiseto (&sinproc->fsm, &sinproc->peer->fsm,
&sinproc->peer->event_received, NN_SINPROC_SRC_PEER,
NN_SINPROC_RECEIVED, sinproc);
sinproc->flags &= ~NN_SINPROC_FLAG_RECEIVING;
}
}
}
if (!nn_msgqueue_empty (&sinproc->msgqueue))
nn_pipebase_received (&sinproc->pipebase);
return NN_PIPEBASE_PARSED;
}
static void nn_sinproc_shutdown_events (struct nn_sinproc *self, int src,
int type, NN_UNUSED void *srcptr)
{
/* ******************************* */
/* Any-state events */
/* ******************************* */
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_STOP:
if (self->state != NN_SINPROC_STATE_IDLE &&
self->state != NN_SINPROC_STATE_DISCONNECTED) {
nn_pipebase_stop (&self->pipebase);
nn_assert (self->fsm.state == 2 || self->fsm.state == 3);
nn_fsm_raiseto (&self->fsm, &self->peer->fsm,
&self->peer->event_disconnect, NN_SINPROC_SRC_PEER,
NN_SINPROC_DISCONNECT, self);
self->state = NN_SINPROC_STATE_STOPPING_PEER;
} else {
self->state = NN_SINPROC_STATE_STOPPING;
}
return;
}
case NN_SINPROC_SRC_PEER:
switch (type) {
case NN_SINPROC_RECEIVED:
return;
}
}
/* ******************************* */
/* Regular events */
/* ******************************* */
switch (self->state) {
case NN_SINPROC_STATE_STOPPING_PEER:
switch (src) {
case NN_SINPROC_SRC_PEER:
switch (type) {
case NN_SINPROC_DISCONNECT:
self->state = NN_SINPROC_STATE_STOPPING;
return;
default:
nn_fsm_bad_action (self->state, src, type);
}
default:
nn_fsm_bad_source (self->state, src, type);
}
default:
nn_fsm_bad_state (self->state, src, type);
}
nn_fsm_bad_action (self->state, src, type);
}
static void nn_sinproc_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr)
{
struct nn_sinproc *sinproc;
sinproc = nn_cont (self, struct nn_sinproc, fsm);
nn_assert (sinproc->fsm.state == 3);
nn_sinproc_shutdown_events (sinproc, src, type, srcptr);
/* *************** */
/* States to check */
/* *************** */
/* Have we got notification that peer is stopped */
if (nn_slow (sinproc->state != NN_SINPROC_STATE_STOPPING)) {
return;
}
/* Are all events processed? We can't cancel them unfortunately */
if (nn_fsm_event_active (&sinproc->event_received)
|| nn_fsm_event_active (&sinproc->event_disconnect))
{
return;
}
/* These events are deemed to be impossible here */
nn_assert (!nn_fsm_event_active (&sinproc->event_connect));
nn_assert (!nn_fsm_event_active (&sinproc->event_sent));
/* ********************************************** */
/* All checks are successful. Just stop right now */
/* ********************************************** */
nn_fsm_stopped (&sinproc->fsm, NN_SINPROC_STOPPED);
return;
}
static void nn_sinproc_handler (struct nn_fsm *self, int src, int type,
void *srcptr)
{
int rc;
struct nn_sinproc *sinproc;
int empty;
sinproc = nn_cont (self, struct nn_sinproc, fsm);
switch (sinproc->state) {
/******************************************************************************/
/* IDLE state. */
/******************************************************************************/
case NN_SINPROC_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
sinproc->state = NN_SINPROC_STATE_CONNECTING;
return;
default:
nn_fsm_bad_action (sinproc->state, src, type);
}
default:
nn_fsm_bad_source (sinproc->state, src, type);
}
/******************************************************************************/
/* CONNECTING state. */
/* CONNECT request was sent to the peer. Now we are waiting for the */
/* acknowledgement. */
/******************************************************************************/
case NN_SINPROC_STATE_CONNECTING:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_SINPROC_ACTION_READY:
sinproc->state = NN_SINPROC_STATE_READY;
return;
default:
nn_fsm_bad_action (sinproc->state, src, type);
}
case NN_SINPROC_SRC_PEER:
switch (type) {
case NN_SINPROC_READY:
sinproc->peer = (struct nn_sinproc*) srcptr;
rc = nn_pipebase_start (&sinproc->pipebase);
errnum_assert (rc == 0, -rc);
sinproc->state = NN_SINPROC_STATE_ACTIVE;
nn_fsm_raiseto (&sinproc->fsm, &sinproc->peer->fsm,
&sinproc->event_connect,
NN_SINPROC_SRC_PEER, NN_SINPROC_ACCEPTED, self);
return;
default:
nn_fsm_bad_action (sinproc->state, src, type);
}
default:
nn_fsm_bad_source (sinproc->state, src, type);
}
/******************************************************************************/
/* READY state. */
/* */
/******************************************************************************/
case NN_SINPROC_STATE_READY:
switch (src) {
case NN_SINPROC_SRC_PEER:
switch (type) {
case NN_SINPROC_READY:
/* This means both peers sent READY so they are both
ready for receiving messages */
rc = nn_pipebase_start (&sinproc->pipebase);
errnum_assert (rc == 0, -rc);
sinproc->state = NN_SINPROC_STATE_ACTIVE;
return;
case NN_SINPROC_ACCEPTED:
rc = nn_pipebase_start (&sinproc->pipebase);
errnum_assert (rc == 0, -rc);
sinproc->state = NN_SINPROC_STATE_ACTIVE;
return;
default:
nn_fsm_bad_action (sinproc->state, src, type);
}
default:
nn_fsm_bad_source (sinproc->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/******************************************************************************/
case NN_SINPROC_STATE_ACTIVE:
switch (src) {
case NN_SINPROC_SRC_PEER:
switch (type) {
case NN_SINPROC_SENT:
empty = nn_msgqueue_empty (&sinproc->msgqueue);
/* Push the message to the inbound message queue. */
rc = nn_msgqueue_send (&sinproc->msgqueue,
&sinproc->peer->msg);
if (rc == -EAGAIN) {
sinproc->flags |= NN_SINPROC_FLAG_RECEIVING;
return;
}
errnum_assert (rc == 0, -rc);
nn_msg_init (&sinproc->peer->msg, 0);
/* Notify the user that there's a message to receive. */
if (empty)
nn_pipebase_received (&sinproc->pipebase);
/* Notify the peer that the message was received. */
nn_fsm_raiseto (&sinproc->fsm, &sinproc->peer->fsm,
&sinproc->peer->event_received, NN_SINPROC_SRC_PEER,
NN_SINPROC_RECEIVED, sinproc);
return;
case NN_SINPROC_RECEIVED:
nn_assert (sinproc->flags & NN_SINPROC_FLAG_SENDING);
nn_pipebase_sent (&sinproc->pipebase);
sinproc->flags &= ~NN_SINPROC_FLAG_SENDING;
return;
case NN_SINPROC_DISCONNECT:
nn_pipebase_stop (&sinproc->pipebase);
nn_fsm_raiseto (&sinproc->fsm, &sinproc->peer->fsm,
&sinproc->peer->event_disconnect, NN_SINPROC_SRC_PEER,
NN_SINPROC_DISCONNECT, sinproc);
sinproc->state = NN_SINPROC_STATE_DISCONNECTED;
sinproc->peer = NULL;
nn_fsm_raise (&sinproc->fsm, &sinproc->event_disconnect,
NN_SINPROC_DISCONNECT);
return;
default:
nn_fsm_bad_action (sinproc->state, src, type);
}
default:
nn_fsm_bad_source (sinproc->state, src, type);
}
/******************************************************************************/
/* DISCONNECTED state. */
/* The peer have already closed the connection, but the object was not yet */
/* asked to stop. */
/******************************************************************************/
case NN_SINPROC_STATE_DISCONNECTED:
switch (src) {
case NN_SINPROC_SRC_PEER:
switch (type) {
case NN_SINPROC_RECEIVED:
/* This case can safely be ignored. It may happen when
nn_close() comes before the already enqueued
NN_SINPROC_RECEIVED has been delivered. */
return;
default:
nn_fsm_bad_action (sinproc->state, src, type);
};
default:
nn_fsm_bad_source (sinproc->state, src, type);
}
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (sinproc->state, src, type);
}
}
nanomsg-0.8-beta/src/transports/ipc/0000775000175000017500000000000012623652617020433 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/transports/ipc/aipc.h0000664000175000017500000000516512623652600021517 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_AIPC_INCLUDED
#define NN_AIPC_INCLUDED
#include "sipc.h"
#include "../../transport.h"
#include "../../aio/fsm.h"
#include "../../aio/usock.h"
#include "../../utils/list.h"
/* State machine handling accepted IPC sockets. */
/* In bipc, some events are just *assumed* to come from a child aipc object.
By using non-trivial event codes, we can do more reliable sanity checking
in such scenarios. */
#define NN_AIPC_ACCEPTED 34231
#define NN_AIPC_ERROR 34232
#define NN_AIPC_STOPPED 34233
struct nn_aipc {
/* The state machine. */
struct nn_fsm fsm;
int state;
/* Pointer to the associated endpoint. */
struct nn_epbase *epbase;
/* Underlying socket. */
struct nn_usock usock;
/* Listening socket. Valid only while accepting new connection. */
struct nn_usock *listener;
struct nn_fsm_owner listener_owner;
/* State machine that takes care of the connection in the active state. */
struct nn_sipc sipc;
/* Events generated by aipc state machine. */
struct nn_fsm_event accepted;
struct nn_fsm_event done;
/* This member can be used by owner to keep individual aipcs in a list. */
struct nn_list_item item;
};
void nn_aipc_init (struct nn_aipc *self, int src,
struct nn_epbase *epbase, struct nn_fsm *owner);
void nn_aipc_term (struct nn_aipc *self);
int nn_aipc_isidle (struct nn_aipc *self);
void nn_aipc_start (struct nn_aipc *self, struct nn_usock *listener);
void nn_aipc_stop (struct nn_aipc *self);
#endif
nanomsg-0.8-beta/src/transports/ipc/aipc.c0000664000175000017500000002526212623652600021512 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "aipc.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/attr.h"
#define NN_AIPC_STATE_IDLE 1
#define NN_AIPC_STATE_ACCEPTING 2
#define NN_AIPC_STATE_ACTIVE 3
#define NN_AIPC_STATE_STOPPING_SIPC 4
#define NN_AIPC_STATE_STOPPING_USOCK 5
#define NN_AIPC_STATE_DONE 6
#define NN_AIPC_STATE_STOPPING_SIPC_FINAL 7
#define NN_AIPC_STATE_STOPPING 8
#define NN_AIPC_SRC_USOCK 1
#define NN_AIPC_SRC_SIPC 2
#define NN_AIPC_SRC_LISTENER 3
/* Private functions. */
static void nn_aipc_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_aipc_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
void nn_aipc_init (struct nn_aipc *self, int src,
struct nn_epbase *epbase, struct nn_fsm *owner)
{
nn_fsm_init (&self->fsm, nn_aipc_handler, nn_aipc_shutdown,
src, self, owner);
self->state = NN_AIPC_STATE_IDLE;
self->epbase = epbase;
nn_usock_init (&self->usock, NN_AIPC_SRC_USOCK, &self->fsm);
self->listener = NULL;
self->listener_owner.src = -1;
self->listener_owner.fsm = NULL;
nn_sipc_init (&self->sipc, NN_AIPC_SRC_SIPC, epbase, &self->fsm);
nn_fsm_event_init (&self->accepted);
nn_fsm_event_init (&self->done);
nn_list_item_init (&self->item);
}
void nn_aipc_term (struct nn_aipc *self)
{
nn_assert_state (self, NN_AIPC_STATE_IDLE);
nn_list_item_term (&self->item);
nn_fsm_event_term (&self->done);
nn_fsm_event_term (&self->accepted);
nn_sipc_term (&self->sipc);
nn_usock_term (&self->usock);
nn_fsm_term (&self->fsm);
}
int nn_aipc_isidle (struct nn_aipc *self)
{
return nn_fsm_isidle (&self->fsm);
}
void nn_aipc_start (struct nn_aipc *self, struct nn_usock *listener)
{
nn_assert_state (self, NN_AIPC_STATE_IDLE);
/* Take ownership of the listener socket. */
self->listener = listener;
self->listener_owner.src = NN_AIPC_SRC_LISTENER;
self->listener_owner.fsm = &self->fsm;
nn_usock_swap_owner (listener, &self->listener_owner);
/* Start the state machine. */
nn_fsm_start (&self->fsm);
}
void nn_aipc_stop (struct nn_aipc *self)
{
nn_fsm_stop (&self->fsm);
}
static void nn_aipc_shutdown (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_aipc *aipc;
aipc = nn_cont (self, struct nn_aipc, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
if (!nn_sipc_isidle (&aipc->sipc)) {
nn_epbase_stat_increment (aipc->epbase,
NN_STAT_DROPPED_CONNECTIONS, 1);
nn_sipc_stop (&aipc->sipc);
}
aipc->state = NN_AIPC_STATE_STOPPING_SIPC_FINAL;
}
if (nn_slow (aipc->state == NN_AIPC_STATE_STOPPING_SIPC_FINAL)) {
if (!nn_sipc_isidle (&aipc->sipc))
return;
nn_usock_stop (&aipc->usock);
aipc->state = NN_AIPC_STATE_STOPPING;
}
if (nn_slow (aipc->state == NN_AIPC_STATE_STOPPING)) {
if (!nn_usock_isidle (&aipc->usock))
return;
if (aipc->listener) {
nn_assert (aipc->listener_owner.fsm);
nn_usock_swap_owner (aipc->listener, &aipc->listener_owner);
aipc->listener = NULL;
aipc->listener_owner.src = -1;
aipc->listener_owner.fsm = NULL;
}
aipc->state = NN_AIPC_STATE_IDLE;
nn_fsm_stopped (&aipc->fsm, NN_AIPC_STOPPED);
return;
}
nn_fsm_bad_state(aipc->state, src, type);
}
static void nn_aipc_handler (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_aipc *aipc;
int val;
size_t sz;
aipc = nn_cont (self, struct nn_aipc, fsm);
switch (aipc->state) {
/******************************************************************************/
/* IDLE state. */
/* The state machine wasn't yet started. */
/******************************************************************************/
case NN_AIPC_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
nn_usock_accept (&aipc->usock, aipc->listener);
aipc->state = NN_AIPC_STATE_ACCEPTING;
return;
default:
nn_fsm_bad_action (aipc->state, src, type);
}
default:
nn_fsm_bad_source (aipc->state, src, type);
}
/******************************************************************************/
/* ACCEPTING state. */
/* Waiting for incoming connection. */
/******************************************************************************/
case NN_AIPC_STATE_ACCEPTING:
switch (src) {
case NN_AIPC_SRC_USOCK:
switch (type) {
case NN_USOCK_ACCEPTED:
nn_epbase_clear_error (aipc->epbase);
/* Set the relevant socket options. */
sz = sizeof (val);
nn_epbase_getopt (aipc->epbase, NN_SOL_SOCKET, NN_SNDBUF,
&val, &sz);
nn_assert (sz == sizeof (val));
nn_usock_setsockopt (&aipc->usock, SOL_SOCKET, SO_SNDBUF,
&val, sizeof (val));
sz = sizeof (val);
nn_epbase_getopt (aipc->epbase, NN_SOL_SOCKET, NN_RCVBUF,
&val, &sz);
nn_assert (sz == sizeof (val));
nn_usock_setsockopt (&aipc->usock, SOL_SOCKET, SO_RCVBUF,
&val, sizeof (val));
/* Return ownership of the listening socket to the parent. */
nn_usock_swap_owner (aipc->listener, &aipc->listener_owner);
aipc->listener = NULL;
aipc->listener_owner.src = -1;
aipc->listener_owner.fsm = NULL;
nn_fsm_raise (&aipc->fsm, &aipc->accepted, NN_AIPC_ACCEPTED);
/* Start the sipc state machine. */
nn_usock_activate (&aipc->usock);
nn_sipc_start (&aipc->sipc, &aipc->usock);
aipc->state = NN_AIPC_STATE_ACTIVE;
nn_epbase_stat_increment (aipc->epbase,
NN_STAT_ACCEPTED_CONNECTIONS, 1);
return;
default:
nn_fsm_bad_action (aipc->state, src, type);
}
case NN_AIPC_SRC_LISTENER:
switch (type) {
case NN_USOCK_ACCEPT_ERROR:
nn_epbase_set_error (aipc->epbase,
nn_usock_geterrno (aipc->listener));
nn_epbase_stat_increment (aipc->epbase,
NN_STAT_ACCEPT_ERRORS, 1);
nn_usock_accept (&aipc->usock, aipc->listener);
return;
default:
nn_fsm_bad_action (aipc->state, src, type);
}
default:
nn_fsm_bad_source (aipc->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/******************************************************************************/
case NN_AIPC_STATE_ACTIVE:
switch (src) {
case NN_AIPC_SRC_SIPC:
switch (type) {
case NN_SIPC_ERROR:
nn_sipc_stop (&aipc->sipc);
aipc->state = NN_AIPC_STATE_STOPPING_SIPC;
nn_epbase_stat_increment (aipc->epbase,
NN_STAT_BROKEN_CONNECTIONS, 1);
return;
default:
nn_fsm_bad_action (aipc->state, src, type);
}
default:
nn_fsm_bad_source (aipc->state, src, type);
}
/******************************************************************************/
/* STOPPING_SIPC state. */
/******************************************************************************/
case NN_AIPC_STATE_STOPPING_SIPC:
switch (src) {
case NN_AIPC_SRC_SIPC:
switch (type) {
case NN_USOCK_SHUTDOWN:
return;
case NN_SIPC_STOPPED:
nn_usock_stop (&aipc->usock);
aipc->state = NN_AIPC_STATE_STOPPING_USOCK;
return;
default:
nn_fsm_bad_action (aipc->state, src, type);
}
default:
nn_fsm_bad_source (aipc->state, src, type);
}
/******************************************************************************/
/* STOPPING_USOCK state. */
/******************************************************************************/
case NN_AIPC_STATE_STOPPING_USOCK:
switch (src) {
case NN_AIPC_SRC_USOCK:
switch (type) {
case NN_USOCK_SHUTDOWN:
return;
case NN_USOCK_STOPPED:
nn_fsm_raise (&aipc->fsm, &aipc->done, NN_AIPC_ERROR);
aipc->state = NN_AIPC_STATE_DONE;
return;
default:
nn_fsm_bad_action (aipc->state, src, type);
}
default:
nn_fsm_bad_source (aipc->state, src, type);
}
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (aipc->state, src, type);
}
}
nanomsg-0.8-beta/src/transports/ipc/bipc.h0000664000175000017500000000250512623652600021513 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_BIPC_INCLUDED
#define NN_BIPC_INCLUDED
#include "../../transport.h"
/* State machine managing bound IPC socket. */
int nn_bipc_create (void *hint, struct nn_epbase **epbase);
#endif
nanomsg-0.8-beta/src/transports/ipc/bipc.c0000664000175000017500000003523612623652600021515 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "bipc.h"
#include "aipc.h"
#include "../../aio/fsm.h"
#include "../../aio/usock.h"
#include "../utils/backoff.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/alloc.h"
#include "../../utils/list.h"
#include "../../utils/fast.h"
#include
#if defined NN_HAVE_WINDOWS
#include "../../utils/win.h"
#else
#include
#include
#include
#endif
#define NN_BIPC_BACKLOG 10
#define NN_BIPC_STATE_IDLE 1
#define NN_BIPC_STATE_ACTIVE 2
#define NN_BIPC_STATE_STOPPING_AIPC 3
#define NN_BIPC_STATE_STOPPING_USOCK 4
#define NN_BIPC_STATE_STOPPING_AIPCS 5
#define NN_BIPC_STATE_LISTENING 6
#define NN_BIPC_STATE_WAITING 7
#define NN_BIPC_STATE_CLOSING 8
#define NN_BIPC_STATE_STOPPING_BACKOFF 9
#define NN_BIPC_SRC_USOCK 1
#define NN_BIPC_SRC_AIPC 2
#define NN_BIPC_SRC_RECONNECT_TIMER 3
struct nn_bipc {
/* The state machine. */
struct nn_fsm fsm;
int state;
/* This object is a specific type of endpoint.
Thus it is derived from epbase. */
struct nn_epbase epbase;
/* The underlying listening IPC socket. */
struct nn_usock usock;
/* The connection being accepted at the moment. */
struct nn_aipc *aipc;
/* List of accepted connections. */
struct nn_list aipcs;
/* Used to wait before retrying to connect. */
struct nn_backoff retry;
};
/* nn_epbase virtual interface implementation. */
static void nn_bipc_stop (struct nn_epbase *self);
static void nn_bipc_destroy (struct nn_epbase *self);
const struct nn_epbase_vfptr nn_bipc_epbase_vfptr = {
nn_bipc_stop,
nn_bipc_destroy
};
/* Private functions. */
static void nn_bipc_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_bipc_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_bipc_start_listening (struct nn_bipc *self);
static void nn_bipc_start_accepting (struct nn_bipc *self);
int nn_bipc_create (void *hint, struct nn_epbase **epbase)
{
struct nn_bipc *self;
int reconnect_ivl;
int reconnect_ivl_max;
size_t sz;
/* Allocate the new endpoint object. */
self = nn_alloc (sizeof (struct nn_bipc), "bipc");
alloc_assert (self);
/* Initialise the structure. */
nn_epbase_init (&self->epbase, &nn_bipc_epbase_vfptr, hint);
nn_fsm_init_root (&self->fsm, nn_bipc_handler, nn_bipc_shutdown,
nn_epbase_getctx (&self->epbase));
self->state = NN_BIPC_STATE_IDLE;
sz = sizeof (reconnect_ivl);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL,
&reconnect_ivl, &sz);
nn_assert (sz == sizeof (reconnect_ivl));
sz = sizeof (reconnect_ivl_max);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX,
&reconnect_ivl_max, &sz);
nn_assert (sz == sizeof (reconnect_ivl_max));
if (reconnect_ivl_max == 0)
reconnect_ivl_max = reconnect_ivl;
nn_backoff_init (&self->retry, NN_BIPC_SRC_RECONNECT_TIMER,
reconnect_ivl, reconnect_ivl_max, &self->fsm);
nn_usock_init (&self->usock, NN_BIPC_SRC_USOCK, &self->fsm);
self->aipc = NULL;
nn_list_init (&self->aipcs);
/* Start the state machine. */
nn_fsm_start (&self->fsm);
/* Return the base class as an out parameter. */
*epbase = &self->epbase;
return 0;
}
static void nn_bipc_stop (struct nn_epbase *self)
{
struct nn_bipc *bipc;
bipc = nn_cont (self, struct nn_bipc, epbase);
nn_fsm_stop (&bipc->fsm);
}
static void nn_bipc_destroy (struct nn_epbase *self)
{
struct nn_bipc *bipc;
bipc = nn_cont (self, struct nn_bipc, epbase);
nn_assert_state (bipc, NN_BIPC_STATE_IDLE);
nn_list_term (&bipc->aipcs);
nn_assert (bipc->aipc == NULL);
nn_usock_term (&bipc->usock);
nn_backoff_term (&bipc->retry);
nn_epbase_term (&bipc->epbase);
nn_fsm_term (&bipc->fsm);
nn_free (bipc);
}
static void nn_bipc_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr)
{
struct nn_bipc *bipc;
struct nn_list_item *it;
struct nn_aipc *aipc;
bipc = nn_cont (self, struct nn_bipc, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
nn_backoff_stop (&bipc->retry);
if (bipc->aipc) {
nn_aipc_stop (bipc->aipc);
bipc->state = NN_BIPC_STATE_STOPPING_AIPC;
}
else {
bipc->state = NN_BIPC_STATE_STOPPING_USOCK;
}
}
if (nn_slow (bipc->state == NN_BIPC_STATE_STOPPING_AIPC)) {
if (!nn_aipc_isidle (bipc->aipc))
return;
nn_aipc_term (bipc->aipc);
nn_free (bipc->aipc);
bipc->aipc = NULL;
nn_usock_stop (&bipc->usock);
bipc->state = NN_BIPC_STATE_STOPPING_USOCK;
}
if (nn_slow (bipc->state == NN_BIPC_STATE_STOPPING_USOCK)) {
if (!nn_usock_isidle (&bipc->usock) ||
!nn_backoff_isidle (&bipc->retry))
return;
for (it = nn_list_begin (&bipc->aipcs);
it != nn_list_end (&bipc->aipcs);
it = nn_list_next (&bipc->aipcs, it)) {
aipc = nn_cont (it, struct nn_aipc, item);
nn_aipc_stop (aipc);
}
bipc->state = NN_BIPC_STATE_STOPPING_AIPCS;
goto aipcs_stopping;
}
if (nn_slow (bipc->state == NN_BIPC_STATE_STOPPING_AIPCS)) {
nn_assert (src == NN_BIPC_SRC_AIPC && type == NN_AIPC_STOPPED);
aipc = (struct nn_aipc *) srcptr;
nn_list_erase (&bipc->aipcs, &aipc->item);
nn_aipc_term (aipc);
nn_free (aipc);
/* If there are no more aipc state machines, we can stop the whole
bipc object. */
aipcs_stopping:
if (nn_list_empty (&bipc->aipcs)) {
bipc->state = NN_BIPC_STATE_IDLE;
nn_fsm_stopped_noevent (&bipc->fsm);
nn_epbase_stopped (&bipc->epbase);
return;
}
return;
}
nn_fsm_bad_state(bipc->state, src, type);
}
static void nn_bipc_handler (struct nn_fsm *self, int src, int type,
void *srcptr)
{
struct nn_bipc *bipc;
struct nn_aipc *aipc;
bipc = nn_cont (self, struct nn_bipc, fsm);
switch (bipc->state) {
/******************************************************************************/
/* IDLE state. */
/******************************************************************************/
case NN_BIPC_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
nn_bipc_start_listening (bipc);
return;
default:
nn_fsm_bad_action (bipc->state, src, type);
}
default:
nn_fsm_bad_source (bipc->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/* The execution is yielded to the aipc state machine in this state. */
/******************************************************************************/
case NN_BIPC_STATE_ACTIVE:
if (srcptr == bipc->aipc) {
switch (type) {
case NN_AIPC_ACCEPTED:
/* Move the newly created connection to the list of existing
connections. */
nn_list_insert (&bipc->aipcs, &bipc->aipc->item,
nn_list_end (&bipc->aipcs));
bipc->aipc = NULL;
/* Start waiting for a new incoming connection. */
nn_bipc_start_accepting (bipc);
return;
default:
nn_fsm_bad_action (bipc->state, src, type);
}
}
/* For all remaining events we'll assume they are coming from one
of remaining child aipc objects. */
nn_assert (src == NN_BIPC_SRC_AIPC);
aipc = (struct nn_aipc*) srcptr;
switch (type) {
case NN_AIPC_ERROR:
nn_aipc_stop (aipc);
return;
case NN_AIPC_STOPPED:
nn_list_erase (&bipc->aipcs, &aipc->item);
nn_aipc_term (aipc);
nn_free (aipc);
return;
default:
nn_fsm_bad_action (bipc->state, src, type);
}
/******************************************************************************/
/* CLOSING_USOCK state. */
/* usock object was asked to stop but it haven't stopped yet. */
/******************************************************************************/
case NN_BIPC_STATE_CLOSING:
switch (src) {
case NN_BIPC_SRC_USOCK:
switch (type) {
case NN_USOCK_SHUTDOWN:
return;
case NN_USOCK_STOPPED:
nn_backoff_start (&bipc->retry);
bipc->state = NN_BIPC_STATE_WAITING;
return;
default:
nn_fsm_bad_action (bipc->state, src, type);
}
default:
nn_fsm_bad_source (bipc->state, src, type);
}
/******************************************************************************/
/* WAITING state. */
/* Waiting before re-bind is attempted. This way we won't overload */
/* the system by continuous re-bind attemps. */
/******************************************************************************/
case NN_BIPC_STATE_WAITING:
switch (src) {
case NN_BIPC_SRC_RECONNECT_TIMER:
switch (type) {
case NN_BACKOFF_TIMEOUT:
nn_backoff_stop (&bipc->retry);
bipc->state = NN_BIPC_STATE_STOPPING_BACKOFF;
return;
default:
nn_fsm_bad_action (bipc->state, src, type);
}
default:
nn_fsm_bad_source (bipc->state, src, type);
}
/******************************************************************************/
/* STOPPING_BACKOFF state. */
/* backoff object was asked to stop, but it haven't stopped yet. */
/******************************************************************************/
case NN_BIPC_STATE_STOPPING_BACKOFF:
switch (src) {
case NN_BIPC_SRC_RECONNECT_TIMER:
switch (type) {
case NN_BACKOFF_STOPPED:
nn_bipc_start_listening (bipc);
return;
default:
nn_fsm_bad_action (bipc->state, src, type);
}
default:
nn_fsm_bad_source (bipc->state, src, type);
}
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (bipc->state, src, type);
}
}
/******************************************************************************/
/* State machine actions. */
/******************************************************************************/
static void nn_bipc_start_listening (struct nn_bipc *self)
{
int rc;
struct sockaddr_storage ss;
struct sockaddr_un *un;
const char *addr;
#if !defined NN_HAVE_WINDOWS
int fd;
#endif
/* First, create the AF_UNIX address. */
addr = nn_epbase_getaddr (&self->epbase);
memset (&ss, 0, sizeof (ss));
un = (struct sockaddr_un*) &ss;
nn_assert (strlen (addr) < sizeof (un->sun_path));
ss.ss_family = AF_UNIX;
strncpy (un->sun_path, addr, sizeof (un->sun_path));
/* Delete the IPC file left over by eventual previous runs of
the application. We'll check whether the file is still in use by
connecting to the endpoint. On Windows plaform, NamedPipe is used
which does not have an underlying file. */
#if !defined NN_HAVE_WINDOWS
fd = socket (AF_UNIX, SOCK_STREAM, 0);
if (fd >= 0) {
rc = fcntl (fd, F_SETFL, O_NONBLOCK);
errno_assert (rc != -1 || errno == EINVAL);
rc = connect (fd, (struct sockaddr*) &ss,
sizeof (struct sockaddr_un));
if (rc == -1 && errno == ECONNREFUSED) {
rc = unlink (addr);
errno_assert (rc == 0 || errno == ENOENT);
}
rc = close (fd);
errno_assert (rc == 0);
}
#endif
/* Start listening for incoming connections. */
rc = nn_usock_start (&self->usock, AF_UNIX, SOCK_STREAM, 0);
if (nn_slow (rc < 0)) {
nn_backoff_start (&self->retry);
self->state = NN_BIPC_STATE_WAITING;
return;
}
rc = nn_usock_bind (&self->usock,
(struct sockaddr*) &ss, sizeof (struct sockaddr_un));
if (nn_slow (rc < 0)) {
nn_usock_stop (&self->usock);
self->state = NN_BIPC_STATE_CLOSING;
return;
}
rc = nn_usock_listen (&self->usock, NN_BIPC_BACKLOG);
if (nn_slow (rc < 0)) {
nn_usock_stop (&self->usock);
self->state = NN_BIPC_STATE_CLOSING;
return;
}
nn_bipc_start_accepting (self);
self->state = NN_BIPC_STATE_ACTIVE;
}
static void nn_bipc_start_accepting (struct nn_bipc *self)
{
nn_assert (self->aipc == NULL);
/* Allocate new aipc state machine. */
self->aipc = nn_alloc (sizeof (struct nn_aipc), "aipc");
alloc_assert (self->aipc);
nn_aipc_init (self->aipc, NN_BIPC_SRC_AIPC, &self->epbase, &self->fsm);
/* Start waiting for a new incoming connection. */
nn_aipc_start (self->aipc, &self->usock);
}
nanomsg-0.8-beta/src/transports/ipc/cipc.h0000664000175000017500000000251112623652600021511 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_CIPC_INCLUDED
#define NN_CIPC_INCLUDED
#include "../../transport.h"
/* State machine managing connected IPC socket. */
int nn_cipc_create (void *hint, struct nn_epbase **epbase);
#endif
nanomsg-0.8-beta/src/transports/ipc/cipc.c0000664000175000017500000003470412623652600021515 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "cipc.h"
#include "sipc.h"
#include "../../aio/fsm.h"
#include "../../aio/usock.h"
#include "../utils/backoff.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/alloc.h"
#include "../../utils/fast.h"
#include "../../utils/attr.h"
#include
#if defined NN_HAVE_WINDOWS
#include "../../utils/win.h"
#else
#include
#include
#endif
#define NN_CIPC_STATE_IDLE 1
#define NN_CIPC_STATE_CONNECTING 2
#define NN_CIPC_STATE_ACTIVE 3
#define NN_CIPC_STATE_STOPPING_SIPC 4
#define NN_CIPC_STATE_STOPPING_USOCK 5
#define NN_CIPC_STATE_WAITING 6
#define NN_CIPC_STATE_STOPPING_BACKOFF 7
#define NN_CIPC_STATE_STOPPING_SIPC_FINAL 8
#define NN_CIPC_STATE_STOPPING 9
#define NN_CIPC_SRC_USOCK 1
#define NN_CIPC_SRC_RECONNECT_TIMER 2
#define NN_CIPC_SRC_SIPC 3
struct nn_cipc {
/* The state machine. */
struct nn_fsm fsm;
int state;
/* This object is a specific type of endpoint.
Thus it is derived from epbase. */
struct nn_epbase epbase;
/* The underlying IPC socket. */
struct nn_usock usock;
/* Used to wait before retrying to connect. */
struct nn_backoff retry;
/* State machine that handles the active part of the connection
lifetime. */
struct nn_sipc sipc;
};
/* nn_epbase virtual interface implementation. */
static void nn_cipc_stop (struct nn_epbase *self);
static void nn_cipc_destroy (struct nn_epbase *self);
const struct nn_epbase_vfptr nn_cipc_epbase_vfptr = {
nn_cipc_stop,
nn_cipc_destroy
};
/* Private functions. */
static void nn_cipc_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_cipc_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_cipc_start_connecting (struct nn_cipc *self);
int nn_cipc_create (void *hint, struct nn_epbase **epbase)
{
struct nn_cipc *self;
int reconnect_ivl;
int reconnect_ivl_max;
size_t sz;
/* Allocate the new endpoint object. */
self = nn_alloc (sizeof (struct nn_cipc), "cipc");
alloc_assert (self);
/* Initialise the structure. */
nn_epbase_init (&self->epbase, &nn_cipc_epbase_vfptr, hint);
nn_fsm_init_root (&self->fsm, nn_cipc_handler, nn_cipc_shutdown,
nn_epbase_getctx (&self->epbase));
self->state = NN_CIPC_STATE_IDLE;
nn_usock_init (&self->usock, NN_CIPC_SRC_USOCK, &self->fsm);
sz = sizeof (reconnect_ivl);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL,
&reconnect_ivl, &sz);
nn_assert (sz == sizeof (reconnect_ivl));
sz = sizeof (reconnect_ivl_max);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX,
&reconnect_ivl_max, &sz);
nn_assert (sz == sizeof (reconnect_ivl_max));
if (reconnect_ivl_max == 0)
reconnect_ivl_max = reconnect_ivl;
nn_backoff_init (&self->retry, NN_CIPC_SRC_RECONNECT_TIMER,
reconnect_ivl, reconnect_ivl_max, &self->fsm);
nn_sipc_init (&self->sipc, NN_CIPC_SRC_SIPC, &self->epbase, &self->fsm);
/* Start the state machine. */
nn_fsm_start (&self->fsm);
/* Return the base class as an out parameter. */
*epbase = &self->epbase;
return 0;
}
static void nn_cipc_stop (struct nn_epbase *self)
{
struct nn_cipc *cipc;
cipc = nn_cont (self, struct nn_cipc, epbase);
nn_fsm_stop (&cipc->fsm);
}
static void nn_cipc_destroy (struct nn_epbase *self)
{
struct nn_cipc *cipc;
cipc = nn_cont (self, struct nn_cipc, epbase);
nn_sipc_term (&cipc->sipc);
nn_backoff_term (&cipc->retry);
nn_usock_term (&cipc->usock);
nn_fsm_term (&cipc->fsm);
nn_epbase_term (&cipc->epbase);
nn_free (cipc);
}
static void nn_cipc_shutdown (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_cipc *cipc;
cipc = nn_cont (self, struct nn_cipc, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
if (!nn_sipc_isidle (&cipc->sipc)) {
nn_epbase_stat_increment (&cipc->epbase,
NN_STAT_DROPPED_CONNECTIONS, 1);
nn_sipc_stop (&cipc->sipc);
}
cipc->state = NN_CIPC_STATE_STOPPING_SIPC_FINAL;
}
if (nn_slow (cipc->state == NN_CIPC_STATE_STOPPING_SIPC_FINAL)) {
if (!nn_sipc_isidle (&cipc->sipc))
return;
nn_backoff_stop (&cipc->retry);
nn_usock_stop (&cipc->usock);
cipc->state = NN_CIPC_STATE_STOPPING;
}
if (nn_slow (cipc->state == NN_CIPC_STATE_STOPPING)) {
if (!nn_backoff_isidle (&cipc->retry) ||
!nn_usock_isidle (&cipc->usock))
return;
cipc->state = NN_CIPC_STATE_IDLE;
nn_fsm_stopped_noevent (&cipc->fsm);
nn_epbase_stopped (&cipc->epbase);
return;
}
nn_fsm_bad_state(cipc->state, src, type);
}
static void nn_cipc_handler (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_cipc *cipc;
cipc = nn_cont (self, struct nn_cipc, fsm);
switch (cipc->state) {
/******************************************************************************/
/* IDLE state. */
/* The state machine wasn't yet started. */
/******************************************************************************/
case NN_CIPC_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
nn_cipc_start_connecting (cipc);
return;
default:
nn_fsm_bad_action (cipc->state, src, type);
}
default:
nn_fsm_bad_source (cipc->state, src, type);
}
/******************************************************************************/
/* CONNECTING state. */
/* Non-blocking connect is under way. */
/******************************************************************************/
case NN_CIPC_STATE_CONNECTING:
switch (src) {
case NN_CIPC_SRC_USOCK:
switch (type) {
case NN_USOCK_CONNECTED:
nn_sipc_start (&cipc->sipc, &cipc->usock);
cipc->state = NN_CIPC_STATE_ACTIVE;
nn_epbase_stat_increment (&cipc->epbase,
NN_STAT_INPROGRESS_CONNECTIONS, -1);
nn_epbase_stat_increment (&cipc->epbase,
NN_STAT_ESTABLISHED_CONNECTIONS, 1);
nn_epbase_clear_error (&cipc->epbase);
return;
case NN_USOCK_ERROR:
nn_epbase_set_error (&cipc->epbase,
nn_usock_geterrno (&cipc->usock));
nn_usock_stop (&cipc->usock);
cipc->state = NN_CIPC_STATE_STOPPING_USOCK;
nn_epbase_stat_increment (&cipc->epbase,
NN_STAT_INPROGRESS_CONNECTIONS, -1);
nn_epbase_stat_increment (&cipc->epbase,
NN_STAT_CONNECT_ERRORS, 1);
return;
default:
nn_fsm_bad_action (cipc->state, src, type);
}
default:
nn_fsm_bad_source (cipc->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/* Connection is established and handled by the sipc state machine. */
/******************************************************************************/
case NN_CIPC_STATE_ACTIVE:
switch (src) {
case NN_CIPC_SRC_SIPC:
switch (type) {
case NN_SIPC_ERROR:
nn_sipc_stop (&cipc->sipc);
cipc->state = NN_CIPC_STATE_STOPPING_SIPC;
nn_epbase_stat_increment (&cipc->epbase,
NN_STAT_BROKEN_CONNECTIONS, 1);
return;
default:
nn_fsm_bad_action (cipc->state, src, type);
}
default:
nn_fsm_bad_source (cipc->state, src, type);
}
/******************************************************************************/
/* STOPPING_SIPC state. */
/* sipc object was asked to stop but it haven't stopped yet. */
/******************************************************************************/
case NN_CIPC_STATE_STOPPING_SIPC:
switch (src) {
case NN_CIPC_SRC_SIPC:
switch (type) {
case NN_USOCK_SHUTDOWN:
return;
case NN_SIPC_STOPPED:
nn_usock_stop (&cipc->usock);
cipc->state = NN_CIPC_STATE_STOPPING_USOCK;
return;
default:
nn_fsm_bad_action (cipc->state, src, type);
}
default:
nn_fsm_bad_source (cipc->state, src, type);
}
/******************************************************************************/
/* STOPPING_USOCK state. */
/* usock object was asked to stop but it haven't stopped yet. */
/******************************************************************************/
case NN_CIPC_STATE_STOPPING_USOCK:
switch (src) {
case NN_CIPC_SRC_USOCK:
switch (type) {
case NN_USOCK_SHUTDOWN:
return;
case NN_USOCK_STOPPED:
nn_backoff_start (&cipc->retry);
cipc->state = NN_CIPC_STATE_WAITING;
return;
default:
nn_fsm_bad_action (cipc->state, src, type);
}
default:
nn_fsm_bad_source (cipc->state, src, type);
}
/******************************************************************************/
/* WAITING state. */
/* Waiting before re-connection is attempted. This way we won't overload */
/* the system by continuous re-connection attemps. */
/******************************************************************************/
case NN_CIPC_STATE_WAITING:
switch (src) {
case NN_CIPC_SRC_RECONNECT_TIMER:
switch (type) {
case NN_BACKOFF_TIMEOUT:
nn_backoff_stop (&cipc->retry);
cipc->state = NN_CIPC_STATE_STOPPING_BACKOFF;
return;
default:
nn_fsm_bad_action (cipc->state, src, type);
}
default:
nn_fsm_bad_source (cipc->state, src, type);
}
/******************************************************************************/
/* STOPPING_BACKOFF state. */
/* backoff object was asked to stop, but it haven't stopped yet. */
/******************************************************************************/
case NN_CIPC_STATE_STOPPING_BACKOFF:
switch (src) {
case NN_CIPC_SRC_RECONNECT_TIMER:
switch (type) {
case NN_BACKOFF_STOPPED:
nn_cipc_start_connecting (cipc);
return;
default:
nn_fsm_bad_action (cipc->state, src, type);
}
default:
nn_fsm_bad_source (cipc->state, src, type);
}
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (cipc->state, src, type);
}
}
/******************************************************************************/
/* State machine actions. */
/******************************************************************************/
static void nn_cipc_start_connecting (struct nn_cipc *self)
{
int rc;
struct sockaddr_storage ss;
struct sockaddr_un *un;
const char *addr;
int val;
size_t sz;
/* Try to start the underlying socket. */
rc = nn_usock_start (&self->usock, AF_UNIX, SOCK_STREAM, 0);
if (nn_slow (rc < 0)) {
nn_backoff_start (&self->retry);
self->state = NN_CIPC_STATE_WAITING;
return;
}
/* Set the relevant socket options. */
sz = sizeof (val);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz);
nn_assert (sz == sizeof (val));
nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_SNDBUF,
&val, sizeof (val));
sz = sizeof (val);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz);
nn_assert (sz == sizeof (val));
nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_RCVBUF,
&val, sizeof (val));
/* Create the IPC address from the address string. */
addr = nn_epbase_getaddr (&self->epbase);
memset (&ss, 0, sizeof (ss));
un = (struct sockaddr_un*) &ss;
nn_assert (strlen (addr) < sizeof (un->sun_path));
ss.ss_family = AF_UNIX;
strncpy (un->sun_path, addr, sizeof (un->sun_path));
/* Start connecting. */
nn_usock_connect (&self->usock, (struct sockaddr*) &ss,
sizeof (struct sockaddr_un));
self->state = NN_CIPC_STATE_CONNECTING;
nn_epbase_stat_increment (&self->epbase,
NN_STAT_INPROGRESS_CONNECTIONS, 1);
}
nanomsg-0.8-beta/src/transports/ipc/ipc.h0000664000175000017500000000237712623652600021360 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_IPC_INCLUDED
#define NN_IPC_INCLUDED
#include "../../transport.h"
extern struct nn_transport *nn_ipc;
#endif
nanomsg-0.8-beta/src/transports/ipc/ipc.c0000664000175000017500000000417212623652600021346 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "ipc.h"
#include "bipc.h"
#include "cipc.h"
#include "../../ipc.h"
#include "../../utils/err.h"
#include "../../utils/alloc.h"
#include "../../utils/fast.h"
#include "../../utils/list.h"
#include
#if defined NN_HAVE_WINDOWS
#include "../../utils/win.h"
#else
#include
#include
#include
#endif
/* nn_transport interface. */
static int nn_ipc_bind (void *hint, struct nn_epbase **epbase);
static int nn_ipc_connect (void *hint, struct nn_epbase **epbase);
static struct nn_transport nn_ipc_vfptr = {
"ipc",
NN_IPC,
NULL,
NULL,
nn_ipc_bind,
nn_ipc_connect,
NULL,
NN_LIST_ITEM_INITIALIZER
};
struct nn_transport *nn_ipc = &nn_ipc_vfptr;
static int nn_ipc_bind (void *hint, struct nn_epbase **epbase)
{
return nn_bipc_create (hint, epbase);
}
static int nn_ipc_connect (void *hint, struct nn_epbase **epbase)
{
return nn_cipc_create (hint, epbase);
}
nanomsg-0.8-beta/src/transports/ipc/sipc.h0000664000175000017500000000540212623652600021533 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_SIPC_INCLUDED
#define NN_SIPC_INCLUDED
#include "../../transport.h"
#include "../../aio/fsm.h"
#include "../../aio/usock.h"
#include "../utils/streamhdr.h"
#include "../../utils/msg.h"
/* This state machine handles IPC connection from the point where it is
established to the point when it is broken. */
#define NN_SIPC_ERROR 1
#define NN_SIPC_STOPPED 2
struct nn_sipc {
/* The state machine. */
struct nn_fsm fsm;
int state;
/* The underlying socket. */
struct nn_usock *usock;
/* Child state machine to do protocol header exchange. */
struct nn_streamhdr streamhdr;
/* The original owner of the underlying socket. */
struct nn_fsm_owner usock_owner;
/* Pipe connecting this IPC connection to the nanomsg core. */
struct nn_pipebase pipebase;
/* State of inbound state machine. */
int instate;
/* Buffer used to store the header of incoming message. */
uint8_t inhdr [9];
/* Message being received at the moment. */
struct nn_msg inmsg;
/* State of the outbound state machine. */
int outstate;
/* Buffer used to store the header of outgoing message. */
uint8_t outhdr [9];
/* Message being sent at the moment. */
struct nn_msg outmsg;
/* Event raised when the state machine ends. */
struct nn_fsm_event done;
};
void nn_sipc_init (struct nn_sipc *self, int src,
struct nn_epbase *epbase, struct nn_fsm *owner);
void nn_sipc_term (struct nn_sipc *self);
int nn_sipc_isidle (struct nn_sipc *self);
void nn_sipc_start (struct nn_sipc *self, struct nn_usock *usock);
void nn_sipc_stop (struct nn_sipc *self);
#endif
nanomsg-0.8-beta/src/transports/ipc/sipc.c0000664000175000017500000003447312623652600021540 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "sipc.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/wire.h"
#include "../../utils/int.h"
#include "../../utils/attr.h"
/* Types of messages passed via IPC transport. */
#define NN_SIPC_MSG_NORMAL 1
#define NN_SIPC_MSG_SHMEM 2
/* States of the object as a whole. */
#define NN_SIPC_STATE_IDLE 1
#define NN_SIPC_STATE_PROTOHDR 2
#define NN_SIPC_STATE_STOPPING_STREAMHDR 3
#define NN_SIPC_STATE_ACTIVE 4
#define NN_SIPC_STATE_SHUTTING_DOWN 5
#define NN_SIPC_STATE_DONE 6
#define NN_SIPC_STATE_STOPPING 7
/* Subordinated srcptr objects. */
#define NN_SIPC_SRC_USOCK 1
#define NN_SIPC_SRC_STREAMHDR 2
/* Possible states of the inbound part of the object. */
#define NN_SIPC_INSTATE_HDR 1
#define NN_SIPC_INSTATE_BODY 2
#define NN_SIPC_INSTATE_HASMSG 3
/* Possible states of the outbound part of the object. */
#define NN_SIPC_OUTSTATE_IDLE 1
#define NN_SIPC_OUTSTATE_SENDING 2
/* Stream is a special type of pipe. Implementation of the virtual pipe API. */
static int nn_sipc_send (struct nn_pipebase *self, struct nn_msg *msg);
static int nn_sipc_recv (struct nn_pipebase *self, struct nn_msg *msg);
const struct nn_pipebase_vfptr nn_sipc_pipebase_vfptr = {
nn_sipc_send,
nn_sipc_recv
};
/* Private functions. */
static void nn_sipc_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_sipc_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
void nn_sipc_init (struct nn_sipc *self, int src,
struct nn_epbase *epbase, struct nn_fsm *owner)
{
nn_fsm_init (&self->fsm, nn_sipc_handler, nn_sipc_shutdown,
src, self, owner);
self->state = NN_SIPC_STATE_IDLE;
nn_streamhdr_init (&self->streamhdr, NN_SIPC_SRC_STREAMHDR, &self->fsm);
self->usock = NULL;
self->usock_owner.src = -1;
self->usock_owner.fsm = NULL;
nn_pipebase_init (&self->pipebase, &nn_sipc_pipebase_vfptr, epbase);
self->instate = -1;
nn_msg_init (&self->inmsg, 0);
self->outstate = -1;
nn_msg_init (&self->outmsg, 0);
nn_fsm_event_init (&self->done);
}
void nn_sipc_term (struct nn_sipc *self)
{
nn_assert_state (self, NN_SIPC_STATE_IDLE);
nn_fsm_event_term (&self->done);
nn_msg_term (&self->outmsg);
nn_msg_term (&self->inmsg);
nn_pipebase_term (&self->pipebase);
nn_streamhdr_term (&self->streamhdr);
nn_fsm_term (&self->fsm);
}
int nn_sipc_isidle (struct nn_sipc *self)
{
return nn_fsm_isidle (&self->fsm);
}
void nn_sipc_start (struct nn_sipc *self, struct nn_usock *usock)
{
/* Take ownership of the underlying socket. */
nn_assert (self->usock == NULL && self->usock_owner.fsm == NULL);
self->usock_owner.src = NN_SIPC_SRC_USOCK;
self->usock_owner.fsm = &self->fsm;
nn_usock_swap_owner (usock, &self->usock_owner);
self->usock = usock;
/* Launch the state machine. */
nn_fsm_start (&self->fsm);
}
void nn_sipc_stop (struct nn_sipc *self)
{
nn_fsm_stop (&self->fsm);
}
static int nn_sipc_send (struct nn_pipebase *self, struct nn_msg *msg)
{
struct nn_sipc *sipc;
struct nn_iovec iov [3];
sipc = nn_cont (self, struct nn_sipc, pipebase);
nn_assert_state (sipc, NN_SIPC_STATE_ACTIVE);
nn_assert (sipc->outstate == NN_SIPC_OUTSTATE_IDLE);
/* Move the message to the local storage. */
nn_msg_term (&sipc->outmsg);
nn_msg_mv (&sipc->outmsg, msg);
/* Serialise the message header. */
sipc->outhdr [0] = NN_SIPC_MSG_NORMAL;
nn_putll (sipc->outhdr + 1, nn_chunkref_size (&sipc->outmsg.sphdr) +
nn_chunkref_size (&sipc->outmsg.body));
/* Start async sending. */
iov [0].iov_base = sipc->outhdr;
iov [0].iov_len = sizeof (sipc->outhdr);
iov [1].iov_base = nn_chunkref_data (&sipc->outmsg.sphdr);
iov [1].iov_len = nn_chunkref_size (&sipc->outmsg.sphdr);
iov [2].iov_base = nn_chunkref_data (&sipc->outmsg.body);
iov [2].iov_len = nn_chunkref_size (&sipc->outmsg.body);
nn_usock_send (sipc->usock, iov, 3);
sipc->outstate = NN_SIPC_OUTSTATE_SENDING;
return 0;
}
static int nn_sipc_recv (struct nn_pipebase *self, struct nn_msg *msg)
{
struct nn_sipc *sipc;
sipc = nn_cont (self, struct nn_sipc, pipebase);
nn_assert_state (sipc, NN_SIPC_STATE_ACTIVE);
nn_assert (sipc->instate == NN_SIPC_INSTATE_HASMSG);
/* Move received message to the user. */
nn_msg_mv (msg, &sipc->inmsg);
nn_msg_init (&sipc->inmsg, 0);
/* Start receiving new message. */
sipc->instate = NN_SIPC_INSTATE_HDR;
nn_usock_recv (sipc->usock, sipc->inhdr, sizeof (sipc->inhdr), NULL);
return 0;
}
static void nn_sipc_shutdown (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_sipc *sipc;
sipc = nn_cont (self, struct nn_sipc, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
nn_pipebase_stop (&sipc->pipebase);
nn_streamhdr_stop (&sipc->streamhdr);
sipc->state = NN_SIPC_STATE_STOPPING;
}
if (nn_slow (sipc->state == NN_SIPC_STATE_STOPPING)) {
if (nn_streamhdr_isidle (&sipc->streamhdr)) {
nn_usock_swap_owner (sipc->usock, &sipc->usock_owner);
sipc->usock = NULL;
sipc->usock_owner.src = -1;
sipc->usock_owner.fsm = NULL;
sipc->state = NN_SIPC_STATE_IDLE;
nn_fsm_stopped (&sipc->fsm, NN_SIPC_STOPPED);
return;
}
return;
}
nn_fsm_bad_state(sipc->state, src, type);
}
static void nn_sipc_handler (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
int rc;
struct nn_sipc *sipc;
uint64_t size;
sipc = nn_cont (self, struct nn_sipc, fsm);
switch (sipc->state) {
/******************************************************************************/
/* IDLE state. */
/******************************************************************************/
case NN_SIPC_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
nn_streamhdr_start (&sipc->streamhdr, sipc->usock,
&sipc->pipebase);
sipc->state = NN_SIPC_STATE_PROTOHDR;
return;
default:
nn_fsm_bad_action (sipc->state, src, type);
}
default:
nn_fsm_bad_source (sipc->state, src, type);
}
/******************************************************************************/
/* PROTOHDR state. */
/******************************************************************************/
case NN_SIPC_STATE_PROTOHDR:
switch (src) {
case NN_SIPC_SRC_STREAMHDR:
switch (type) {
case NN_STREAMHDR_OK:
/* Before moving to the active state stop the streamhdr
state machine. */
nn_streamhdr_stop (&sipc->streamhdr);
sipc->state = NN_SIPC_STATE_STOPPING_STREAMHDR;
return;
case NN_STREAMHDR_ERROR:
/* Raise the error and move directly to the DONE state.
streamhdr object will be stopped later on. */
sipc->state = NN_SIPC_STATE_DONE;
nn_fsm_raise (&sipc->fsm, &sipc->done, NN_SIPC_ERROR);
return;
default:
nn_fsm_bad_action (sipc->state, src, type);
}
default:
nn_fsm_bad_source (sipc->state, src, type);
}
/******************************************************************************/
/* STOPPING_STREAMHDR state. */
/******************************************************************************/
case NN_SIPC_STATE_STOPPING_STREAMHDR:
switch (src) {
case NN_SIPC_SRC_STREAMHDR:
switch (type) {
case NN_STREAMHDR_STOPPED:
/* Start the pipe. */
rc = nn_pipebase_start (&sipc->pipebase);
if (nn_slow (rc < 0)) {
sipc->state = NN_SIPC_STATE_DONE;
nn_fsm_raise (&sipc->fsm, &sipc->done, NN_SIPC_ERROR);
return;
}
/* Start receiving a message in asynchronous manner. */
sipc->instate = NN_SIPC_INSTATE_HDR;
nn_usock_recv (sipc->usock, &sipc->inhdr,
sizeof (sipc->inhdr), NULL);
/* Mark the pipe as available for sending. */
sipc->outstate = NN_SIPC_OUTSTATE_IDLE;
sipc->state = NN_SIPC_STATE_ACTIVE;
return;
default:
nn_fsm_bad_action (sipc->state, src, type);
}
default:
nn_fsm_bad_source (sipc->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/******************************************************************************/
case NN_SIPC_STATE_ACTIVE:
switch (src) {
case NN_SIPC_SRC_USOCK:
switch (type) {
case NN_USOCK_SENT:
/* The message is now fully sent. */
nn_assert (sipc->outstate == NN_SIPC_OUTSTATE_SENDING);
sipc->outstate = NN_SIPC_OUTSTATE_IDLE;
nn_msg_term (&sipc->outmsg);
nn_msg_init (&sipc->outmsg, 0);
nn_pipebase_sent (&sipc->pipebase);
return;
case NN_USOCK_RECEIVED:
switch (sipc->instate) {
case NN_SIPC_INSTATE_HDR:
/* Message header was received. Allocate memory for the
message. */
nn_assert (sipc->inhdr [0] == NN_SIPC_MSG_NORMAL);
size = nn_getll (sipc->inhdr + 1);
nn_msg_term (&sipc->inmsg);
nn_msg_init (&sipc->inmsg, (size_t) size);
/* Special case when size of the message body is 0. */
if (!size) {
sipc->instate = NN_SIPC_INSTATE_HASMSG;
nn_pipebase_received (&sipc->pipebase);
return;
}
/* Start receiving the message body. */
sipc->instate = NN_SIPC_INSTATE_BODY;
nn_usock_recv (sipc->usock,
nn_chunkref_data (&sipc->inmsg.body),
(size_t) size, NULL);
return;
case NN_SIPC_INSTATE_BODY:
/* Message body was received. Notify the owner that it
can receive it. */
sipc->instate = NN_SIPC_INSTATE_HASMSG;
nn_pipebase_received (&sipc->pipebase);
return;
default:
nn_assert (0);
}
case NN_USOCK_SHUTDOWN:
nn_pipebase_stop (&sipc->pipebase);
sipc->state = NN_SIPC_STATE_SHUTTING_DOWN;
return;
case NN_USOCK_ERROR:
nn_pipebase_stop (&sipc->pipebase);
sipc->state = NN_SIPC_STATE_DONE;
nn_fsm_raise (&sipc->fsm, &sipc->done, NN_SIPC_ERROR);
return;
default:
nn_fsm_bad_action (sipc->state, src, type);
}
default:
nn_fsm_bad_source (sipc->state, src, type);
}
/******************************************************************************/
/* SHUTTING_DOWN state. */
/* The underlying connection is closed. We are just waiting that underlying */
/* usock being closed */
/******************************************************************************/
case NN_SIPC_STATE_SHUTTING_DOWN:
switch (src) {
case NN_SIPC_SRC_USOCK:
switch (type) {
case NN_USOCK_ERROR:
sipc->state = NN_SIPC_STATE_DONE;
nn_fsm_raise (&sipc->fsm, &sipc->done, NN_SIPC_ERROR);
return;
default:
nn_fsm_bad_action (sipc->state, src, type);
}
default:
nn_fsm_bad_source (sipc->state, src, type);
}
/******************************************************************************/
/* DONE state. */
/* The underlying connection is closed. There's nothing that can be done in */
/* this state except stopping the object. */
/******************************************************************************/
case NN_SIPC_STATE_DONE:
nn_fsm_bad_source (sipc->state, src, type);
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (sipc->state, src, type);
}
}
nanomsg-0.8-beta/src/transports/tcp/0000775000175000017500000000000012623652617020446 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/transports/tcp/atcp.h0000664000175000017500000000516512623652600021545 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_ATCP_INCLUDED
#define NN_ATCP_INCLUDED
#include "stcp.h"
#include "../../transport.h"
#include "../../aio/fsm.h"
#include "../../aio/usock.h"
#include "../../utils/list.h"
/* State machine handling accepted TCP sockets. */
/* In btcp, some events are just *assumed* to come from a child atcp object.
By using non-trivial event codes, we can do more reliable sanity checking
in such scenarios. */
#define NN_ATCP_ACCEPTED 34231
#define NN_ATCP_ERROR 34232
#define NN_ATCP_STOPPED 34233
struct nn_atcp {
/* The state machine. */
struct nn_fsm fsm;
int state;
/* Pointer to the associated endpoint. */
struct nn_epbase *epbase;
/* Underlying socket. */
struct nn_usock usock;
/* Listening socket. Valid only while accepting new connection. */
struct nn_usock *listener;
struct nn_fsm_owner listener_owner;
/* State machine that takes care of the connection in the active state. */
struct nn_stcp stcp;
/* Events generated by atcp state machine. */
struct nn_fsm_event accepted;
struct nn_fsm_event done;
/* This member can be used by owner to keep individual atcps in a list. */
struct nn_list_item item;
};
void nn_atcp_init (struct nn_atcp *self, int src,
struct nn_epbase *epbase, struct nn_fsm *owner);
void nn_atcp_term (struct nn_atcp *self);
int nn_atcp_isidle (struct nn_atcp *self);
void nn_atcp_start (struct nn_atcp *self, struct nn_usock *listener);
void nn_atcp_stop (struct nn_atcp *self);
#endif
nanomsg-0.8-beta/src/transports/tcp/atcp.c0000664000175000017500000002526512623652600021543 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "atcp.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/attr.h"
#define NN_ATCP_STATE_IDLE 1
#define NN_ATCP_STATE_ACCEPTING 2
#define NN_ATCP_STATE_ACTIVE 3
#define NN_ATCP_STATE_STOPPING_STCP 4
#define NN_ATCP_STATE_STOPPING_USOCK 5
#define NN_ATCP_STATE_DONE 6
#define NN_ATCP_STATE_STOPPING_STCP_FINAL 7
#define NN_ATCP_STATE_STOPPING 8
#define NN_ATCP_SRC_USOCK 1
#define NN_ATCP_SRC_STCP 2
#define NN_ATCP_SRC_LISTENER 3
/* Private functions. */
static void nn_atcp_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_atcp_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
void nn_atcp_init (struct nn_atcp *self, int src,
struct nn_epbase *epbase, struct nn_fsm *owner)
{
nn_fsm_init (&self->fsm, nn_atcp_handler, nn_atcp_shutdown,
src, self, owner);
self->state = NN_ATCP_STATE_IDLE;
self->epbase = epbase;
nn_usock_init (&self->usock, NN_ATCP_SRC_USOCK, &self->fsm);
self->listener = NULL;
self->listener_owner.src = -1;
self->listener_owner.fsm = NULL;
nn_stcp_init (&self->stcp, NN_ATCP_SRC_STCP, epbase, &self->fsm);
nn_fsm_event_init (&self->accepted);
nn_fsm_event_init (&self->done);
nn_list_item_init (&self->item);
}
void nn_atcp_term (struct nn_atcp *self)
{
nn_assert_state (self, NN_ATCP_STATE_IDLE);
nn_list_item_term (&self->item);
nn_fsm_event_term (&self->done);
nn_fsm_event_term (&self->accepted);
nn_stcp_term (&self->stcp);
nn_usock_term (&self->usock);
nn_fsm_term (&self->fsm);
}
int nn_atcp_isidle (struct nn_atcp *self)
{
return nn_fsm_isidle (&self->fsm);
}
void nn_atcp_start (struct nn_atcp *self, struct nn_usock *listener)
{
nn_assert_state (self, NN_ATCP_STATE_IDLE);
/* Take ownership of the listener socket. */
self->listener = listener;
self->listener_owner.src = NN_ATCP_SRC_LISTENER;
self->listener_owner.fsm = &self->fsm;
nn_usock_swap_owner (listener, &self->listener_owner);
/* Start the state machine. */
nn_fsm_start (&self->fsm);
}
void nn_atcp_stop (struct nn_atcp *self)
{
nn_fsm_stop (&self->fsm);
}
static void nn_atcp_shutdown (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_atcp *atcp;
atcp = nn_cont (self, struct nn_atcp, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
if (!nn_stcp_isidle (&atcp->stcp)) {
nn_epbase_stat_increment (atcp->epbase,
NN_STAT_DROPPED_CONNECTIONS, 1);
nn_stcp_stop (&atcp->stcp);
}
atcp->state = NN_ATCP_STATE_STOPPING_STCP_FINAL;
}
if (nn_slow (atcp->state == NN_ATCP_STATE_STOPPING_STCP_FINAL)) {
if (!nn_stcp_isidle (&atcp->stcp))
return;
nn_usock_stop (&atcp->usock);
atcp->state = NN_ATCP_STATE_STOPPING;
}
if (nn_slow (atcp->state == NN_ATCP_STATE_STOPPING)) {
if (!nn_usock_isidle (&atcp->usock))
return;
if (atcp->listener) {
nn_assert (atcp->listener_owner.fsm);
nn_usock_swap_owner (atcp->listener, &atcp->listener_owner);
atcp->listener = NULL;
atcp->listener_owner.src = -1;
atcp->listener_owner.fsm = NULL;
}
atcp->state = NN_ATCP_STATE_IDLE;
nn_fsm_stopped (&atcp->fsm, NN_ATCP_STOPPED);
return;
}
nn_fsm_bad_action(atcp->state, src, type);
}
static void nn_atcp_handler (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_atcp *atcp;
int val;
size_t sz;
atcp = nn_cont (self, struct nn_atcp, fsm);
switch (atcp->state) {
/******************************************************************************/
/* IDLE state. */
/* The state machine wasn't yet started. */
/******************************************************************************/
case NN_ATCP_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
nn_usock_accept (&atcp->usock, atcp->listener);
atcp->state = NN_ATCP_STATE_ACCEPTING;
return;
default:
nn_fsm_bad_action (atcp->state, src, type);
}
default:
nn_fsm_bad_source (atcp->state, src, type);
}
/******************************************************************************/
/* ACCEPTING state. */
/* Waiting for incoming connection. */
/******************************************************************************/
case NN_ATCP_STATE_ACCEPTING:
switch (src) {
case NN_ATCP_SRC_USOCK:
switch (type) {
case NN_USOCK_ACCEPTED:
nn_epbase_clear_error (atcp->epbase);
/* Set the relevant socket options. */
sz = sizeof (val);
nn_epbase_getopt (atcp->epbase, NN_SOL_SOCKET, NN_SNDBUF,
&val, &sz);
nn_assert (sz == sizeof (val));
nn_usock_setsockopt (&atcp->usock, SOL_SOCKET, SO_SNDBUF,
&val, sizeof (val));
sz = sizeof (val);
nn_epbase_getopt (atcp->epbase, NN_SOL_SOCKET, NN_RCVBUF,
&val, &sz);
nn_assert (sz == sizeof (val));
nn_usock_setsockopt (&atcp->usock, SOL_SOCKET, SO_RCVBUF,
&val, sizeof (val));
/* Return ownership of the listening socket to the parent. */
nn_usock_swap_owner (atcp->listener, &atcp->listener_owner);
atcp->listener = NULL;
atcp->listener_owner.src = -1;
atcp->listener_owner.fsm = NULL;
nn_fsm_raise (&atcp->fsm, &atcp->accepted, NN_ATCP_ACCEPTED);
/* Start the stcp state machine. */
nn_usock_activate (&atcp->usock);
nn_stcp_start (&atcp->stcp, &atcp->usock);
atcp->state = NN_ATCP_STATE_ACTIVE;
nn_epbase_stat_increment (atcp->epbase,
NN_STAT_ACCEPTED_CONNECTIONS, 1);
return;
default:
nn_fsm_bad_action (atcp->state, src, type);
}
case NN_ATCP_SRC_LISTENER:
switch (type) {
case NN_USOCK_ACCEPT_ERROR:
nn_epbase_set_error (atcp->epbase,
nn_usock_geterrno(atcp->listener));
nn_epbase_stat_increment (atcp->epbase,
NN_STAT_ACCEPT_ERRORS, 1);
nn_usock_accept (&atcp->usock, atcp->listener);
return;
default:
nn_fsm_bad_action (atcp->state, src, type);
}
default:
nn_fsm_bad_source (atcp->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/******************************************************************************/
case NN_ATCP_STATE_ACTIVE:
switch (src) {
case NN_ATCP_SRC_STCP:
switch (type) {
case NN_STCP_ERROR:
nn_stcp_stop (&atcp->stcp);
atcp->state = NN_ATCP_STATE_STOPPING_STCP;
nn_epbase_stat_increment (atcp->epbase,
NN_STAT_BROKEN_CONNECTIONS, 1);
return;
default:
nn_fsm_bad_action (atcp->state, src, type);
}
default:
nn_fsm_bad_source (atcp->state, src, type);
}
/******************************************************************************/
/* STOPPING_STCP state. */
/******************************************************************************/
case NN_ATCP_STATE_STOPPING_STCP:
switch (src) {
case NN_ATCP_SRC_STCP:
switch (type) {
case NN_USOCK_SHUTDOWN:
return;
case NN_STCP_STOPPED:
nn_usock_stop (&atcp->usock);
atcp->state = NN_ATCP_STATE_STOPPING_USOCK;
return;
default:
nn_fsm_bad_action (atcp->state, src, type);
}
default:
nn_fsm_bad_source (atcp->state, src, type);
}
/******************************************************************************/
/* STOPPING_USOCK state. */
/******************************************************************************/
case NN_ATCP_STATE_STOPPING_USOCK:
switch (src) {
case NN_ATCP_SRC_USOCK:
switch (type) {
case NN_USOCK_SHUTDOWN:
return;
case NN_USOCK_STOPPED:
nn_fsm_raise (&atcp->fsm, &atcp->done, NN_ATCP_ERROR);
atcp->state = NN_ATCP_STATE_DONE;
return;
default:
nn_fsm_bad_action (atcp->state, src, type);
}
default:
nn_fsm_bad_source (atcp->state, src, type);
}
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (atcp->state, src, type);
}
}
nanomsg-0.8-beta/src/transports/tcp/btcp.h0000664000175000017500000000250612623652600021542 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_BTCP_INCLUDED
#define NN_BTCP_INCLUDED
#include "../../transport.h"
/* State machine managing bound TCP socket. */
int nn_btcp_create (void *hint, struct nn_epbase **epbase);
#endif
nanomsg-0.8-beta/src/transports/tcp/btcp.c0000664000175000017500000003755112623652600021545 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "btcp.h"
#include "atcp.h"
#include "../utils/port.h"
#include "../utils/iface.h"
#include "../../aio/fsm.h"
#include "../../aio/usock.h"
#include "../utils/backoff.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/alloc.h"
#include "../../utils/list.h"
#include "../../utils/fast.h"
#include "../../utils/int.h"
#include
#if defined NN_HAVE_WINDOWS
#include "../../utils/win.h"
#else
#include
#include
#endif
/* The backlog is set relatively high so that there are not too many failed
connection attemps during re-connection storms. */
#define NN_BTCP_BACKLOG 100
#define NN_BTCP_STATE_IDLE 1
#define NN_BTCP_STATE_ACTIVE 2
#define NN_BTCP_STATE_STOPPING_ATCP 3
#define NN_BTCP_STATE_STOPPING_USOCK 4
#define NN_BTCP_STATE_STOPPING_ATCPS 5
#define NN_BTCP_STATE_LISTENING 6
#define NN_BTCP_STATE_WAITING 7
#define NN_BTCP_STATE_CLOSING 8
#define NN_BTCP_STATE_STOPPING_BACKOFF 9
#define NN_BTCP_SRC_USOCK 1
#define NN_BTCP_SRC_ATCP 2
#define NN_BTCP_SRC_RECONNECT_TIMER 3
struct nn_btcp {
/* The state machine. */
struct nn_fsm fsm;
int state;
/* This object is a specific type of endpoint.
Thus it is derived from epbase. */
struct nn_epbase epbase;
/* The underlying listening TCP socket. */
struct nn_usock usock;
/* The connection being accepted at the moment. */
struct nn_atcp *atcp;
/* List of accepted connections. */
struct nn_list atcps;
/* Used to wait before retrying to connect. */
struct nn_backoff retry;
};
/* nn_epbase virtual interface implementation. */
static void nn_btcp_stop (struct nn_epbase *self);
static void nn_btcp_destroy (struct nn_epbase *self);
const struct nn_epbase_vfptr nn_btcp_epbase_vfptr = {
nn_btcp_stop,
nn_btcp_destroy
};
/* Private functions. */
static void nn_btcp_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_btcp_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_btcp_start_listening (struct nn_btcp *self);
static void nn_btcp_start_accepting (struct nn_btcp *self);
int nn_btcp_create (void *hint, struct nn_epbase **epbase)
{
int rc;
struct nn_btcp *self;
const char *addr;
const char *end;
const char *pos;
struct sockaddr_storage ss;
size_t sslen;
int ipv4only;
size_t ipv4onlylen;
int reconnect_ivl;
int reconnect_ivl_max;
size_t sz;
/* Allocate the new endpoint object. */
self = nn_alloc (sizeof (struct nn_btcp), "btcp");
alloc_assert (self);
/* Initalise the epbase. */
nn_epbase_init (&self->epbase, &nn_btcp_epbase_vfptr, hint);
addr = nn_epbase_getaddr (&self->epbase);
/* Parse the port. */
end = addr + strlen (addr);
pos = strrchr (addr, ':');
if (nn_slow (!pos)) {
nn_epbase_term (&self->epbase);
return -EINVAL;
}
++pos;
rc = nn_port_resolve (pos, end - pos);
if (nn_slow (rc < 0)) {
nn_epbase_term (&self->epbase);
return -EINVAL;
}
/* Check whether IPv6 is to be used. */
ipv4onlylen = sizeof (ipv4only);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
&ipv4only, &ipv4onlylen);
nn_assert (ipv4onlylen == sizeof (ipv4only));
/* Parse the address. */
rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen);
if (nn_slow (rc < 0)) {
nn_epbase_term (&self->epbase);
return -ENODEV;
}
/* Initialise the structure. */
nn_fsm_init_root (&self->fsm, nn_btcp_handler, nn_btcp_shutdown,
nn_epbase_getctx (&self->epbase));
self->state = NN_BTCP_STATE_IDLE;
sz = sizeof (reconnect_ivl);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL,
&reconnect_ivl, &sz);
nn_assert (sz == sizeof (reconnect_ivl));
sz = sizeof (reconnect_ivl_max);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX,
&reconnect_ivl_max, &sz);
nn_assert (sz == sizeof (reconnect_ivl_max));
if (reconnect_ivl_max == 0)
reconnect_ivl_max = reconnect_ivl;
nn_backoff_init (&self->retry, NN_BTCP_SRC_RECONNECT_TIMER,
reconnect_ivl, reconnect_ivl_max, &self->fsm);
nn_usock_init (&self->usock, NN_BTCP_SRC_USOCK, &self->fsm);
self->atcp = NULL;
nn_list_init (&self->atcps);
/* Start the state machine. */
nn_fsm_start (&self->fsm);
/* Return the base class as an out parameter. */
*epbase = &self->epbase;
return 0;
}
static void nn_btcp_stop (struct nn_epbase *self)
{
struct nn_btcp *btcp;
btcp = nn_cont (self, struct nn_btcp, epbase);
nn_fsm_stop (&btcp->fsm);
}
static void nn_btcp_destroy (struct nn_epbase *self)
{
struct nn_btcp *btcp;
btcp = nn_cont (self, struct nn_btcp, epbase);
nn_assert_state (btcp, NN_BTCP_STATE_IDLE);
nn_list_term (&btcp->atcps);
nn_assert (btcp->atcp == NULL);
nn_usock_term (&btcp->usock);
nn_backoff_term (&btcp->retry);
nn_epbase_term (&btcp->epbase);
nn_fsm_term (&btcp->fsm);
nn_free (btcp);
}
static void nn_btcp_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr)
{
struct nn_btcp *btcp;
struct nn_list_item *it;
struct nn_atcp *atcp;
btcp = nn_cont (self, struct nn_btcp, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
nn_backoff_stop (&btcp->retry);
if (btcp->atcp) {
nn_atcp_stop (btcp->atcp);
btcp->state = NN_BTCP_STATE_STOPPING_ATCP;
}
else {
btcp->state = NN_BTCP_STATE_STOPPING_USOCK;
}
}
if (nn_slow (btcp->state == NN_BTCP_STATE_STOPPING_ATCP)) {
if (!nn_atcp_isidle (btcp->atcp))
return;
nn_atcp_term (btcp->atcp);
nn_free (btcp->atcp);
btcp->atcp = NULL;
nn_usock_stop (&btcp->usock);
btcp->state = NN_BTCP_STATE_STOPPING_USOCK;
}
if (nn_slow (btcp->state == NN_BTCP_STATE_STOPPING_USOCK)) {
if (!nn_usock_isidle (&btcp->usock) ||
!nn_backoff_isidle (&btcp->retry))
return;
for (it = nn_list_begin (&btcp->atcps);
it != nn_list_end (&btcp->atcps);
it = nn_list_next (&btcp->atcps, it)) {
atcp = nn_cont (it, struct nn_atcp, item);
nn_atcp_stop (atcp);
}
btcp->state = NN_BTCP_STATE_STOPPING_ATCPS;
goto atcps_stopping;
}
if (nn_slow (btcp->state == NN_BTCP_STATE_STOPPING_ATCPS)) {
nn_assert (src == NN_BTCP_SRC_ATCP && type == NN_ATCP_STOPPED);
atcp = (struct nn_atcp *) srcptr;
nn_list_erase (&btcp->atcps, &atcp->item);
nn_atcp_term (atcp);
nn_free (atcp);
/* If there are no more atcp state machines, we can stop the whole
btcp object. */
atcps_stopping:
if (nn_list_empty (&btcp->atcps)) {
btcp->state = NN_BTCP_STATE_IDLE;
nn_fsm_stopped_noevent (&btcp->fsm);
nn_epbase_stopped (&btcp->epbase);
return;
}
return;
}
nn_fsm_bad_action(btcp->state, src, type);
}
static void nn_btcp_handler (struct nn_fsm *self, int src, int type,
void *srcptr)
{
struct nn_btcp *btcp;
struct nn_atcp *atcp;
btcp = nn_cont (self, struct nn_btcp, fsm);
switch (btcp->state) {
/******************************************************************************/
/* IDLE state. */
/******************************************************************************/
case NN_BTCP_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
nn_btcp_start_listening (btcp);
return;
default:
nn_fsm_bad_action (btcp->state, src, type);
}
default:
nn_fsm_bad_source (btcp->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/* The execution is yielded to the atcp state machine in this state. */
/******************************************************************************/
case NN_BTCP_STATE_ACTIVE:
if (srcptr == btcp->atcp) {
switch (type) {
case NN_ATCP_ACCEPTED:
/* Move the newly created connection to the list of existing
connections. */
nn_list_insert (&btcp->atcps, &btcp->atcp->item,
nn_list_end (&btcp->atcps));
btcp->atcp = NULL;
/* Start waiting for a new incoming connection. */
nn_btcp_start_accepting (btcp);
return;
default:
nn_fsm_bad_action (btcp->state, src, type);
}
}
/* For all remaining events we'll assume they are coming from one
of remaining child atcp objects. */
nn_assert (src == NN_BTCP_SRC_ATCP);
atcp = (struct nn_atcp*) srcptr;
switch (type) {
case NN_ATCP_ERROR:
nn_atcp_stop (atcp);
return;
case NN_ATCP_STOPPED:
nn_list_erase (&btcp->atcps, &atcp->item);
nn_atcp_term (atcp);
nn_free (atcp);
return;
default:
nn_fsm_bad_action (btcp->state, src, type);
}
/******************************************************************************/
/* CLOSING_USOCK state. */
/* usock object was asked to stop but it haven't stopped yet. */
/******************************************************************************/
case NN_BTCP_STATE_CLOSING:
switch (src) {
case NN_BTCP_SRC_USOCK:
switch (type) {
case NN_USOCK_SHUTDOWN:
return;
case NN_USOCK_STOPPED:
nn_backoff_start (&btcp->retry);
btcp->state = NN_BTCP_STATE_WAITING;
return;
default:
nn_fsm_bad_action (btcp->state, src, type);
}
default:
nn_fsm_bad_source (btcp->state, src, type);
}
/******************************************************************************/
/* WAITING state. */
/* Waiting before re-bind is attempted. This way we won't overload */
/* the system by continuous re-bind attemps. */
/******************************************************************************/
case NN_BTCP_STATE_WAITING:
switch (src) {
case NN_BTCP_SRC_RECONNECT_TIMER:
switch (type) {
case NN_BACKOFF_TIMEOUT:
nn_backoff_stop (&btcp->retry);
btcp->state = NN_BTCP_STATE_STOPPING_BACKOFF;
return;
default:
nn_fsm_bad_action (btcp->state, src, type);
}
default:
nn_fsm_bad_source (btcp->state, src, type);
}
/******************************************************************************/
/* STOPPING_BACKOFF state. */
/* backoff object was asked to stop, but it haven't stopped yet. */
/******************************************************************************/
case NN_BTCP_STATE_STOPPING_BACKOFF:
switch (src) {
case NN_BTCP_SRC_RECONNECT_TIMER:
switch (type) {
case NN_BACKOFF_STOPPED:
nn_btcp_start_listening (btcp);
return;
default:
nn_fsm_bad_action (btcp->state, src, type);
}
default:
nn_fsm_bad_source (btcp->state, src, type);
}
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (btcp->state, src, type);
}
}
/******************************************************************************/
/* State machine actions. */
/******************************************************************************/
static void nn_btcp_start_listening (struct nn_btcp *self)
{
int rc;
struct sockaddr_storage ss;
size_t sslen;
int ipv4only;
size_t ipv4onlylen;
const char *addr;
const char *end;
const char *pos;
uint16_t port;
/* First, resolve the IP address. */
addr = nn_epbase_getaddr (&self->epbase);
memset (&ss, 0, sizeof (ss));
/* Parse the port. */
end = addr + strlen (addr);
pos = strrchr (addr, ':');
nn_assert (pos);
++pos;
rc = nn_port_resolve (pos, end - pos);
nn_assert (rc >= 0);
port = rc;
/* Parse the address. */
ipv4onlylen = sizeof (ipv4only);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
&ipv4only, &ipv4onlylen);
nn_assert (ipv4onlylen == sizeof (ipv4only));
rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen);
errnum_assert (rc == 0, -rc);
/* Combine the port and the address. */
if (ss.ss_family == AF_INET) {
((struct sockaddr_in*) &ss)->sin_port = htons (port);
sslen = sizeof (struct sockaddr_in);
}
else if (ss.ss_family == AF_INET6) {
((struct sockaddr_in6*) &ss)->sin6_port = htons (port);
sslen = sizeof (struct sockaddr_in6);
}
else
nn_assert (0);
/* Start listening for incoming connections. */
rc = nn_usock_start (&self->usock, ss.ss_family, SOCK_STREAM, 0);
if (nn_slow (rc < 0)) {
nn_backoff_start (&self->retry);
self->state = NN_BTCP_STATE_WAITING;
return;
}
rc = nn_usock_bind (&self->usock, (struct sockaddr*) &ss, (size_t) sslen);
if (nn_slow (rc < 0)) {
nn_usock_stop (&self->usock);
self->state = NN_BTCP_STATE_CLOSING;
return;
}
rc = nn_usock_listen (&self->usock, NN_BTCP_BACKLOG);
if (nn_slow (rc < 0)) {
nn_usock_stop (&self->usock);
self->state = NN_BTCP_STATE_CLOSING;
return;
}
nn_btcp_start_accepting(self);
self->state = NN_BTCP_STATE_ACTIVE;
}
static void nn_btcp_start_accepting (struct nn_btcp *self)
{
nn_assert (self->atcp == NULL);
/* Allocate new atcp state machine. */
self->atcp = nn_alloc (sizeof (struct nn_atcp), "atcp");
alloc_assert (self->atcp);
nn_atcp_init (self->atcp, NN_BTCP_SRC_ATCP, &self->epbase, &self->fsm);
/* Start waiting for a new incoming connection. */
nn_atcp_start (self->atcp, &self->usock);
}
nanomsg-0.8-beta/src/transports/tcp/ctcp.h0000664000175000017500000000251212623652600021540 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_CTCP_INCLUDED
#define NN_CTCP_INCLUDED
#include "../../transport.h"
/* State machine managing connected TCP socket. */
int nn_ctcp_create (void *hint, struct nn_epbase **epbase);
#endif
nanomsg-0.8-beta/src/transports/tcp/ctcp.c0000664000175000017500000005157612623652600021551 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "ctcp.h"
#include "stcp.h"
#include "../../tcp.h"
#include "../utils/dns.h"
#include "../utils/port.h"
#include "../utils/iface.h"
#include "../utils/backoff.h"
#include "../utils/literal.h"
#include "../../aio/fsm.h"
#include "../../aio/usock.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/alloc.h"
#include "../../utils/fast.h"
#include "../../utils/int.h"
#include "../../utils/attr.h"
#include
#if defined NN_HAVE_WINDOWS
#include "../../utils/win.h"
#else
#include
#include
#include
#endif
#define NN_CTCP_STATE_IDLE 1
#define NN_CTCP_STATE_RESOLVING 2
#define NN_CTCP_STATE_STOPPING_DNS 3
#define NN_CTCP_STATE_CONNECTING 4
#define NN_CTCP_STATE_ACTIVE 5
#define NN_CTCP_STATE_STOPPING_STCP 6
#define NN_CTCP_STATE_STOPPING_USOCK 7
#define NN_CTCP_STATE_WAITING 8
#define NN_CTCP_STATE_STOPPING_BACKOFF 9
#define NN_CTCP_STATE_STOPPING_STCP_FINAL 10
#define NN_CTCP_STATE_STOPPING 11
#define NN_CTCP_SRC_USOCK 1
#define NN_CTCP_SRC_RECONNECT_TIMER 2
#define NN_CTCP_SRC_DNS 3
#define NN_CTCP_SRC_STCP 4
struct nn_ctcp {
/* The state machine. */
struct nn_fsm fsm;
int state;
/* This object is a specific type of endpoint.
Thus it is derived from epbase. */
struct nn_epbase epbase;
/* The underlying TCP socket. */
struct nn_usock usock;
/* Used to wait before retrying to connect. */
struct nn_backoff retry;
/* State machine that handles the active part of the connection
lifetime. */
struct nn_stcp stcp;
/* DNS resolver used to convert textual address into actual IP address
along with the variable to hold the result. */
struct nn_dns dns;
struct nn_dns_result dns_result;
};
/* nn_epbase virtual interface implementation. */
static void nn_ctcp_stop (struct nn_epbase *self);
static void nn_ctcp_destroy (struct nn_epbase *self);
const struct nn_epbase_vfptr nn_ctcp_epbase_vfptr = {
nn_ctcp_stop,
nn_ctcp_destroy
};
/* Private functions. */
static void nn_ctcp_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_ctcp_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_ctcp_start_resolving (struct nn_ctcp *self);
static void nn_ctcp_start_connecting (struct nn_ctcp *self,
struct sockaddr_storage *ss, size_t sslen);
int nn_ctcp_create (void *hint, struct nn_epbase **epbase)
{
int rc;
const char *addr;
size_t addrlen;
const char *semicolon;
const char *hostname;
const char *colon;
const char *end;
struct sockaddr_storage ss;
size_t sslen;
int ipv4only;
size_t ipv4onlylen;
struct nn_ctcp *self;
int reconnect_ivl;
int reconnect_ivl_max;
size_t sz;
/* Allocate the new endpoint object. */
self = nn_alloc (sizeof (struct nn_ctcp), "ctcp");
alloc_assert (self);
/* Initalise the endpoint. */
nn_epbase_init (&self->epbase, &nn_ctcp_epbase_vfptr, hint);
/* Check whether IPv6 is to be used. */
ipv4onlylen = sizeof (ipv4only);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
&ipv4only, &ipv4onlylen);
nn_assert (ipv4onlylen == sizeof (ipv4only));
/* Start parsing the address. */
addr = nn_epbase_getaddr (&self->epbase);
addrlen = strlen (addr);
semicolon = strchr (addr, ';');
hostname = semicolon ? semicolon + 1 : addr;
colon = strrchr (addr, ':');
end = addr + addrlen;
/* Parse the port. */
if (nn_slow (!colon)) {
nn_epbase_term (&self->epbase);
return -EINVAL;
}
rc = nn_port_resolve (colon + 1, end - colon - 1);
if (nn_slow (rc < 0)) {
nn_epbase_term (&self->epbase);
return -EINVAL;
}
/* Check whether the host portion of the address is either a literal
or a valid hostname. */
if (nn_dns_check_hostname (hostname, colon - hostname) < 0 &&
nn_literal_resolve (hostname, colon - hostname, ipv4only,
&ss, &sslen) < 0) {
nn_epbase_term (&self->epbase);
return -EINVAL;
}
/* If local address is specified, check whether it is valid. */
if (semicolon) {
rc = nn_iface_resolve (addr, semicolon - addr, ipv4only, &ss, &sslen);
if (rc < 0) {
nn_epbase_term (&self->epbase);
return -ENODEV;
}
}
/* Initialise the structure. */
nn_fsm_init_root (&self->fsm, nn_ctcp_handler, nn_ctcp_shutdown,
nn_epbase_getctx (&self->epbase));
self->state = NN_CTCP_STATE_IDLE;
nn_usock_init (&self->usock, NN_CTCP_SRC_USOCK, &self->fsm);
sz = sizeof (reconnect_ivl);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL,
&reconnect_ivl, &sz);
nn_assert (sz == sizeof (reconnect_ivl));
sz = sizeof (reconnect_ivl_max);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX,
&reconnect_ivl_max, &sz);
nn_assert (sz == sizeof (reconnect_ivl_max));
if (reconnect_ivl_max == 0)
reconnect_ivl_max = reconnect_ivl;
nn_backoff_init (&self->retry, NN_CTCP_SRC_RECONNECT_TIMER,
reconnect_ivl, reconnect_ivl_max, &self->fsm);
nn_stcp_init (&self->stcp, NN_CTCP_SRC_STCP, &self->epbase, &self->fsm);
nn_dns_init (&self->dns, NN_CTCP_SRC_DNS, &self->fsm);
/* Start the state machine. */
nn_fsm_start (&self->fsm);
/* Return the base class as an out parameter. */
*epbase = &self->epbase;
return 0;
}
static void nn_ctcp_stop (struct nn_epbase *self)
{
struct nn_ctcp *ctcp;
ctcp = nn_cont (self, struct nn_ctcp, epbase);
nn_fsm_stop (&ctcp->fsm);
}
static void nn_ctcp_destroy (struct nn_epbase *self)
{
struct nn_ctcp *ctcp;
ctcp = nn_cont (self, struct nn_ctcp, epbase);
nn_dns_term (&ctcp->dns);
nn_stcp_term (&ctcp->stcp);
nn_backoff_term (&ctcp->retry);
nn_usock_term (&ctcp->usock);
nn_fsm_term (&ctcp->fsm);
nn_epbase_term (&ctcp->epbase);
nn_free (ctcp);
}
static void nn_ctcp_shutdown (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_ctcp *ctcp;
ctcp = nn_cont (self, struct nn_ctcp, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
if (!nn_stcp_isidle (&ctcp->stcp)) {
nn_epbase_stat_increment (&ctcp->epbase,
NN_STAT_DROPPED_CONNECTIONS, 1);
nn_stcp_stop (&ctcp->stcp);
}
ctcp->state = NN_CTCP_STATE_STOPPING_STCP_FINAL;
}
if (nn_slow (ctcp->state == NN_CTCP_STATE_STOPPING_STCP_FINAL)) {
if (!nn_stcp_isidle (&ctcp->stcp))
return;
nn_backoff_stop (&ctcp->retry);
nn_usock_stop (&ctcp->usock);
nn_dns_stop (&ctcp->dns);
ctcp->state = NN_CTCP_STATE_STOPPING;
}
if (nn_slow (ctcp->state == NN_CTCP_STATE_STOPPING)) {
if (!nn_backoff_isidle (&ctcp->retry) ||
!nn_usock_isidle (&ctcp->usock) ||
!nn_dns_isidle (&ctcp->dns))
return;
ctcp->state = NN_CTCP_STATE_IDLE;
nn_fsm_stopped_noevent (&ctcp->fsm);
nn_epbase_stopped (&ctcp->epbase);
return;
}
nn_fsm_bad_state (ctcp->state, src, type);
}
static void nn_ctcp_handler (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_ctcp *ctcp;
ctcp = nn_cont (self, struct nn_ctcp, fsm);
switch (ctcp->state) {
/******************************************************************************/
/* IDLE state. */
/* The state machine wasn't yet started. */
/******************************************************************************/
case NN_CTCP_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
nn_ctcp_start_resolving (ctcp);
return;
default:
nn_fsm_bad_action (ctcp->state, src, type);
}
default:
nn_fsm_bad_source (ctcp->state, src, type);
}
/******************************************************************************/
/* RESOLVING state. */
/* Name of the host to connect to is being resolved to get an IP address. */
/******************************************************************************/
case NN_CTCP_STATE_RESOLVING:
switch (src) {
case NN_CTCP_SRC_DNS:
switch (type) {
case NN_DNS_DONE:
nn_dns_stop (&ctcp->dns);
ctcp->state = NN_CTCP_STATE_STOPPING_DNS;
return;
default:
nn_fsm_bad_action (ctcp->state, src, type);
}
default:
nn_fsm_bad_source (ctcp->state, src, type);
}
/******************************************************************************/
/* STOPPING_DNS state. */
/* dns object was asked to stop but it haven't stopped yet. */
/******************************************************************************/
case NN_CTCP_STATE_STOPPING_DNS:
switch (src) {
case NN_CTCP_SRC_DNS:
switch (type) {
case NN_DNS_STOPPED:
if (ctcp->dns_result.error == 0) {
nn_ctcp_start_connecting (ctcp, &ctcp->dns_result.addr,
ctcp->dns_result.addrlen);
return;
}
nn_backoff_start (&ctcp->retry);
ctcp->state = NN_CTCP_STATE_WAITING;
return;
default:
nn_fsm_bad_action (ctcp->state, src, type);
}
default:
nn_fsm_bad_source (ctcp->state, src, type);
}
/******************************************************************************/
/* CONNECTING state. */
/* Non-blocking connect is under way. */
/******************************************************************************/
case NN_CTCP_STATE_CONNECTING:
switch (src) {
case NN_CTCP_SRC_USOCK:
switch (type) {
case NN_USOCK_CONNECTED:
nn_stcp_start (&ctcp->stcp, &ctcp->usock);
ctcp->state = NN_CTCP_STATE_ACTIVE;
nn_epbase_stat_increment (&ctcp->epbase,
NN_STAT_INPROGRESS_CONNECTIONS, -1);
nn_epbase_stat_increment (&ctcp->epbase,
NN_STAT_ESTABLISHED_CONNECTIONS, 1);
nn_epbase_clear_error (&ctcp->epbase);
return;
case NN_USOCK_ERROR:
nn_epbase_set_error (&ctcp->epbase,
nn_usock_geterrno (&ctcp->usock));
nn_usock_stop (&ctcp->usock);
ctcp->state = NN_CTCP_STATE_STOPPING_USOCK;
nn_epbase_stat_increment (&ctcp->epbase,
NN_STAT_INPROGRESS_CONNECTIONS, -1);
nn_epbase_stat_increment (&ctcp->epbase,
NN_STAT_CONNECT_ERRORS, 1);
return;
default:
nn_fsm_bad_action (ctcp->state, src, type);
}
default:
nn_fsm_bad_source (ctcp->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/* Connection is established and handled by the stcp state machine. */
/******************************************************************************/
case NN_CTCP_STATE_ACTIVE:
switch (src) {
case NN_CTCP_SRC_STCP:
switch (type) {
case NN_STCP_ERROR:
nn_stcp_stop (&ctcp->stcp);
ctcp->state = NN_CTCP_STATE_STOPPING_STCP;
nn_epbase_stat_increment (&ctcp->epbase,
NN_STAT_BROKEN_CONNECTIONS, 1);
return;
default:
nn_fsm_bad_action (ctcp->state, src, type);
}
default:
nn_fsm_bad_source (ctcp->state, src, type);
}
/******************************************************************************/
/* STOPPING_STCP state. */
/* stcp object was asked to stop but it haven't stopped yet. */
/******************************************************************************/
case NN_CTCP_STATE_STOPPING_STCP:
switch (src) {
case NN_CTCP_SRC_STCP:
switch (type) {
case NN_USOCK_SHUTDOWN:
return;
case NN_STCP_STOPPED:
nn_usock_stop (&ctcp->usock);
ctcp->state = NN_CTCP_STATE_STOPPING_USOCK;
return;
default:
nn_fsm_bad_action (ctcp->state, src, type);
}
default:
nn_fsm_bad_source (ctcp->state, src, type);
}
/******************************************************************************/
/* STOPPING_USOCK state. */
/* usock object was asked to stop but it haven't stopped yet. */
/******************************************************************************/
case NN_CTCP_STATE_STOPPING_USOCK:
switch (src) {
case NN_CTCP_SRC_USOCK:
switch (type) {
case NN_USOCK_SHUTDOWN:
return;
case NN_USOCK_STOPPED:
nn_backoff_start (&ctcp->retry);
ctcp->state = NN_CTCP_STATE_WAITING;
return;
default:
nn_fsm_bad_action (ctcp->state, src, type);
}
default:
nn_fsm_bad_source (ctcp->state, src, type);
}
/******************************************************************************/
/* WAITING state. */
/* Waiting before re-connection is attempted. This way we won't overload */
/* the system by continuous re-connection attemps. */
/******************************************************************************/
case NN_CTCP_STATE_WAITING:
switch (src) {
case NN_CTCP_SRC_RECONNECT_TIMER:
switch (type) {
case NN_BACKOFF_TIMEOUT:
nn_backoff_stop (&ctcp->retry);
ctcp->state = NN_CTCP_STATE_STOPPING_BACKOFF;
return;
default:
nn_fsm_bad_action (ctcp->state, src, type);
}
default:
nn_fsm_bad_source (ctcp->state, src, type);
}
/******************************************************************************/
/* STOPPING_BACKOFF state. */
/* backoff object was asked to stop, but it haven't stopped yet. */
/******************************************************************************/
case NN_CTCP_STATE_STOPPING_BACKOFF:
switch (src) {
case NN_CTCP_SRC_RECONNECT_TIMER:
switch (type) {
case NN_BACKOFF_STOPPED:
nn_ctcp_start_resolving (ctcp);
return;
default:
nn_fsm_bad_action (ctcp->state, src, type);
}
default:
nn_fsm_bad_source (ctcp->state, src, type);
}
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (ctcp->state, src, type);
}
}
/******************************************************************************/
/* State machine actions. */
/******************************************************************************/
static void nn_ctcp_start_resolving (struct nn_ctcp *self)
{
const char *addr;
const char *begin;
const char *end;
int ipv4only;
size_t ipv4onlylen;
/* Extract the hostname part from address string. */
addr = nn_epbase_getaddr (&self->epbase);
begin = strchr (addr, ';');
if (!begin)
begin = addr;
else
++begin;
end = strrchr (addr, ':');
nn_assert (end);
/* Check whether IPv6 is to be used. */
ipv4onlylen = sizeof (ipv4only);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
&ipv4only, &ipv4onlylen);
nn_assert (ipv4onlylen == sizeof (ipv4only));
/* TODO: Get the actual value of IPV4ONLY option. */
nn_dns_start (&self->dns, begin, end - begin, ipv4only, &self->dns_result);
self->state = NN_CTCP_STATE_RESOLVING;
}
static void nn_ctcp_start_connecting (struct nn_ctcp *self,
struct sockaddr_storage *ss, size_t sslen)
{
int rc;
struct sockaddr_storage remote;
size_t remotelen;
struct sockaddr_storage local;
size_t locallen;
const char *addr;
const char *end;
const char *colon;
const char *semicolon;
uint16_t port;
int ipv4only;
size_t ipv4onlylen;
int val;
size_t sz;
/* Create IP address from the address string. */
addr = nn_epbase_getaddr (&self->epbase);
memset (&remote, 0, sizeof (remote));
/* Parse the port. */
end = addr + strlen (addr);
colon = strrchr (addr, ':');
rc = nn_port_resolve (colon + 1, end - colon - 1);
errnum_assert (rc > 0, -rc);
port = rc;
/* Check whether IPv6 is to be used. */
ipv4onlylen = sizeof (ipv4only);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
&ipv4only, &ipv4onlylen);
nn_assert (ipv4onlylen == sizeof (ipv4only));
/* Parse the local address, if any. */
semicolon = strchr (addr, ';');
memset (&local, 0, sizeof (local));
if (semicolon)
rc = nn_iface_resolve (addr, semicolon - addr, ipv4only,
&local, &locallen);
else
rc = nn_iface_resolve ("*", 1, ipv4only, &local, &locallen);
if (nn_slow (rc < 0)) {
nn_backoff_start (&self->retry);
self->state = NN_CTCP_STATE_WAITING;
return;
}
/* Combine the remote address and the port. */
remote = *ss;
remotelen = sslen;
if (remote.ss_family == AF_INET)
((struct sockaddr_in*) &remote)->sin_port = htons (port);
else if (remote.ss_family == AF_INET6)
((struct sockaddr_in6*) &remote)->sin6_port = htons (port);
else
nn_assert (0);
/* Try to start the underlying socket. */
rc = nn_usock_start (&self->usock, remote.ss_family, SOCK_STREAM, 0);
if (nn_slow (rc < 0)) {
nn_backoff_start (&self->retry);
self->state = NN_CTCP_STATE_WAITING;
return;
}
/* Set the relevant socket options. */
sz = sizeof (val);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz);
nn_assert (sz == sizeof (val));
nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_SNDBUF,
&val, sizeof (val));
sz = sizeof (val);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz);
nn_assert (sz == sizeof (val));
nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_RCVBUF,
&val, sizeof (val));
/* Bind the socket to the local network interface. */
rc = nn_usock_bind (&self->usock, (struct sockaddr*) &local, locallen);
if (nn_slow (rc != 0)) {
nn_backoff_start (&self->retry);
self->state = NN_CTCP_STATE_WAITING;
return;
}
/* Start connecting. */
nn_usock_connect (&self->usock, (struct sockaddr*) &remote, remotelen);
self->state = NN_CTCP_STATE_CONNECTING;
nn_epbase_stat_increment (&self->epbase,
NN_STAT_INPROGRESS_CONNECTIONS, 1);
}
nanomsg-0.8-beta/src/transports/tcp/stcp.h0000664000175000017500000000540312623652600021562 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_STCP_INCLUDED
#define NN_STCP_INCLUDED
#include "../../transport.h"
#include "../../aio/fsm.h"
#include "../../aio/usock.h"
#include "../utils/streamhdr.h"
#include "../../utils/msg.h"
/* This state machine handles TCP connection from the point where it is
established to the point when it is broken. */
#define NN_STCP_ERROR 1
#define NN_STCP_STOPPED 2
struct nn_stcp {
/* The state machine. */
struct nn_fsm fsm;
int state;
/* The underlying socket. */
struct nn_usock *usock;
/* Child state machine to do protocol header exchange. */
struct nn_streamhdr streamhdr;
/* The original owner of the underlying socket. */
struct nn_fsm_owner usock_owner;
/* Pipe connecting this TCP connection to the nanomsg core. */
struct nn_pipebase pipebase;
/* State of inbound state machine. */
int instate;
/* Buffer used to store the header of incoming message. */
uint8_t inhdr [8];
/* Message being received at the moment. */
struct nn_msg inmsg;
/* State of the outbound state machine. */
int outstate;
/* Buffer used to store the header of outgoing message. */
uint8_t outhdr [8];
/* Message being sent at the moment. */
struct nn_msg outmsg;
/* Event raised when the state machine ends. */
struct nn_fsm_event done;
};
void nn_stcp_init (struct nn_stcp *self, int src,
struct nn_epbase *epbase, struct nn_fsm *owner);
void nn_stcp_term (struct nn_stcp *self);
int nn_stcp_isidle (struct nn_stcp *self);
void nn_stcp_start (struct nn_stcp *self, struct nn_usock *usock);
void nn_stcp_stop (struct nn_stcp *self);
#endif
nanomsg-0.8-beta/src/transports/tcp/stcp.c0000664000175000017500000003535312623652600021564 0ustar00travistravis00000000000000/*
Copyright (c) 2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "stcp.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/fast.h"
#include "../../utils/wire.h"
#include "../../utils/int.h"
#include "../../utils/attr.h"
/* States of the object as a whole. */
#define NN_STCP_STATE_IDLE 1
#define NN_STCP_STATE_PROTOHDR 2
#define NN_STCP_STATE_STOPPING_STREAMHDR 3
#define NN_STCP_STATE_ACTIVE 4
#define NN_STCP_STATE_SHUTTING_DOWN 5
#define NN_STCP_STATE_DONE 6
#define NN_STCP_STATE_STOPPING 7
/* Possible states of the inbound part of the object. */
#define NN_STCP_INSTATE_HDR 1
#define NN_STCP_INSTATE_BODY 2
#define NN_STCP_INSTATE_HASMSG 3
/* Possible states of the outbound part of the object. */
#define NN_STCP_OUTSTATE_IDLE 1
#define NN_STCP_OUTSTATE_SENDING 2
/* Subordinate srcptr objects. */
#define NN_STCP_SRC_USOCK 1
#define NN_STCP_SRC_STREAMHDR 2
/* Stream is a special type of pipe. Implementation of the virtual pipe API. */
static int nn_stcp_send (struct nn_pipebase *self, struct nn_msg *msg);
static int nn_stcp_recv (struct nn_pipebase *self, struct nn_msg *msg);
const struct nn_pipebase_vfptr nn_stcp_pipebase_vfptr = {
nn_stcp_send,
nn_stcp_recv
};
/* Private functions. */
static void nn_stcp_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_stcp_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
void nn_stcp_init (struct nn_stcp *self, int src,
struct nn_epbase *epbase, struct nn_fsm *owner)
{
nn_fsm_init (&self->fsm, nn_stcp_handler, nn_stcp_shutdown,
src, self, owner);
self->state = NN_STCP_STATE_IDLE;
nn_streamhdr_init (&self->streamhdr, NN_STCP_SRC_STREAMHDR, &self->fsm);
self->usock = NULL;
self->usock_owner.src = -1;
self->usock_owner.fsm = NULL;
nn_pipebase_init (&self->pipebase, &nn_stcp_pipebase_vfptr, epbase);
self->instate = -1;
nn_msg_init (&self->inmsg, 0);
self->outstate = -1;
nn_msg_init (&self->outmsg, 0);
nn_fsm_event_init (&self->done);
}
void nn_stcp_term (struct nn_stcp *self)
{
nn_assert_state (self, NN_STCP_STATE_IDLE);
nn_fsm_event_term (&self->done);
nn_msg_term (&self->outmsg);
nn_msg_term (&self->inmsg);
nn_pipebase_term (&self->pipebase);
nn_streamhdr_term (&self->streamhdr);
nn_fsm_term (&self->fsm);
}
int nn_stcp_isidle (struct nn_stcp *self)
{
return nn_fsm_isidle (&self->fsm);
}
void nn_stcp_start (struct nn_stcp *self, struct nn_usock *usock)
{
/* Take ownership of the underlying socket. */
nn_assert (self->usock == NULL && self->usock_owner.fsm == NULL);
self->usock_owner.src = NN_STCP_SRC_USOCK;
self->usock_owner.fsm = &self->fsm;
nn_usock_swap_owner (usock, &self->usock_owner);
self->usock = usock;
/* Launch the state machine. */
nn_fsm_start (&self->fsm);
}
void nn_stcp_stop (struct nn_stcp *self)
{
nn_fsm_stop (&self->fsm);
}
static int nn_stcp_send (struct nn_pipebase *self, struct nn_msg *msg)
{
struct nn_stcp *stcp;
struct nn_iovec iov [3];
stcp = nn_cont (self, struct nn_stcp, pipebase);
nn_assert_state (stcp, NN_STCP_STATE_ACTIVE);
nn_assert (stcp->outstate == NN_STCP_OUTSTATE_IDLE);
/* Move the message to the local storage. */
nn_msg_term (&stcp->outmsg);
nn_msg_mv (&stcp->outmsg, msg);
/* Serialise the message header. */
nn_putll (stcp->outhdr, nn_chunkref_size (&stcp->outmsg.sphdr) +
nn_chunkref_size (&stcp->outmsg.body));
/* Start async sending. */
iov [0].iov_base = stcp->outhdr;
iov [0].iov_len = sizeof (stcp->outhdr);
iov [1].iov_base = nn_chunkref_data (&stcp->outmsg.sphdr);
iov [1].iov_len = nn_chunkref_size (&stcp->outmsg.sphdr);
iov [2].iov_base = nn_chunkref_data (&stcp->outmsg.body);
iov [2].iov_len = nn_chunkref_size (&stcp->outmsg.body);
nn_usock_send (stcp->usock, iov, 3);
stcp->outstate = NN_STCP_OUTSTATE_SENDING;
return 0;
}
static int nn_stcp_recv (struct nn_pipebase *self, struct nn_msg *msg)
{
struct nn_stcp *stcp;
stcp = nn_cont (self, struct nn_stcp, pipebase);
nn_assert_state (stcp, NN_STCP_STATE_ACTIVE);
nn_assert (stcp->instate == NN_STCP_INSTATE_HASMSG);
/* Move received message to the user. */
nn_msg_mv (msg, &stcp->inmsg);
nn_msg_init (&stcp->inmsg, 0);
/* Start receiving new message. */
stcp->instate = NN_STCP_INSTATE_HDR;
nn_usock_recv (stcp->usock, stcp->inhdr, sizeof (stcp->inhdr), NULL);
return 0;
}
static void nn_stcp_shutdown (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_stcp *stcp;
stcp = nn_cont (self, struct nn_stcp, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
nn_pipebase_stop (&stcp->pipebase);
nn_streamhdr_stop (&stcp->streamhdr);
stcp->state = NN_STCP_STATE_STOPPING;
}
if (nn_slow (stcp->state == NN_STCP_STATE_STOPPING)) {
if (nn_streamhdr_isidle (&stcp->streamhdr)) {
nn_usock_swap_owner (stcp->usock, &stcp->usock_owner);
stcp->usock = NULL;
stcp->usock_owner.src = -1;
stcp->usock_owner.fsm = NULL;
stcp->state = NN_STCP_STATE_IDLE;
nn_fsm_stopped (&stcp->fsm, NN_STCP_STOPPED);
return;
}
return;
}
nn_fsm_bad_state(stcp->state, src, type);
}
static void nn_stcp_handler (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
int rc;
struct nn_stcp *stcp;
uint64_t size;
int opt;
size_t opt_sz = sizeof (opt);
stcp = nn_cont (self, struct nn_stcp, fsm);
switch (stcp->state) {
/******************************************************************************/
/* IDLE state. */
/******************************************************************************/
case NN_STCP_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
nn_streamhdr_start (&stcp->streamhdr, stcp->usock,
&stcp->pipebase);
stcp->state = NN_STCP_STATE_PROTOHDR;
return;
default:
nn_fsm_bad_action (stcp->state, src, type);
}
default:
nn_fsm_bad_source (stcp->state, src, type);
}
/******************************************************************************/
/* PROTOHDR state. */
/******************************************************************************/
case NN_STCP_STATE_PROTOHDR:
switch (src) {
case NN_STCP_SRC_STREAMHDR:
switch (type) {
case NN_STREAMHDR_OK:
/* Before moving to the active state stop the streamhdr
state machine. */
nn_streamhdr_stop (&stcp->streamhdr);
stcp->state = NN_STCP_STATE_STOPPING_STREAMHDR;
return;
case NN_STREAMHDR_ERROR:
/* Raise the error and move directly to the DONE state.
streamhdr object will be stopped later on. */
stcp->state = NN_STCP_STATE_DONE;
nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR);
return;
default:
nn_fsm_bad_action (stcp->state, src, type);
}
default:
nn_fsm_bad_source (stcp->state, src, type);
}
/******************************************************************************/
/* STOPPING_STREAMHDR state. */
/******************************************************************************/
case NN_STCP_STATE_STOPPING_STREAMHDR:
switch (src) {
case NN_STCP_SRC_STREAMHDR:
switch (type) {
case NN_STREAMHDR_STOPPED:
/* Start the pipe. */
rc = nn_pipebase_start (&stcp->pipebase);
if (nn_slow (rc < 0)) {
stcp->state = NN_STCP_STATE_DONE;
nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR);
return;
}
/* Start receiving a message in asynchronous manner. */
stcp->instate = NN_STCP_INSTATE_HDR;
nn_usock_recv (stcp->usock, &stcp->inhdr,
sizeof (stcp->inhdr), NULL);
/* Mark the pipe as available for sending. */
stcp->outstate = NN_STCP_OUTSTATE_IDLE;
stcp->state = NN_STCP_STATE_ACTIVE;
return;
default:
nn_fsm_bad_action (stcp->state, src, type);
}
default:
nn_fsm_bad_source (stcp->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/******************************************************************************/
case NN_STCP_STATE_ACTIVE:
switch (src) {
case NN_STCP_SRC_USOCK:
switch (type) {
case NN_USOCK_SENT:
/* The message is now fully sent. */
nn_assert (stcp->outstate == NN_STCP_OUTSTATE_SENDING);
stcp->outstate = NN_STCP_OUTSTATE_IDLE;
nn_msg_term (&stcp->outmsg);
nn_msg_init (&stcp->outmsg, 0);
nn_pipebase_sent (&stcp->pipebase);
return;
case NN_USOCK_RECEIVED:
switch (stcp->instate) {
case NN_STCP_INSTATE_HDR:
/* Message header was received. Check that message size
is acceptable by comparing with NN_RCVMAXSIZE;
if it's too large, drop the connection. */
size = nn_getll (stcp->inhdr);
nn_pipebase_getopt (&stcp->pipebase, NN_SOL_SOCKET,
NN_RCVMAXSIZE, &opt, &opt_sz);
if (opt >= 0 && size > (unsigned)opt) {
stcp->state = NN_STCP_STATE_DONE;
nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR);
return;
}
/* Allocate memory for the message. */
nn_msg_term (&stcp->inmsg);
nn_msg_init (&stcp->inmsg, (size_t) size);
/* Special case when size of the message body is 0. */
if (!size) {
stcp->instate = NN_STCP_INSTATE_HASMSG;
nn_pipebase_received (&stcp->pipebase);
return;
}
/* Start receiving the message body. */
stcp->instate = NN_STCP_INSTATE_BODY;
nn_usock_recv (stcp->usock,
nn_chunkref_data (&stcp->inmsg.body),
(size_t) size, NULL);
return;
case NN_STCP_INSTATE_BODY:
/* Message body was received. Notify the owner that it
can receive it. */
stcp->instate = NN_STCP_INSTATE_HASMSG;
nn_pipebase_received (&stcp->pipebase);
return;
default:
nn_fsm_error("Unexpected socket instate",
stcp->state, src, type);
}
case NN_USOCK_SHUTDOWN:
nn_pipebase_stop (&stcp->pipebase);
stcp->state = NN_STCP_STATE_SHUTTING_DOWN;
return;
case NN_USOCK_ERROR:
nn_pipebase_stop (&stcp->pipebase);
stcp->state = NN_STCP_STATE_DONE;
nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR);
return;
default:
nn_fsm_bad_action (stcp->state, src, type);
}
default:
nn_fsm_bad_source (stcp->state, src, type);
}
/******************************************************************************/
/* SHUTTING_DOWN state. */
/* The underlying connection is closed. We are just waiting that underlying */
/* usock being closed */
/******************************************************************************/
case NN_STCP_STATE_SHUTTING_DOWN:
switch (src) {
case NN_STCP_SRC_USOCK:
switch (type) {
case NN_USOCK_ERROR:
stcp->state = NN_STCP_STATE_DONE;
nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR);
return;
default:
nn_fsm_bad_action (stcp->state, src, type);
}
default:
nn_fsm_bad_source (stcp->state, src, type);
}
/******************************************************************************/
/* DONE state. */
/* The underlying connection is closed. There's nothing that can be done in */
/* this state except stopping the object. */
/******************************************************************************/
case NN_STCP_STATE_DONE:
nn_fsm_bad_source (stcp->state, src, type);
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (stcp->state, src, type);
}
}
nanomsg-0.8-beta/src/transports/tcp/tcp.h0000664000175000017500000000237712623652600021406 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_TCP_INCLUDED
#define NN_TCP_INCLUDED
#include "../../transport.h"
extern struct nn_transport *nn_tcp;
#endif
nanomsg-0.8-beta/src/transports/tcp/tcp.c0000664000175000017500000001046412623652600021375 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "tcp.h"
#include "btcp.h"
#include "ctcp.h"
#include "../../tcp.h"
#include "../utils/port.h"
#include "../utils/iface.h"
#include "../../utils/err.h"
#include "../../utils/alloc.h"
#include "../../utils/fast.h"
#include "../../utils/list.h"
#include "../../utils/cont.h"
#include
#if defined NN_HAVE_WINDOWS
#include "../../utils/win.h"
#else
#include
#endif
/* TCP-specific socket options. */
struct nn_tcp_optset {
struct nn_optset base;
int nodelay;
};
static void nn_tcp_optset_destroy (struct nn_optset *self);
static int nn_tcp_optset_setopt (struct nn_optset *self, int option,
const void *optval, size_t optvallen);
static int nn_tcp_optset_getopt (struct nn_optset *self, int option,
void *optval, size_t *optvallen);
static const struct nn_optset_vfptr nn_tcp_optset_vfptr = {
nn_tcp_optset_destroy,
nn_tcp_optset_setopt,
nn_tcp_optset_getopt
};
/* nn_transport interface. */
static int nn_tcp_bind (void *hint, struct nn_epbase **epbase);
static int nn_tcp_connect (void *hint, struct nn_epbase **epbase);
static struct nn_optset *nn_tcp_optset (void);
static struct nn_transport nn_tcp_vfptr = {
"tcp",
NN_TCP,
NULL,
NULL,
nn_tcp_bind,
nn_tcp_connect,
nn_tcp_optset,
NN_LIST_ITEM_INITIALIZER
};
struct nn_transport *nn_tcp = &nn_tcp_vfptr;
static int nn_tcp_bind (void *hint, struct nn_epbase **epbase)
{
return nn_btcp_create (hint, epbase);
}
static int nn_tcp_connect (void *hint, struct nn_epbase **epbase)
{
return nn_ctcp_create (hint, epbase);
}
static struct nn_optset *nn_tcp_optset ()
{
struct nn_tcp_optset *optset;
optset = nn_alloc (sizeof (struct nn_tcp_optset), "optset (tcp)");
alloc_assert (optset);
optset->base.vfptr = &nn_tcp_optset_vfptr;
/* Default values for TCP socket options. */
optset->nodelay = 0;
return &optset->base;
}
static void nn_tcp_optset_destroy (struct nn_optset *self)
{
struct nn_tcp_optset *optset;
optset = nn_cont (self, struct nn_tcp_optset, base);
nn_free (optset);
}
static int nn_tcp_optset_setopt (struct nn_optset *self, int option,
const void *optval, size_t optvallen)
{
struct nn_tcp_optset *optset;
int val;
optset = nn_cont (self, struct nn_tcp_optset, base);
/* At this point we assume that all options are of type int. */
if (optvallen != sizeof (int))
return -EINVAL;
val = *(int*) optval;
switch (option) {
case NN_TCP_NODELAY:
if (nn_slow (val != 0 && val != 1))
return -EINVAL;
optset->nodelay = val;
return 0;
default:
return -ENOPROTOOPT;
}
}
static int nn_tcp_optset_getopt (struct nn_optset *self, int option,
void *optval, size_t *optvallen)
{
struct nn_tcp_optset *optset;
int intval;
optset = nn_cont (self, struct nn_tcp_optset, base);
switch (option) {
case NN_TCP_NODELAY:
intval = optset->nodelay;
break;
default:
return -ENOPROTOOPT;
}
memcpy (optval, &intval,
*optvallen < sizeof (int) ? *optvallen : sizeof (int));
*optvallen = sizeof (int);
return 0;
}
nanomsg-0.8-beta/src/transports/tcpmux/0000775000175000017500000000000012623652617021200 5ustar00travistravis00000000000000nanomsg-0.8-beta/src/transports/tcpmux/atcpmux.h0000664000175000017500000000505012623652600023022 0ustar00travistravis00000000000000/*
Copyright (c) 2013-2014 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_ATCPMUX_INCLUDED
#define NN_ATCPMUX_INCLUDED
#include "stcpmux.h"
#include "../../transport.h"
#include "../../aio/fsm.h"
#include "../../aio/usock.h"
#include "../../utils/list.h"
/* State machine handling accepted TCPMUX sockets. */
/* In btcpmux, some events are just *assumed* to come from a child atcpmux
object. By using non-trivial event codes, we can do more reliable sanity
checking in such scenarios. */
#define NN_ATCPMUX_ACCEPTED 34231
#define NN_ATCPMUX_ERROR 34232
#define NN_ATCPMUX_STOPPED 34233
struct nn_atcpmux {
/* The state machine. */
struct nn_fsm fsm;
int state;
/* Pointer to the associated endpoint. */
struct nn_epbase *epbase;
/* Underlying socket. */
struct nn_usock usock;
/* State machine that takes care of the connection in the active state. */
struct nn_stcpmux stcpmux;
/* Events generated by atcpmux state machine. */
struct nn_fsm_event accepted;
struct nn_fsm_event done;
/* This member can be used by owner to keep individual atcpmuxes
in a list. */
struct nn_list_item item;
};
void nn_atcpmux_init (struct nn_atcpmux *self, int src,
struct nn_epbase *epbase, struct nn_fsm *owner);
void nn_atcpmux_term (struct nn_atcpmux *self);
int nn_atcpmux_isidle (struct nn_atcpmux *self);
void nn_atcpmux_start (struct nn_atcpmux *self, int fd);
void nn_atcpmux_stop (struct nn_atcpmux *self);
#endif
nanomsg-0.8-beta/src/transports/tcpmux/atcpmux.c0000664000175000017500000001762612623652600023031 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2014 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "atcpmux.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/attr.h"
#define NN_ATCPMUX_STATE_IDLE 1
#define NN_ATCPMUX_STATE_ACTIVE 2
#define NN_ATCPMUX_STATE_STOPPING_STCPMUX 3
#define NN_ATCPMUX_STATE_STOPPING_USOCK 4
#define NN_ATCPMUX_STATE_DONE 5
#define NN_ATCPMUX_STATE_STOPPING_STCPMUX_FINAL 6
#define NN_ATCPMUX_STATE_STOPPING 7
#define NN_ATCPMUX_SRC_USOCK 1
#define NN_ATCPMUX_SRC_STCPMUX 2
/* Private functions. */
static void nn_atcpmux_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_atcpmux_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
void nn_atcpmux_init (struct nn_atcpmux *self, int src,
struct nn_epbase *epbase, struct nn_fsm *owner)
{
nn_fsm_init (&self->fsm, nn_atcpmux_handler, nn_atcpmux_shutdown,
src, self, owner);
self->state = NN_ATCPMUX_STATE_IDLE;
self->epbase = epbase;
nn_usock_init (&self->usock, NN_ATCPMUX_SRC_USOCK, &self->fsm);
nn_stcpmux_init (&self->stcpmux, NN_ATCPMUX_SRC_STCPMUX,
epbase, &self->fsm);
nn_fsm_event_init (&self->accepted);
nn_fsm_event_init (&self->done);
nn_list_item_init (&self->item);
}
void nn_atcpmux_term (struct nn_atcpmux *self)
{
nn_assert_state (self, NN_ATCPMUX_STATE_IDLE);
nn_list_item_term (&self->item);
nn_fsm_event_term (&self->done);
nn_fsm_event_term (&self->accepted);
nn_stcpmux_term (&self->stcpmux);
nn_usock_term (&self->usock);
nn_fsm_term (&self->fsm);
}
int nn_atcpmux_isidle (struct nn_atcpmux *self)
{
return nn_fsm_isidle (&self->fsm);
}
void nn_atcpmux_start (struct nn_atcpmux *self, int fd)
{
nn_assert_state (self, NN_ATCPMUX_STATE_IDLE);
/* Start the state machine. */
nn_fsm_start (&self->fsm);
/* Start the stcp state machine. */
nn_usock_start_fd (&self->usock, fd);
nn_stcpmux_start (&self->stcpmux, &self->usock);
self->state = NN_ATCPMUX_STATE_ACTIVE;
}
void nn_atcpmux_stop (struct nn_atcpmux *self)
{
nn_fsm_stop (&self->fsm);
}
static void nn_atcpmux_shutdown (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_atcpmux *atcpmux;
atcpmux = nn_cont (self, struct nn_atcpmux, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
if (!nn_stcpmux_isidle (&atcpmux->stcpmux)) {
nn_epbase_stat_increment (atcpmux->epbase,
NN_STAT_DROPPED_CONNECTIONS, 1);
nn_stcpmux_stop (&atcpmux->stcpmux);
}
atcpmux->state = NN_ATCPMUX_STATE_STOPPING_STCPMUX_FINAL;
}
if (nn_slow (atcpmux->state == NN_ATCPMUX_STATE_STOPPING_STCPMUX_FINAL)) {
if (!nn_stcpmux_isidle (&atcpmux->stcpmux))
return;
nn_usock_stop (&atcpmux->usock);
atcpmux->state = NN_ATCPMUX_STATE_STOPPING;
}
if (nn_slow (atcpmux->state == NN_ATCPMUX_STATE_STOPPING)) {
if (!nn_usock_isidle (&atcpmux->usock))
return;
atcpmux->state = NN_ATCPMUX_STATE_IDLE;
nn_fsm_stopped (&atcpmux->fsm, NN_ATCPMUX_STOPPED);
return;
}
nn_fsm_bad_action(atcpmux->state, src, type);
}
static void nn_atcpmux_handler (struct nn_fsm *self, int src, int type,
NN_UNUSED void *srcptr)
{
struct nn_atcpmux *atcpmux;
atcpmux = nn_cont (self, struct nn_atcpmux, fsm);
switch (atcpmux->state) {
/******************************************************************************/
/* IDLE state. */
/* The state machine wasn't yet started. */
/******************************************************************************/
case NN_ATCPMUX_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
// TODO
atcpmux->state = NN_ATCPMUX_STATE_ACTIVE;
return;
default:
nn_fsm_bad_action (atcpmux->state, src, type);
}
default:
nn_fsm_bad_source (atcpmux->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/******************************************************************************/
case NN_ATCPMUX_STATE_ACTIVE:
switch (src) {
case NN_ATCPMUX_SRC_STCPMUX:
switch (type) {
case NN_STCPMUX_ERROR:
nn_stcpmux_stop (&atcpmux->stcpmux);
atcpmux->state = NN_ATCPMUX_STATE_STOPPING_STCPMUX;
nn_epbase_stat_increment (atcpmux->epbase,
NN_STAT_BROKEN_CONNECTIONS, 1);
return;
default:
nn_fsm_bad_action (atcpmux->state, src, type);
}
default:
nn_fsm_bad_source (atcpmux->state, src, type);
}
/******************************************************************************/
/* STOPPING_STCPMUX state. */
/******************************************************************************/
case NN_ATCPMUX_STATE_STOPPING_STCPMUX:
switch (src) {
case NN_ATCPMUX_SRC_STCPMUX:
switch (type) {
case NN_USOCK_SHUTDOWN:
return;
case NN_STCPMUX_STOPPED:
nn_usock_stop (&atcpmux->usock);
atcpmux->state = NN_ATCPMUX_STATE_STOPPING_USOCK;
return;
default:
nn_fsm_bad_action (atcpmux->state, src, type);
}
default:
nn_fsm_bad_source (atcpmux->state, src, type);
}
/******************************************************************************/
/* STOPPING_USOCK state. */
/******************************************************************************/
case NN_ATCPMUX_STATE_STOPPING_USOCK:
switch (src) {
case NN_ATCPMUX_SRC_USOCK:
switch (type) {
case NN_USOCK_SHUTDOWN:
return;
case NN_USOCK_STOPPED:
nn_fsm_raise (&atcpmux->fsm, &atcpmux->done, NN_ATCPMUX_ERROR);
atcpmux->state = NN_ATCPMUX_STATE_DONE;
return;
default:
nn_fsm_bad_action (atcpmux->state, src, type);
}
default:
nn_fsm_bad_source (atcpmux->state, src, type);
}
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (atcpmux->state, src, type);
}
}
nanomsg-0.8-beta/src/transports/tcpmux/btcpmux.h0000664000175000017500000000252712623652600023031 0ustar00travistravis00000000000000/*
Copyright (c) 2013-2014 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_BTCPMUX_INCLUDED
#define NN_BTCPMUX_INCLUDED
#include "../../transport.h"
/* State machine managing bound TCPMUX socket. */
int nn_btcpmux_create (void *hint, struct nn_epbase **epbase);
#endif
nanomsg-0.8-beta/src/transports/tcpmux/btcpmux.c0000664000175000017500000004241112623652600023020 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2014 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "btcpmux.h"
#include "atcpmux.h"
#include "../utils/port.h"
#include "../utils/iface.h"
#include "../../aio/fsm.h"
#include "../../aio/usock.h"
#include "../utils/backoff.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/alloc.h"
#include "../../utils/list.h"
#include "../../utils/fast.h"
#include "../../utils/int.h"
#include
#if defined NN_HAVE_WINDOWS
#include "../../utils/win.h"
#else
#include
#include
#include
#endif
/* The backlog is set relatively high so that there are not too many failed
connection attemps during re-connection storms. */
#define NN_BTCPMUX_BACKLOG 100
#define NN_BTCPMUX_STATE_IDLE 1
#define NN_BTCPMUX_STATE_CONNECTING 2
#define NN_BTCPMUX_STATE_SENDING_BINDREQ 3
#define NN_BTCPMUX_STATE_ACTIVE 4
#define NN_BTCPMUX_STATE_STOPPING_USOCK 5
#define NN_BTCPMUX_STATE_STOPPING_ATCPMUXES 6
#define NN_BTCPMUX_STATE_LISTENING 7
#define NN_BTCPMUX_STATE_WAITING 8
#define NN_BTCPMUX_STATE_CLOSING 9
#define NN_BTCPMUX_STATE_STOPPING_BACKOFF 10
#define NN_BTCPMUX_SRC_USOCK 1
#define NN_BTCPMUX_SRC_ATCPMUX 2
#define NN_BTCPMUX_SRC_RECONNECT_TIMER 3
struct nn_btcpmux {
/* The state machine. */
struct nn_fsm fsm;
int state;
/* This object is a specific type of endpoint.
Thus it is derived from epbase. */
struct nn_epbase epbase;
/* The underlying listening TCPMUX socket. */
struct nn_usock usock;
/* List of accepted connections. */
struct nn_list atcpmuxes;
/* Used to wait before retrying to connect. */
struct nn_backoff retry;
/* Service name. */
const char *service;
/* Service name length, in network byte order. */
uint16_t servicelen;
/* File descriptor of newly accepted connection. */
int newfd;
/* Temporary buffer. */
char code;
};
/* nn_epbase virtual interface implementation. */
static void nn_btcpmux_stop (struct nn_epbase *self);
static void nn_btcpmux_destroy (struct nn_epbase *self);
const struct nn_epbase_vfptr nn_btcpmux_epbase_vfptr = {
nn_btcpmux_stop,
nn_btcpmux_destroy
};
/* Private functions. */
static void nn_btcpmux_handler (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_btcpmux_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr);
static void nn_btcpmux_start_connecting (struct nn_btcpmux *self);
int nn_btcpmux_create (void *hint, struct nn_epbase **epbase)
{
int rc;
struct nn_btcpmux *self;
const char *addr;
const char *colon;
const char *slash;
const char *end;
int reconnect_ivl;
int reconnect_ivl_max;
size_t sz;
/* Allocate the new endpoint object. */
self = nn_alloc (sizeof (struct nn_btcpmux), "btcpmux");
alloc_assert (self);
/* Initalise the epbase. */
nn_epbase_init (&self->epbase, &nn_btcpmux_epbase_vfptr, hint);
/* Parse the connection string. For now, we can only bind to all
interfaces. */
addr = nn_epbase_getaddr (&self->epbase);
colon = strchr (addr, ':');
if (nn_slow (!colon || colon - addr != 1 || addr [0] != '*')) {
nn_epbase_term (&self->epbase);
return -EINVAL;
}
slash = strchr (colon + 1, '/');
if (nn_slow (!slash)) {
nn_epbase_term (&self->epbase);
return -EINVAL;
}
end = addr + strlen (addr);
/* Parse the port. */
rc = nn_port_resolve (colon + 1, slash - (colon + 1));
if (nn_slow (rc < 0)) {
nn_epbase_term (&self->epbase);
return -EINVAL;
}
/* Store the service name. */
self->service = slash + 1;
self->servicelen = htons (end - (slash + 1));
/* Initialise the structure. */
nn_fsm_init_root (&self->fsm, nn_btcpmux_handler, nn_btcpmux_shutdown,
nn_epbase_getctx (&self->epbase));
self->state = NN_BTCPMUX_STATE_IDLE;
sz = sizeof (reconnect_ivl);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL,
&reconnect_ivl, &sz);
nn_assert (sz == sizeof (reconnect_ivl));
sz = sizeof (reconnect_ivl_max);
nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX,
&reconnect_ivl_max, &sz);
nn_assert (sz == sizeof (reconnect_ivl_max));
if (reconnect_ivl_max == 0)
reconnect_ivl_max = reconnect_ivl;
nn_backoff_init (&self->retry, NN_BTCPMUX_SRC_RECONNECT_TIMER,
reconnect_ivl, reconnect_ivl_max, &self->fsm);
nn_usock_init (&self->usock, NN_BTCPMUX_SRC_USOCK, &self->fsm);
nn_list_init (&self->atcpmuxes);
/* Start the state machine. */
nn_fsm_start (&self->fsm);
/* Return the base class as an out parameter. */
*epbase = &self->epbase;
return 0;
}
static void nn_btcpmux_stop (struct nn_epbase *self)
{
struct nn_btcpmux *btcpmux;
btcpmux = nn_cont (self, struct nn_btcpmux, epbase);
nn_fsm_stop (&btcpmux->fsm);
}
static void nn_btcpmux_destroy (struct nn_epbase *self)
{
struct nn_btcpmux *btcpmux;
btcpmux = nn_cont (self, struct nn_btcpmux, epbase);
nn_assert_state (btcpmux, NN_BTCPMUX_STATE_IDLE);
nn_list_term (&btcpmux->atcpmuxes);
nn_usock_term (&btcpmux->usock);
nn_backoff_term (&btcpmux->retry);
nn_epbase_term (&btcpmux->epbase);
nn_fsm_term (&btcpmux->fsm);
nn_free (btcpmux);
}
static void nn_btcpmux_shutdown (struct nn_fsm *self, int src, int type,
void *srcptr)
{
struct nn_btcpmux *btcpmux;
struct nn_list_item *it;
struct nn_atcpmux *atcpmux;
btcpmux = nn_cont (self, struct nn_btcpmux, fsm);
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
nn_backoff_stop (&btcpmux->retry);
nn_usock_stop (&btcpmux->usock);
btcpmux->state = NN_BTCPMUX_STATE_STOPPING_USOCK;
}
if (nn_slow (btcpmux->state == NN_BTCPMUX_STATE_STOPPING_USOCK)) {
if (!nn_usock_isidle (&btcpmux->usock))
return;
for (it = nn_list_begin (&btcpmux->atcpmuxes);
it != nn_list_end (&btcpmux->atcpmuxes);
it = nn_list_next (&btcpmux->atcpmuxes, it)) {
atcpmux = nn_cont (it, struct nn_atcpmux, item);
nn_atcpmux_stop (atcpmux);
}
btcpmux->state = NN_BTCPMUX_STATE_STOPPING_ATCPMUXES;
goto atcpmuxes_stopping;
}
if (nn_slow (btcpmux->state == NN_BTCPMUX_STATE_STOPPING_ATCPMUXES)) {
nn_assert (src == NN_BTCPMUX_SRC_ATCPMUX && type == NN_ATCPMUX_STOPPED);
atcpmux = (struct nn_atcpmux *) srcptr;
nn_list_erase (&btcpmux->atcpmuxes, &atcpmux->item);
nn_atcpmux_term (atcpmux);
nn_free (atcpmux);
/* If there are no more atcpmux state machines, we can stop the whole
btcpmux object. */
atcpmuxes_stopping:
if (nn_list_empty (&btcpmux->atcpmuxes)) {
btcpmux->state = NN_BTCPMUX_STATE_IDLE;
nn_fsm_stopped_noevent (&btcpmux->fsm);
nn_epbase_stopped (&btcpmux->epbase);
return;
}
return;
}
nn_fsm_bad_action(btcpmux->state, src, type);
}
static void nn_btcpmux_handler (struct nn_fsm *self, int src, int type,
void *srcptr)
{
struct nn_btcpmux *btcpmux;
struct nn_atcpmux *atcpmux;
struct nn_iovec iovecs [2];
btcpmux = nn_cont (self, struct nn_btcpmux, fsm);
switch (btcpmux->state) {
/******************************************************************************/
/* IDLE state. */
/******************************************************************************/
case NN_BTCPMUX_STATE_IDLE:
switch (src) {
case NN_FSM_ACTION:
switch (type) {
case NN_FSM_START:
nn_btcpmux_start_connecting (btcpmux);
return;
default:
nn_fsm_bad_action (btcpmux->state, src, type);
}
default:
nn_fsm_bad_source (btcpmux->state, src, type);
}
/******************************************************************************/
/* CONNECTING state. */
/******************************************************************************/
case NN_BTCPMUX_STATE_CONNECTING:
switch (src) {
case NN_BTCPMUX_SRC_USOCK:
switch (type) {
case NN_USOCK_CONNECTED:
iovecs [0].iov_base = &btcpmux->servicelen;
iovecs [0].iov_len = 2;
iovecs [1].iov_base = (void*) btcpmux->service;
iovecs [1].iov_len = ntohs (btcpmux->servicelen);
nn_usock_send (&btcpmux->usock, iovecs, 2);
btcpmux->state = NN_BTCPMUX_STATE_SENDING_BINDREQ;
return;
case NN_USOCK_ERROR:
nn_usock_stop (&btcpmux->usock);
btcpmux->state = NN_BTCPMUX_STATE_STOPPING_USOCK;
return;
default:
nn_fsm_bad_action (btcpmux->state, src, type);
}
default:
nn_fsm_bad_source (btcpmux->state, src, type);
}
/******************************************************************************/
/* SENDING_BINDREQ state. */
/******************************************************************************/
case NN_BTCPMUX_STATE_SENDING_BINDREQ:
switch (src) {
case NN_BTCPMUX_SRC_USOCK:
switch (type) {
case NN_USOCK_SENT:
nn_usock_recv (&btcpmux->usock, &btcpmux->code, 1,
&btcpmux->newfd);
btcpmux->state = NN_BTCPMUX_STATE_ACTIVE;
return;
case NN_USOCK_ERROR:
nn_usock_stop (&btcpmux->usock);
btcpmux->state = NN_BTCPMUX_STATE_STOPPING_USOCK;
return;
default:
nn_fsm_bad_action (btcpmux->state, src, type);
}
default:
nn_fsm_bad_source (btcpmux->state, src, type);
}
/******************************************************************************/
/* ACTIVE state. */
/* The execution is yielded to the atcpmux state machine in this state. */
/******************************************************************************/
case NN_BTCPMUX_STATE_ACTIVE:
if (src == NN_BTCPMUX_SRC_USOCK) {
switch (type) {
case NN_USOCK_RECEIVED:
if (btcpmux->code != 0 || btcpmux->newfd < 0) {
nn_usock_stop (&btcpmux->usock);
btcpmux->state = NN_BTCPMUX_STATE_STOPPING_USOCK;
return;
}
/* Allocate new atcpmux state machine. */
atcpmux = nn_alloc (sizeof (struct nn_atcpmux), "atcpmux");
alloc_assert (atcpmux);
nn_atcpmux_init (atcpmux, NN_BTCPMUX_SRC_ATCPMUX,
&btcpmux->epbase, &btcpmux->fsm);
nn_atcpmux_start (atcpmux, btcpmux->newfd);
nn_list_insert (&btcpmux->atcpmuxes, &atcpmux->item,
nn_list_end (&btcpmux->atcpmuxes));
/* Start accepting new connection straight away. */
nn_usock_recv (&btcpmux->usock, &btcpmux->code, 1,
&btcpmux->newfd);
return;
case NN_USOCK_ERROR:
nn_usock_stop (&btcpmux->usock);
btcpmux->state = NN_BTCPMUX_STATE_STOPPING_USOCK;
return;
default:
nn_fsm_bad_action (btcpmux->state, src, type);
}
}
/* For all remaining events we'll assume they are coming from one
of remaining child atcpmux objects. */
nn_assert (src == NN_BTCPMUX_SRC_ATCPMUX);
atcpmux = (struct nn_atcpmux*) srcptr;
switch (type) {
case NN_ATCPMUX_ERROR:
nn_atcpmux_stop (atcpmux);
return;
case NN_ATCPMUX_STOPPED:
nn_list_erase (&btcpmux->atcpmuxes, &atcpmux->item);
nn_atcpmux_term (atcpmux);
nn_free (atcpmux);
return;
default:
nn_fsm_bad_action (btcpmux->state, src, type);
}
/******************************************************************************/
/* CLOSING_USOCK state. */
/* usock object was asked to stop but it haven't stopped yet. */
/******************************************************************************/
case NN_BTCPMUX_STATE_CLOSING:
switch (src) {
case NN_BTCPMUX_SRC_USOCK:
switch (type) {
case NN_USOCK_SHUTDOWN:
return;
case NN_USOCK_STOPPED:
nn_backoff_start (&btcpmux->retry);
btcpmux->state = NN_BTCPMUX_STATE_WAITING;
return;
default:
nn_fsm_bad_action (btcpmux->state, src, type);
}
default:
nn_fsm_bad_source (btcpmux->state, src, type);
}
/******************************************************************************/
/* WAITING state. */
/* Waiting before re-bind is attempted. This way we won't overload */
/* the system by continuous re-bind attemps. */
/******************************************************************************/
case NN_BTCPMUX_STATE_WAITING:
switch (src) {
case NN_BTCPMUX_SRC_RECONNECT_TIMER:
switch (type) {
case NN_BACKOFF_TIMEOUT:
nn_backoff_stop (&btcpmux->retry);
btcpmux->state = NN_BTCPMUX_STATE_STOPPING_BACKOFF;
return;
default:
nn_fsm_bad_action (btcpmux->state, src, type);
}
default:
nn_fsm_bad_source (btcpmux->state, src, type);
}
/******************************************************************************/
/* STOPPING_BACKOFF state. */
/* backoff object was asked to stop, but it haven't stopped yet. */
/******************************************************************************/
case NN_BTCPMUX_STATE_STOPPING_BACKOFF:
switch (src) {
case NN_BTCPMUX_SRC_RECONNECT_TIMER:
switch (type) {
case NN_BACKOFF_STOPPED:
nn_btcpmux_start_connecting (btcpmux);
return;
default:
nn_fsm_bad_action (btcpmux->state, src, type);
}
default:
nn_fsm_bad_source (btcpmux->state, src, type);
}
/******************************************************************************/
/* Invalid state. */
/******************************************************************************/
default:
nn_fsm_bad_state (btcpmux->state, src, type);
}
}
/******************************************************************************/
/* State machine actions. */
/******************************************************************************/
static void nn_btcpmux_start_connecting (struct nn_btcpmux *self)
{
int rc;
struct sockaddr_storage ss;
struct sockaddr_un *un;
const char *addr;
const char *colon;
const char *slash;
int port;
/* Try to start the underlying socket. */
rc = nn_usock_start (&self->usock, AF_UNIX, SOCK_STREAM, 0);
if (nn_slow (rc < 0)) {
nn_backoff_start (&self->retry);
self->state = NN_BTCPMUX_STATE_WAITING;
return;
}
/* Create the IPC address from the address string. */
addr = nn_epbase_getaddr (&self->epbase);
colon = strchr (addr, ':');
slash = strchr (colon + 1, '/');
port = nn_port_resolve (colon + 1, slash - (colon + 1));
memset (&ss, 0, sizeof (ss));
un = (struct sockaddr_un*) &ss;
ss.ss_family = AF_UNIX;
sprintf (un->sun_path, "/tmp/tcpmux-%d.ipc", (int) port);
/* Start connecting. */
nn_usock_connect (&self->usock, (struct sockaddr*) &ss,
sizeof (struct sockaddr_un));
self->state = NN_BTCPMUX_STATE_CONNECTING;
}
nanomsg-0.8-beta/src/transports/tcpmux/ctcpmux.h0000664000175000017500000000253312623652600023027 0ustar00travistravis00000000000000/*
Copyright (c) 2013-2014 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#ifndef NN_CTCPMUX_INCLUDED
#define NN_CTCPMUX_INCLUDED
#include "../../transport.h"
/* State machine managing connected TCPMUX socket. */
int nn_ctcpmux_create (void *hint, struct nn_epbase **epbase);
#endif
nanomsg-0.8-beta/src/transports/tcpmux/ctcpmux.c0000664000175000017500000006105612623652600023027 0ustar00travistravis00000000000000/*
Copyright (c) 2012-2014 Martin Sustrik All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "ctcpmux.h"
#include "stcpmux.h"
#include "../../tcpmux.h"
#include "../utils/dns.h"
#include "../utils/port.h"
#include "../utils/iface.h"
#include "../utils/backoff.h"
#include "../utils/literal.h"
#include "../../aio/fsm.h"
#include "../../aio/usock.h"
#include "../../utils/err.h"
#include "../../utils/cont.h"
#include "../../utils/alloc.h"
#include "../../utils/fast.h"
#include "../../utils/int.h"
#include "../../utils/attr.h"
#include
#if defined NN_HAVE_WINDOWS
#include "../../utils/win.h"
#else
#include