Documentation changes needed to support RTD
[ric-plt/lib/rmr.git] / docs / user-guide.rst
diff --git a/docs/user-guide.rst b/docs/user-guide.rst
new file mode 100644 (file)
index 0000000..b13234a
--- /dev/null
@@ -0,0 +1,3752 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License. 
+.. SPDX-License-Identifier: CC-BY-4.0 
+.. CAUTION: this document is generated from source in doc/src/rtd. 
+.. To make changes edit the source and recompile the document. 
+.. Do NOT make changes directly to .rst or .md files. 
+RMR User's Guide 
+============================================================================================ 
+The RIC Message Router (RMR) is a library which applications 
+use to send and receive messages where the message routing, 
+endpoint selection, is based on the message type rather than 
+on traditional DNS names or IP addresses. Because the user 
+documentation for RMR is a collection of UNIX manpages 
+(included in the development package, and avalable via the 
+man command when installed), there is no separate "User's 
+Guide." To prvide something for the document scrapers to 
+find, this is a collection of the RMR manual pages formatted 
+directly from their source which might be a bit ragged when 
+combined into a single markup document. Read the manual pages 
+:) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ rmr_mbuf_t* rmr_alloc_msg( void* ctx, int size );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_alloc_msg function is used to allocate a buffer which 
+the user programme can write into and then send through the 
+RMR library. The buffer is allocated such that sending it 
+requires no additional copying out of the buffer. If the 
+value passed in size is 0, then the default size supplied on 
+the *rmr_init* call will be used. The *ctx* parameter is the 
+void context pointer that was returned by the *rmr_init* 
+function. 
+The pointer to the message buffer returned is a structure 
+which has some user application visible fields; the structure 
+is described in rmr.h, and is illustrated below. 
+:: 
+  
+ typedef struct {
+     int state;
+     int mtype;
+     int len;
+     unsigned char* payload;
+     unsigned char* xaction;
+     uint sub_id;
+     uint tp_state;
+ } rmr_mbuf_t;
+state 
+   
+  Is the current buffer state. Following a call to 
+  rmr_send_msg the state indicates whether the buffer was 
+  successfully sent which determines exactly what the 
+  payload points to. If the send failed, the payload 
+  referenced by the buffer is the message that failed to 
+  send (allowing the application to attempt a 
+  retransmission). When the state is RMR_OK the buffer 
+  represents an empty buffer that the application may fill 
+  in in preparation to send. 
+   
+mtype 
+   
+  When sending a message, the application is expected to set 
+  this field to the appropriate message type value (as 
+  determined by the user programme). Upon send this value 
+  determines how the RMR library will route the message. For 
+  a buffer which has been received, this field will contain 
+  the message type that was set by the sending application. 
+   
+len 
+   
+  The application using a buffer to send a message is 
+  expected to set the length value to the actual number of 
+  bytes that it placed into the message. This is likely less 
+  than the total number of bytes that the message can carry. 
+  For a message buffer that is passed to the application as 
+  the result of a receive call, this will be the value that 
+  the sending application supplied and should indicate the 
+  number of bytes in the payload which are valid. 
+   
+payload 
+   
+  The payload is a pointer to the actual received data. The 
+  user programme may read and write from/to the memory 
+  referenced by the payload up until the point in time that 
+  the buffer is used on a rmr_send, rmr_call or rmr_reply 
+  function call. Once the buffer has been passed back to a 
+  RMR library function the user programme should **NOT** 
+  make use of the payload pointer. 
+   
+xaction 
+   
+  The *xaction* field is a pointer to a fixed sized area in 
+  the message into which the user may write a transaction 
+  ID. The ID is optional with the exception of when the user 
+  application uses the rmr_call function to send a message 
+  and wait for the reply; the underlying RMR processing 
+  expects that the matching reply message will also contain 
+  the same data in the *xaction* field. 
+sub_id 
+   
+  This value is the subscription ID. It, in combination with 
+  the message type is used by rmr to determine the target 
+  endpoint when sending a message. If the application to 
+  application protocol does not warrant the use of a 
+  subscription ID, the RMR constant RMR_VOID_SUBID should be 
+  placed in this field. When an application is forwarding or 
+  returning a buffer to the sender, it is the application's 
+  responsibility to set/reset this value. 
+   
+tp_state 
+   
+  For C applications making use of RMR, the state of a 
+  transport based failure will often be available via errno. 
+  However, some wrapper environments may not have direct access 
+  to the C-lib errno value. RMR send and receive operations 
+  will place the current value of errno into this field which 
+  should make it available to wrapper functions. User 
+  applications are strongly cautioned against relying on the 
+  value of errno as some transport mechanisms may not set this 
+  value on all calls. This value should also be ignored any 
+  time the message status is RMR_OK. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+The function returns a pointer to a rmr_mbuf structure, or NULL 
+on error. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+ENOMEM 
+   
+  Unable to allocate memory. 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_tralloc_msg(3), rmr_call(3), rmr_free_msg(3), rmr_init(3), 
+rmr_init_trace(3), rmr_get_trace(3), rmr_get_trlen(3), 
+rmr_payload_size(3), rmr_send_msg(3), rmr_rcv_msg(3), 
+rmr_rcv_specific(3), rmr_rts_msg(3), rmr_ready(3), rmr_fib(3), 
+rmr_has_str(3), rmr_tokenise(3), rmr_mk_ring(3), 
+rmr_ring_free(3), rmr_set_trace(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_bytes2meid 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ int rmr_bytes2meid( rmr_mbuf_t* mbuf, unsigned char* src, int len )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_bytes2meid function will copy up to *len* butes from 
+*src* to the managed equipment ID (meid) field in the 
+message. The field is a fixed length, gated by the constant 
+RMR_MAX_MEID and if len is larger than this value, only 
+RMR_MAX_MEID bytes will actually be copied. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+On success, the actual number of bytes copied is returned, or 
+-1 to indicate a hard error. If the length is less than 0, or 
+not the same as length passed in, errno is set to one of the 
+errors described in the *Errors* section. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+If the returned length does not match the length passed in, 
+errno will be set to one of the following constants with the 
+meaning listed below. 
+EINVAL 
+   
+  The message, or an internal portion of the message, was 
+  corrupted or the pointer was invalid. 
+   
+EOVERFLOW 
+   
+  The length passed in was larger than the maximum length of 
+  the field; only a portion of the source bytes were copied. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_bytes2xact(3), rmr_call(3), 
+rmr_free_msg(3), rmr_get_rcvfd(3), rmr_get_meid(3), 
+rmr_payload_size(3), rmr_send_msg(3), rmr_rcv_msg(3), 
+rmr_rcv_specific(3), rmr_rts_msg(3), rmr_ready(3), 
+rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), rmr_mk_ring(3), 
+rmr_ring_free(3), rmr_str2meid(3), rmr_str2xact(3), 
+rmr_wh_open(3), rmr_wh_send_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_bytes2payload 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ void rmr_bytes2payload( rmr_mbuf_t* mbuf, unsigned char* src, int len )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+This is a convenience function as some wrapper languages 
+might not have the ability to directly copy into the payload 
+buffer. The bytes from * src * for the length given are 
+copied to the payload. It is the caller's responsibility to 
+ensure that the payload is large enough. Upon successfully 
+copy, the len field in the message buffer is updated to 
+reflect the number of bytes copied. 
+There is little error checking, and no error reporting. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+None. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_bytes2xact(3), rmr_bytes2payload(3), 
+rmr_call(3), rmr_free_msg(3), rmr_get_rcvfd(3), 
+rmr_get_meid(3), rmr_payload_size(3), rmr_send_msg(3), 
+rmr_rcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), 
+rmr_ready(3), rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), 
+rmr_mk_ring(3), rmr_ring_free(3), rmr_str2meid(3), 
+rmr_str2xact(3), rmr_wh_open(3), rmr_wh_send_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_bytes2xact 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ int rmr_bytes2xact( rmr_mbuf_t* mbuf, unsigned char* src, int len )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_bytes2xact function will copy up to *len* butes from 
+*src* to the transaction ID (xaction) field in the message. 
+The field is a fixed length, gated by the constant 
+RMR_MAX_XID and if len is larger than this value, only 
+RMR_MAX_XID bytes will actually be copied. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+On success, the actual number of bytes copied is returned, 
+or -1 to indicate a hard error. If the length is less than 
+0, or not the same as length passed in, errno is set to 
+one of the errors described in the *Errors* section. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+If the returned length does not match the length passed 
+in, errno will be set to one of the following constants 
+with the meaning listed below. 
+EINVAL 
+   
+  The message, or an internal portion of the message, was 
+  corrupted or the pointer was invalid. 
+   
+EOVERFLOW 
+   
+  The length passed in was larger than the maximum length of 
+  the field; only a portion of the source bytes were copied. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_bytes2meid(3), rmr_call(3), 
+rmr_free_msg(3), rmr_get_meid(3), rmr_get_rcvfd(3), 
+rmr_get_xact(3), rmr_payload_size(3), rmr_send_msg(3), 
+rmr_rcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), 
+rmr_ready(3), rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), 
+rmr_mk_ring(3), rmr_ring_free(3), rmr_str2meid(3), 
+rmr_wh_open(3), rmr_wh_send_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_call 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ extern rmr_mbuf_t* rmr_call( void* vctx, rmr_mbuf_t* msg );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_call function sends the user application message to a 
+remote endpoint, and waits for a corresponding response 
+message before returning control to the user application. The 
+user application supplies a completed message buffer, as it 
+would for a rmr_send call, but unlike with the send, the 
+buffer returned will have the response from the application 
+that received the message. 
+Messages which are received while waiting for the response 
+are queued internally by RMR, and are returned to the user 
+application when rmr_rcv_msg is invoked. These messages are 
+returned in th order received, one per call to rmr_rcv_msg. 
+Call Timeout 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+The rmr_call function implements a timeout failsafe to 
+prevent, in most cases, the function from blocking forever. 
+The timeout period is **not** based on time (calls to clock 
+are deemed too expensive for a low latency system level 
+library, but instead the period is based on the number of 
+received messages which are not the response. Using a 
+non-time mechanism for *timeout* prevents the async queue 
+from filling (which would lead to message drops) in an 
+environment where there is heavy message traffic. 
+When the threshold number of messages have been queued 
+without receiving a response message, control is returned to 
+the user application and a NULL pointer is returned to 
+indicate that no message was received to process. Currently 
+the threshold is fixed at 20 messages, though in future 
+versions of the library this might be extended to be a 
+parameter which the user application may set. 
+Retries 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+The send operations in RMr will retry *soft* send failures 
+until one of three conditions occurs: 
+1. 
+   
+  The message is sent without error 
+   
+2. 
+   
+  The underlying transport reports a * hard * failure 
+   
+3. 
+   
+  The maximum number of retry loops has been attempted 
+A retry loop consists of approximately 1000 send attemps ** 
+without** any intervening calls to * sleep() * or * usleep(). 
+* The number of retry loops defaults to 1, thus a maximum of 
+1000 send attempts is performed before returning to the user 
+application. This value can be set at any point after RMr 
+initialisation using the * rmr_set_stimeout() * function 
+allowing the user application to completely disable retires 
+(set to 0), or to increase the number of retry loops. 
+Transport Level Blocking 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+The underlying transport mechanism used to send messages is 
+configured in *non-blocking* mode. This means that if a 
+message cannot be sent immediately the transport mechanism 
+will **not** pause with the assumption that the inability to 
+send will clear quickly (within a few milliseconds). This 
+means that when the retry loop is completely disabled (set to 
+0), that the failure to accept a message for sending by the 
+underlying mechanisms (software or hardware) will be reported 
+immediately to the user application. 
+It should be noted that depending on the underlying transport 
+mechanism being used, it is extremly possible that during 
+normal operations that retry conditions are very likely to 
+happen. These are completely out of RMr's control, and there 
+is nothing that RMr can do to avoid or midigate these other 
+than by allowing RMr to retry the send operation, and even 
+then it is possible (e.g. during connection reattempts), that 
+a single retry loop is not enough to guarentee a successful 
+send. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+The rmr_call function returns a pointer to a message buffer 
+with the state set to reflect the overall state of call 
+processing (see Errors below). In some cases a NULL pointer 
+will be returned; when this is the case only *errno* will be 
+available to describe the reason for failure. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+These values are reflected in the state field of the returned 
+message. 
+RMR_OK 
+   
+  The call was successful and the message buffer references 
+  the response message. 
+   
+RMR_ERR_CALLFAILED 
+   
+  The call failed and the value of *errno,* as described 
+  below, should be checked for the specific reason. 
+The global "variable" *errno* will be set to one of the 
+following values if the overall call processing was not 
+successful. 
+ETIMEDOUT 
+   
+  Too many messages were queued before receiving the 
+  expected response 
+   
+ENOBUFS 
+   
+  The queued message ring is full, messages were dropped 
+   
+EINVAL 
+   
+  A parameter was not valid 
+   
+EAGAIN 
+   
+  The underlying message system wsa interrupted or the 
+  device was busy; the message was **not** sent, and user 
+  application should call this function with the message 
+  again. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+The following code bit shows one way of using the rmr_call 
+function, and illustrates how the transaction ID must be set. 
+:: 
+  
+     int retries_left = 5;               // max retries on dev not available
+     int retry_delay = 50000;            // retry delay (usec)
+     static rmr_mbuf_t*  mbuf = NULL;    // response msg
+     msg_t*  pm;                         // private message (payload)
+     m// get a send buffer and reference the payload 
+     mbuf = rmr_alloc_msg( mr, RMR_MAX_RCV_BYTES );
+     pm = (msg_t*) mbuf->payload;
+     p// generate an xaction ID and fill in payload with data and msg type
+     snprintf( mbuf->xaction, RMR_MAX_XID, "%s", gen_xaction() );
+     snprintf( pm->req, sizeof( pm->req ), "{ \\"req\\": \\"num users\\"}" );
+     mbuf->mtype = MT_REQ;
+     
+     msg = rmr_call( mr, msg );
+     if( ! msg ) {               // probably a timeout and no msg received
+         return NULL;            // let errno trickle up
+     } 
+     if( mbuf->state != RMR_OK ) {
+         while( retries_left-- > 0 &&             // loop as long as eagain
+                errno == EAGAIN && 
+                (msg = rmr_call( mr, msg )) != NULL && 
+                mbuf->state != RMR_OK ) {
+             usleep( retry_delay );
+         }
+     
+         if( mbuf == NULL || mbuf->state != RMR_OK ) {
+             rmr_free_msg( mbuf );        // safe if nil
+             return NULL;
+         }
+     }
+     // do something with mbuf
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_free_msg(3), rmr_init(3), 
+rmr_payload_size(3), rmr_send_msg(3), rmr_rcv_msg(3), 
+rmr_rcv_specific(3), rmr_rts_msg(3), rmr_ready(3), 
+rmr_fib(3), rmr_has_str(3), rmr_set_stimeout(3), 
+rmr_tokenise(3), rmr_mk_ring(3), rmr_ring_free(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_wh_open 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ void rmr_close( void* vctx )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_close function closes the listen socket effectively 
+cutting the application off. The route table listener is also 
+stopped. Calls to rmr_rcv_msg() will fail with unpredictable 
+error codes, and calls to rmr_send_msg(), rmr_call(), and 
+rmr_rts_msg() will have unknown results. 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), 
+rmr_get_rcvfd(3), rmr_payload_size(3), rmr_send_msg(3), 
+rmr_rcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), 
+rmr_ready(3), rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), 
+rmr_mk_ring(3), rmr_ring_free(3), rmr_wh_open(3), 
+rmr_wh_send_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_free_msg 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ void rmr_free_msg( rmr_mbuf_t* mbuf );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The message buffer is returned to the pool, or the associated 
+memory is released depending on the needs of the underlying 
+messaging system. This allows the user application to release 
+a buffer that is not going to be used. It is safe to pass a 
+nil pointer to this function, and doing so does not result in 
+a change to the value of errrno. 
+After calling, the user application should **not** use any of 
+the pointers (transaction ID, or payload) which were 
+available. 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_init(3), 
+rmr_payload_size(3), rmr_send_msg(3), rmr_rcv_msg(3), 
+rmr_rcv_specific(3), rmr_rts_msg(3), rmr_ready(3), 
+rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), rmr_mk_ring(3), 
+rmr_ring_free(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_get_meid 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ char* rmr_get_meid( rmr_mbuf_t* mbuf, unsigned char* dest )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_get_meid function will copy the managed equipment ID 
+(meid) field from the message into the *dest* buffer provided 
+by the user. The buffer referenced by * dest * is assumed to 
+be at least RMR_MAX_MEID bytes in length. If * dest * is 
+NULL, then a buffer is allocated (the calling application is 
+expected to free when the buffer is no longer needed). 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+On success, a pointer to the extracted string is returned. If 
+* dest * was supplied, then this is just a pointer to the 
+caller's buffer. If * dest * was NULL, this is a pointer to 
+the allocated buffer. If an error occurs, a nil pointer is 
+returned and errno is set as described below. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+If an error occurs, the value of the global variable errno 
+will be set to one of the following with the indicated 
+meaning. 
+EINVAL 
+   
+  The message, or an internal portion of the message, was 
+  corrupted or the pointer was invalid. 
+   
+ENOMEM 
+   
+  A nil pointer was passed for * dest, * however it was not 
+  possible to allocate a buffer using malloc(). 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_bytes2xact(3), rmr_bytes2meid(3), 
+rmr_call(3), rmr_free_msg(3), rmr_get_rcvfd(3), 
+rmr_get_xact(3), rmr_payload_size(3), rmr_send_msg(3), 
+rmr_rcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), 
+rmr_ready(3), rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), 
+rmr_mk_ring(3), rmr_ring_free(3), rmr_str2meid(3), 
+rmr_str2xact(3), rmr_wh_open(3), rmr_wh_send_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_get_rcvfd 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ void* rmr_get_rcvfd( void* ctx )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_get_rcvfd function returns a file descriptor which 
+may be given to epoll_wait() by an application that wishes to 
+use event poll in a single thread rather than block on the 
+arrival of a message via calls to rmr_rcv_msg(). When 
+epoll_wait() indicates that this file descriptor is ready, a 
+call to rmr_rcv_msg() will not block as at least one message 
+has been received. 
+The context (ctx) pointer passed in is the pointer returned 
+by the call to rmr_init(). 
+**NOTE:** There is no support for epoll in Nanomsg, thus his 
+function is only supported when linking with the NNG version 
+of RMr and the file descriptor returned when using the 
+Nanomsg verfsion will always return an error. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+The rmr_get_rcvfd function returns a file descriptor greater 
+or equal to 0 on success and -1 on error. If this function is 
+called from a user application linked against the Nanomsg RMr 
+library, calls will always return -1 with errno set to 
+EINVAL. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+The following error values are specifically set by this RMR 
+function. In some cases the error message of a system call is 
+propagated up, and thus this list might be incomplete. 
+EINVAL 
+   
+  The use of this function is invalid in this environment. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+The following short code bit illustrates the use of this 
+function. Error checking has been omitted for clarity. 
+:: 
+  
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <sys/epoll.h>
+ #include <rmr/rmr.h>
+ int main() {
+     int rcv_fd;     // pollable fd
+     void* mrc;      //msg router context
+     struct epoll_event events[10];          // support 10 events to poll
+     struct epoll_event epe;                 // event definition for event to listen to
+     int     ep_fd = -1;
+     rmr_mbuf_t* msg = NULL;
+     int nready;
+     int i;
+  
+     mrc = rmr_init( "43086", RMR_MAX_RCV_BYTES, RMRFL_NONE );
+     rcv_fd = rmr_get_rcvfd( mrc );
+  
+     rep_fd = epoll_create1( 0 );    _    B    ,// initialise epoll environment
+     epe.events = EPOLLIN;
+     epe.data.fd = rcv_fd;
+     epoll_ctl( ep_fd, EPOLL_CTL_ADD, rcv_fd, &epe );    // add our info to the mix
+  
+     while( 1 ) {
+         nready = epoll_wait( ep_fd, events, 10, -1 );       // -1 == block forever (no timeout)
+         for( i = 0; i < nready && i < 10; i++ ) {           // loop through to find what is ready
+             if( events[i].data.fd == rcv_fd ) {             // RMr has something
+                 msg = rmr_rcv_msg( mrc, msg );
+                 if( msg ) {
+                     // do something with msg
+                 }
+             }
+  
+             // check for other ready fds....
+         }
+     }
+ }
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), 
+rmr_payload_size(3), rmr_send_msg(3), rmr_rcv_msg(3), 
+rmr_rcv_specific(3), rmr_rts_msg(3), rmr_ready(3), 
+rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), rmr_mk_ring(3), 
+rmr_ring_free(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_get_src 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ unsigned char* rmr_get_src( rmr_mbuf_t* mbuf, unsigned char* dest )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_get_src function will copy the *source* information 
+from the message to a buffer (dest) supplied by the user. In 
+an RMr message, the source is the sender's information that 
+is used for return to sender function calls, and is generally 
+the hostname and port in the form *name*. The source might be 
+an IP address port combination; the data is populated by the 
+sending process and the only requirement is that it be 
+capable of being used to start a TCP session with the sender. 
+The maximum size allowed by RMr is 64 bytes (including the 
+nil string terminator), so the user must ensure that the 
+destination buffer given is at least 64 bytes. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+On success, a pointer to the destination buffer is given as a 
+convenience to the user programme. On failure, a nil pointer 
+is returned and the value of errno is set. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+If an error occurs, the value of the global variable errno 
+will be set to one of the following with the indicated 
+meaning. 
+EINVAL 
+   
+  The message, or an internal portion of the message, was 
+  corrupted or the pointer was invalid. 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_bytes2xact(3), rmr_bytes2meid(3), 
+rmr_call(3), rmr_free_msg(3), rmr_get_rcvfd(3), 
+rmr_get_srcip(3), rmr_payload_size(3), rmr_send_msg(3), 
+rmr_rcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), 
+rmr_ready(3), rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), 
+rmr_mk_ring(3), rmr_ring_free(3), rmr_str2meid(3), 
+rmr_str2xact(3), rmr_wh_open(3), rmr_wh_send_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_get_srcip 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ unsigned char* rmr_get_srcip( rmr_mbuf_t* mbuf, unsigned char* dest )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_get_srcip function will copy the *source IP address* 
+from the message to a buffer (dest) supplied by the user. In 
+an RMr message, the source IP address is the sender's 
+information that is used for return to sender function calls; 
+this function makes it available to the user application. The 
+address is maintained as IP:port where *IP* could be either 
+an IPv6 or IPv4 address depending on what was provided by the 
+sending application. 
+The maximum size allowed by RMr is 64 bytes (including the 
+nil string terminator), so the user must ensure that the 
+destination buffer given is at least 64 bytes. The user 
+application should use the RMr constant RMR_MAX_SRC to ensure 
+that the buffer supplied is large enough, and to protect 
+against future RMr enhancements which might increase the 
+address buffer size requirement. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+On success, a pointer to the destination buffer is given as a 
+convenience to the user programme. On failure, a nil pointer 
+is returned and the value of errno is set. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+If an error occurs, the value of the global variable errno 
+will be set to one of the following with the indicated 
+meaning. 
+EINVAL 
+   
+  The message, or an internal portion of the message, was 
+  corrupted or the pointer was invalid. 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_bytes2xact(3), rmr_bytes2meid(3), 
+rmr_call(3), rmr_free_msg(3), rmr_get_rcvfd(3), 
+rmr_get_src(3), rmr_payload_size(3), rmr_send_msg(3), 
+rmr_rcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), 
+rmr_ready(3), rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), 
+rmr_mk_ring(3), rmr_ring_free(3), rmr_str2meid(3), 
+rmr_str2xact(3), rmr_wh_open(3), rmr_wh_send_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_get_trace 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ int rmr_get_trace( rmr_mbuf_t* mbuf, unsigned char* dest, int size )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_get_trace function will copy the trace information 
+from the message into the user's allocated memory referenced 
+by dest. The size parameter is assumed to be the maximum 
+number of bytes which can be copied (size of the destination 
+buffer). 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+On success, the number of bytes actually copied is returned. 
+If the return value is 0, no bytes copied, then the reason 
+could be that the message pointer was nil, or the size 
+parameter was <= 0. 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_tralloc_msg(3), rmr_bytes2xact(3), 
+rmr_bytes2meid(3), rmr_call(3), rmr_free_msg(3), 
+rmr_get_rcvfd(3), rmr_get_trlen(3), rmr_init(3), 
+rmr_init_trace(3), rmr_payload_size(3), rmr_send_msg(3), 
+rmr_rcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), 
+rmr_ready(3), rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), 
+rmr_mk_ring(3), rmr_ring_free(3), rmr_str2meid(3), 
+rmr_str2xact(3), rmr_wh_open(3), rmr_wh_send_msg(3), 
+rmr_set_trace(3), rmr_trace_ref(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_get_trlen 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ int rmr_get_trlen( rmr_mbuf_t* msg );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+Given a message buffer, this function returns the amount of 
+space (bytes) that have been allocated for trace data. If no 
+trace data has been allocated, then 0 is returned. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+The number of bytes allocated for trace information in the 
+given message. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+INVAL 
+   
+  Parameter(s) passed to the function were not valid. 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), 
+rmr_get_trace(3), rmr_init(3), rmr_init_trace(3), 
+rmr_send_msg(3), rmr_rcv_msg(3), rmr_rcv_specific(3), 
+rmr_rts_msg(3), rmr_ready(3), rmr_fib(3), rmr_has_str(3), 
+rmr_tokenise(3), rmr_mk_ring(3), rmr_ring_free(3), 
+rmr_set_trace(3), rmr_tralloc_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_get_xact 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ char* rmr_get_xact( rmr_mbuf_t* mbuf, unsigned char* dest )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_get_xact function will copy the transaction field 
+from the message into the *dest* buffer provided by the user. 
+The buffer referenced by * dest * is assumed to be at least 
+RMR_MAX_XID bytes in length. If * dest * is NULL, then a 
+buffer is allocated (the calling application is expected to 
+free when the buffer is no longer needed). 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+On success, a pointer to the extracted string is returned. If 
+* dest * was supplied, then this is just a pointer to the 
+caller's buffer. If * dest * was NULL, this is a pointer to 
+the allocated buffer. If an error occurs, a nil pointer is 
+returned and errno is set as described below. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+If an error occurs, the value of the global variable errno 
+will be set to one of the following with the indicated 
+meaning. 
+EINVAL 
+   
+  The message, or an internal portion of the message, was 
+  corrupted or the pointer was invalid. 
+   
+ENOMEM 
+   
+  A nil pointer was passed for * dest, * however it was not 
+  possible to allocate a buffer using malloc(). 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_bytes2xact(3), rmr_bytes2meid(3), 
+rmr_call(3), rmr_free_msg(3), rmr_get_rcvfd(3), 
+rmr_get_meid(3), rmr_payload_size(3), rmr_send_msg(3), 
+rmr_rcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), 
+rmr_ready(3), rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), 
+rmr_mk_ring(3), rmr_ring_free(3), rmr_str2meid(3), 
+rmr_str2xact(3), rmr_wh_open(3), rmr_wh_send_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_init 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ void* rmr_init( char* proto_port, int max_msg_size, int flags );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_init function prepares the environment for sending 
+and receiving messages. It does so by establishing a worker 
+thread (pthread) which subscribes to a route table generator 
+which provides the necessary routing information for the RMR 
+library to send messages. 
+*Port* is used to listen for connection requests from other 
+RMR based applications. The value of *max_msg_size* will be 
+used when allocating zero copy send buffers which must be 
+allocated, possibly, prior to the application knowing the 
+actual size of a specific message. 
+*Flags* allows for selection of some RMr options at the time 
+of initialisation. These are set by ORing RMRFL_ constants 
+from the RMr header file. Currently the following flags are 
+supported: 
+RMRFL_NONE 
+   
+  No flags are set. 
+   
+RMRFL_NOTHREAD 
+   
+  The route table collector thread is not to be started. 
+  This should only be used by the route table generator 
+  application if it is based on RMr. 
+   
+RMRFL_MTCALL 
+   
+  Enable multi-threaded call support. 
+Multi-threaded Calling 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+The support for an application to issue a *blocking call* by 
+the rmr_call() function was limited such that only user 
+applications which were operating in a single thread could 
+safely use the function. Further, timeouts were message count 
+based and not time unit based. Multi-threaded call support 
+adds the ability for a user application with multiple threads 
+to invoke a blocking call function with the guarentee that 
+the correct response message is delivered to the thread. The 
+additional support is implemented with the * rmr_mt_call() * 
+and * rmr_mt_rcv() * function calls. 
+Multi-threaded call support requires the user application to 
+specifically enable it when RMr is initialised. This is 
+necessary because a second, dedicated, receiver thread must 
+be started, and requires all messages to be examined and 
+queued by this thread. The additional overhead is minimal, 
+queuing information is all in the RMr message header, but as 
+an additional process is necessary the user application must 
+"opt in" to this approach. 
+ENVIRONMENT 
+-------------------------------------------------------------------------------------------- 
+As a part of the initialisation process rmr_init will look 
+into the available environment variables to influence it's 
+setup. The following variables will be used when found. 
+RMR_SEED_RT 
+   
+  Assumes this is the filename of the seed route table file 
+  to use. In normal situations, the library will wait for an 
+  update from the route table generator (expected within a 
+  few seconds of initialisation) before being able to send 
+  messages. However, in some situations where a bootstrap 
+  table is necessary, this is the means to supply it to the 
+  library. 
+   
+RMR_RTG_SVC 
+   
+  The route table generator assumes that RMr is listening on 
+  a well known port (4561) by default, but this environment 
+  variable can be used to change the listening port if 
+  needed. The value of the variable is expected to be just 
+  the port. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+The rmr_init function returns a void pointer (a contex if you 
+will) that is passed as the first parameter to nearly all 
+other RMR functions. If rmr_init is unable to properly 
+initialise the environment, NULL is returned and errno is set 
+to an appropriate value. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+The following error values are specifically set by this RMR 
+function. In some cases the error message of a system call is 
+propagated up, and thus this list might be incomplete. 
+ENOMEM 
+   
+  Unable to allocate memory. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+    void*  uh;
+    rmr_mbuf* buf = NULL;
+    uh = rmr_init( "43086", 4096, 0 );
+    buf = rmr_rcv_msg( uh, buf );
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), 
+rmr_get_rcvfd(3), rmr_mt_call(3), rmr_mt_rcv(3), 
+rmr_payload_size(3), rmr_send_msg(3), rmr_rcv_msg(3), 
+rmr_rcv_specific(3), rmr_rts_msg(3), rmr_ready(3), 
+rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), rmr_mk_ring(3), 
+rmr_ring_free(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_init_trace 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ void* rmr_init_trace( void* ctx )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_init_trace function establishes the default trace 
+space placed in each message buffer allocated with 
+rmr_alloc_msg(). If this function is never called, then no 
+trace space is allocated by default into any message buffer. 
+Trace space allows the user application to pass some trace 
+token, or other data with the message, but outside of the 
+payload. Trace data may be added to any message with 
+rmr_set_trace(), and may be extracted from a message with 
+rmr_get_trace(). The number of bytes that a message contains 
+for/with trace data can be determined by invoking 
+rmr_get_trlen(). 
+This function may be safely called at any time during the 
+life of the user programme to (re)set the default trace space 
+reserved. If the user programme needs to allocate a message 
+with trace space of a different size than is allocated by 
+default, without fear of extra overhead of reallocating a 
+message later, the rmr_tralloc_msg() function can be used. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+A value of 1 is returned on success, and 0 on failure. A 
+failure indicates that the RMr context (void *) passed to 
+this function was not valid. 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_tr_alloc_msg(3), rmr_call(3), 
+rmr_free_msg(3), rmr_get_rcvfd(3), rmr_get_trace(3), 
+rmr_get_trlen(3), rmr_payload_size(3), rmr_send_msg(3), 
+rmr_rcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), 
+rmr_ready(3), rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), 
+rmr_mk_ring(3), rmr_ring_free(3), rmr_set_trace(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_mt_call 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ extern rmr_mbuf_t* rmr_mt_call( void* vctx, rmr_mbuf_t* msg, int id, int timeout );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_mt_call function sends the user application message 
+to a remote endpoint, and waits for a corresponding response 
+message before returning control to the user application. The 
+user application supplies a completed message buffer, as it 
+would for a rmr_send_msg call, but unlike with a send, the 
+buffer returned will have the response from the application 
+that received the message. The thread invoking the * 
+rmr_mt_call()* will block until a message arrives or until 
+*timeout* milliseconds has passed; which ever comes first. 
+Using a timeout value of zero (0) will cause the thread to 
+block without a timeout. 
+The * id * supplied as the third parameter is an integer in 
+the range of 2 through 255 inclusive. This is a caller 
+defined "thread number" and is used to match the response 
+message with the correct user application thread. If the ID 
+value is not in the proper range, the attempt to make the 
+call will fail. 
+Messages which are received while waiting for the response 
+are queued on a *normal* receive queue and will be delivered 
+to the user application with the next invocation of * 
+rmr_mt_rcv() * or * rmr_rvv_msg().* by RMR, and are returned 
+to the user application when rmr_rcv_msg is invoked. These 
+messages are returned in th order received, one per call to 
+rmr_rcv_msg. 
+NOTE: Currently the multi-threaded functions are supported 
+only when the NNG transport mechanism is being used. It will 
+not be possible to link a programme using the Nanomsg version 
+of the library when references to this function are present. 
+The Transaction ID 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+The user application is responsible for setting the value of 
+the transaction ID field before invoking *rmr_mt_call.* The 
+transaction ID is a RMR_MAX_XID byte field that is used to 
+match the response message when it arrives. RMr will compare 
+**all** of the bytes in the field, so the caller must ensure 
+that they are set correctly to avoid missing the response 
+message. (The application which returns the response message 
+is also expected to ensure that the return buffer has the 
+matching transaction ID. This can be done transparently if 
+the application uses the * rmr_rts_msg() * function and does 
+not adjust the transaction ID. 
+Retries 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+The send operations in RMr will retry *soft* send failures 
+until one of three conditions occurs: 
+1. 
+   
+  The message is sent without error 
+   
+2. 
+   
+  The underlying transport reports a * hard * failure 
+   
+3. 
+   
+  The maximum number of retry loops has been attempted 
+A retry loop consists of approximately 1000 send attemps ** 
+without** any intervening calls to * sleep() * or * usleep(). 
+* The number of retry loops defaults to 1, thus a maximum of 
+1000 send attempts is performed before returning to the user 
+application. This value can be set at any point after RMr 
+initialisation using the * rmr_set_stimeout() * function 
+allowing the user application to completely disable retires 
+(set to 0), or to increase the number of retry loops. 
+Transport Level Blocking 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+The underlying transport mechanism used to send messages is 
+configured in *non-blocking* mode. This means that if a 
+message cannot be sent immediately the transport mechanism 
+will **not** pause with the assumption that the inability to 
+send will clear quickly (within a few milliseconds). This 
+means that when the retry loop is completely disabled (set to 
+0), that the failure to accept a message for sending by the 
+underlying mechanisms (software or hardware) will be reported 
+immediately to the user application. 
+It should be noted that depending on the underlying transport 
+mechanism being used, it is extremly possible that during 
+normal operations that retry conditions are very likely to 
+happen. These are completely out of RMr's control, and there 
+is nothing that RMr can do to avoid or midigate these other 
+than by allowing RMr to retry the send operation, and even 
+then it is possible (e.g. during connection reattempts), that 
+a single retry loop is not enough to guarentee a successful 
+send. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+The rmr_mt_call function returns a pointer to a message 
+buffer with the state set to reflect the overall state of 
+call processing. If the state is RMR_OK then the buffer 
+contains the response message; otherwise the state indicates 
+the error encountered while attempting to send the message. 
+If no response message is received when the timeout period 
+has expired, a nil pointer will be returned (NULL). 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+These values are reflected in the state field of the returned 
+message. 
+RMR_OK 
+   
+  The call was successful and the message buffer references 
+  the response message. 
+   
+RMR_ERR_BADARG 
+   
+  An argument passed to the function was invalid. 
+   
+RMR_ERR_CALLFAILED 
+   
+  The call failed and the value of *errno,* as described 
+  below, should be checked for the specific reason. 
+   
+RMR_ERR_NOENDPT 
+   
+  An endpoint associated with the message type could not be 
+  found in the route table. 
+   
+RMR_ERR_RETRY 
+   
+  The underlying transport mechanism was unable to accept 
+  the message for sending. The user application can retry 
+  the call operation if appropriate to do so. 
+The global "variable" *errno* will be set to one of the 
+following values if the overall call processing was not 
+successful. 
+ETIMEDOUT 
+   
+  Too many messages were queued before receiving the 
+  expected response 
+   
+ENOBUFS 
+   
+  The queued message ring is full, messages were dropped 
+   
+EINVAL 
+   
+  A parameter was not valid 
+   
+EAGAIN 
+   
+  The underlying message system wsa interrupted or the 
+  device was busy; the message was **not** sent, and user 
+  application should call this function with the message 
+  again. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+The following code bit shows one way of using the rmr_mt_call 
+function, and illustrates how the transaction ID must be set. 
+:: 
+  
+     int retries_left = 5;               // max retries on dev not available
+     static rmr_mbuf_t*  mbuf = NULL;    // response msg
+     msg_t*  pm;                         // private message (payload)
+     m// get a send buffer and reference the payload 
+     mbuf = rmr_alloc_msg( mr, RMR_MAX_RCV_BYTES );
+     pm = (msg_t*) mbuf->payload;
+     p// generate an xaction ID and fill in payload with data and msg type
+     rmr_bytes2xact( mbuf, xid, RMR_MAX_XID );
+     snprintf( pm->req, sizeof( pm->req ), "{ \\"req\\": \\"num users\\"}" );
+     mbuf->mtype = MT_USR_RESP;
+     
+     msg = rmr_mt_call( mr, msg, my_id, 100 );    e    :// wait up to 100ms
+     if( ! msg ) {               // probably a timeout and no msg received
+         return NULL;            // let errno trickle up
+     } 
+     if( mbuf->state != RMR_OK ) {
+         while( retries_left-- > 0 &&             // loop as long as eagain
+                mbuf->state == RMR_ERR_RETRY && 
+                (msg = rmr_mt_call( mr, msg )) != NULL && 
+                mbuf->state != RMR_OK ) {
+             usleep( retry_delay );
+         }
+     
+         if( mbuf == NULL || mbuf->state != RMR_OK ) {
+             rmr_free_msg( mbuf );        // safe if nil
+             return NULL;
+         }
+     }
+     // do something with mbuf
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_free_msg(3), rmr_init(3), 
+rmr_mt_rcv(3), rmr_payload_size(3), rmr_send_msg(3), 
+rmr_rcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), 
+rmr_ready(3), rmr_fib(3), rmr_has_str(3), 
+rmr_set_stimeout(3), rmr_tokenise(3), rmr_mk_ring(3), 
+rmr_ring_free(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_mt_rcv 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ rmr_mbuf_t* rmr_mt_rcv( void* vctx, rmr_mbuf_t* old_msg, int timeout );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_mt_rcv function blocks until a message is received, 
+or the timeout period (milliseconds) has passed. The result 
+is an RMr message buffer which references a received message. 
+In the case of a timeout the state will be reflected in an 
+"empty buffer" (if old_msg was not nil, or simply with the 
+return of a nil pointer. If a timeout value of zero (0) is 
+given, then the function will block until the next message 
+received. 
+The *vctx* pointer is the pointer returned by the rmr_init 
+function. *Old_msg* is a pointer to a previously used message 
+buffer or NULL. The ability to reuse message buffers helps to 
+avoid alloc/free cycles in the user application. When no 
+buffer is available to supply, the receive function will 
+allocate one. 
+The *old_msg* parameter allows the user to pass a previously 
+generated RMr message back to RMr for reuse. Optionally, the 
+user application may pass a nil pointer if no reusable 
+message is available. When a timeout occurs, and old_msg was 
+not nil, the state will be returned by returning a pointer to 
+the old message with the state set. 
+It is possible to use the *rmr_rcv_msg()* function instead of 
+this function. Doing so might be advantagous if the user 
+programme does not always start the multi-threaded mode and 
+the use of *rmr_rcv_msg()* would make the flow of the code 
+more simple. The advantags of using this function are the 
+ability to set a timeout without using epoll, and a small 
+performance gain (if multi-threaded mode is enabled, and the 
+*rmr_rcv_msg()* function is used, it simply invokes this 
+function without a timeout value, thus there is the small 
+cost of a second call that results). Similarly, the 
+*rmr_torcv_msg()* call can be used when in multi-threaded 
+mode with the same "pass through" overhead to using this 
+function directly. 
+NOTE: Currently the multi-threaded functions are supported 
+only when the NNG transport mechanism is being used. It will 
+not be possible to link a programme using the nanomsg version 
+of the library when references to this function are present. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+When a message is received before the timeout period expires, 
+a pointer to the RMr message buffer which describes the 
+message is returned. This will, with a high probability, be a 
+different message buffer than *old_msg;* the user application 
+should not continue to use *old_msg* after it is passed to 
+this function. 
+In the event of a timeout the return value will be the old 
+msg with the state set, or a nil pointer if no old message 
+was provided. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+The *state* field in the message buffer will be set to one of 
+the following values: 
+RMR_OK 
+   
+  The message was received without error. 
+   
+RMR_ERR_BADARG 
+   
+  A parameter passed to the function was not valid (e.g. a 
+  nil pointer). indicate either RMR_OK or RMR_ERR_EMPTY if 
+  an empty message was received. 
+   
+RMR_ERR_EMPTY 
+   
+  The message received had no associated data. The length of 
+  the message will be 0. 
+   
+RMR_ERR_NOTSUPP 
+   
+  The multi-threaded option was not enabled when RMr was 
+  initialised. See the man page for *rmr_init() * for 
+  details. 
+   
+RMR_ERR_RCVFAILED 
+   
+  A hard error occurred preventing the receive from 
+  completing. 
+When a nil pointer is returned, or any other state value was 
+set in the message buffer, errno will be set to one of the 
+following: 
+INVAL 
+   
+  Parameter(s) passed to the function were not valid. 
+   
+EBADF 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+ENOTSUP 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+EFSM 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+EAGAIN 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+EINTR 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+ETIMEDOUT 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+ETERM 
+   
+  The underlying message transport is unable to process the 
+  request. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+     rmr_mbuf_t*  mbuf = NULL;   // received msg
+     msg = rmr_mt_recv( mr, mbuf, 100 );     // wait up to 100ms
+     if( msg != NULL ) {
+         switch( msg->state ) {
+             case RMR_OK:
+                 printf( "got a good message\\n" );
+                 break;
+             case RMR_ERR_EMPTY:
+                 printf( "received timed out\\n" );
+                 break;
+             default:
+                 printf( "receive error: %d\\n", mbuf->state );
+                 break;
+         }
+     } else {
+         printf( "receive timeout (nil)\\n" );
+     }
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), 
+rmr_get_rcvfd(3), rmr_init(3), rmr_mk_ring(3), 
+rmr_mt_call(3), rmr_payload_size(3), rmr_send_msg(3), 
+rmr_torcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), 
+rmr_ready(3), rmr_ring_free(3), rmr_torcv_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_payload_size 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ int rmr_payload_size( rmr_mbuf_t* msg );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+Given a message buffer, this function returns the amount of 
+space (bytes) available for the user application to consume 
+in the message payload. This is different than the message 
+length available as a field in the message buffer. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+The number of bytes available in the payload. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+INVAL 
+   
+  Parameter(s) passed to the function were not valid. 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), rmr_init(3), 
+rmr_send_msg(3), rmr_rcv_msg(3), rmr_rcv_specific(3), 
+rmr_rts_msg(3), rmr_ready(3), rmr_fib(3), rmr_has_str(3), 
+rmr_tokenise(3), rmr_mk_ring(3), rmr_ring_free(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_rcv_msg 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ rmr_mbuf_t* rmr_rcv_msg( void* vctx, rmr_mbuf_t* old_msg );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_rcv_msg function blocks until a message is received, 
+returning the message to the caller via a pointer to a 
+rmr_mbuf_t structure type. If messages were queued while 
+waiting for the response to a previous invocation of 
+rmr_call, the oldest message is removed from the queue and 
+returned without delay. 
+The *vctx* pointer is the pointer returned by the rmr_init 
+function. *Old_msg* is a pointer to a previously used message 
+buffer or NULL. The ability to reuse message buffers helps to 
+avoid alloc/free cycles in the user application. When no 
+buffer is available to supply, the receive function will 
+allocate one. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+The function returns a pointer to the rmr_mbuf_t structure 
+which references the message information (state, length, 
+payload), or a NULL pointer in the case of an extreme error. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+The *state* field in the message buffer will indicate either 
+RMR_OK or RMR_ERR_EMPTY if an empty message was received. If 
+a nil pointer is returned, or any other state value was set 
+in the message buffer, errno will be set to one of the 
+following: 
+INVAL 
+   
+  Parameter(s) passed to the function were not valid. 
+   
+EBADF 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+ENOTSUP 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+EFSM 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+EAGAIN 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+EINTR 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+ETIMEDOUT 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+ETERM 
+   
+  The underlying message transport is unable to process the 
+  request. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), 
+rmr_get_rcvfd(3), rmr_init(3), rmr_mk_ring(3), 
+rmr_payload_size(3), rmr_send_msg(3), rmr_torcv_msg(3), 
+rmr_rcv_specific(3), rmr_rts_msg(3), rmr_ready(3), 
+rmr_ring_free(3), rmr_torcv_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_ready 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ int rmr_ready( void* vctx );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_ready function checks to see if a routing table has 
+been successfully received and installed. The return value 
+indicates the state of readiness. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+A return value of 1 (true) indicates that the routing table 
+is in place and attempts to send messages can be made. When 0 
+is returned (false) the routing table has not been received 
+and thus attempts to send messages will fail with *no 
+endpoint* errors. 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), rmr_init(3), 
+rmr_payload_size(3), rmr_send_msg(3), rmr_rcv_msg(3), 
+rmr_rcv_specific(3), rmr_rts_msg(3), rmr_fib(3), 
+rmr_has_str(3), rmr_tokenise(3), rmr_mk_ring(3), 
+rmr_ring_free(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_realloc_payload 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ extern rmr_mbuf_t* rmr_realloc_payload( rmr_mbuf_t* msg, int new_len, int copy, int clone );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_realloc_payload function will return a pointer to an 
+RMR message buffer struct (rmr_mbuf_t) which has a payload 
+large enough to accomodate *new_len* bytes. If necessary, the 
+underlying payload is reallocated, and the bytes from the 
+original payload are copied if the *copy* parameter is true 
+(1). If the message passed in has a payload large enough, 
+there is no additional memory allocation and copying. 
+Cloning The Message Buffer 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+This function can also be used to generate a separate copy of 
+the original message, with the desired payload size, without 
+destroying the original message buffer or the original 
+payload. A standalone copy is made only when the *clone* 
+parameter is true (1). When cloning, the payload is copied to 
+the cloned message **only** if the *copy* parameter is true. 
+Message Buffer Metadata 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+The metadata in the original message buffer (message type, 
+subscription ID, and payload length) will be preserved if the 
+*copy* parameter is true. When this parameter is not true 
+(0), then these values are set to the uninitialised value 
+(-1) for type and ID, and the length is set to 0. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+The rmr_realloc_payload function returns a pointer to the 
+message buffer with the payload which is large enough to hold 
+*new_len* bytes. If the *clone* option is true, this will be 
+a pointer to the newly cloned message buffer; the original 
+message buffer pointer may still be used to referenced that 
+message. It is the calling application's responsibility to 
+free the memory associateed with both messages using the 
+rmr_free_msg() function. 
+When the *clone* option is not used, it is still good 
+practice by the calling application to capture and use this 
+reference as it is possible that the message buffer, and not 
+just the payload buffer, was reallocated. In the event of an 
+error, a nil pointer will be returned and the value of 
+*errno* will be set to reflect the problem. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+These value of *errno* will reflect the error condition if a 
+nil pointer is returned: 
+ENOMEM 
+   
+  Memory allocation of the new payload failed. 
+   
+EINVAL 
+   
+  The pointer passed in was nil, or refrenced an invalid 
+  message, or the required length was not valid. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+The following code bit illustrates how this function can be 
+used to reallocate a buffer for a return to sender 
+acknowledgement message which is larger than the message 
+received. 
+:: 
+  
+   if( rmr_payload_size( msg ) < ack_sz ) {              // received message too small for ack
+     msg = rmr_realloc_payload( msg, ack_sz, 0, 0 );     // reallocate the message with a payload big enough
+     if( msg == NULL ) {
+       fprintf( stderr, "[ERR] realloc returned a nil pointer: %s\\n", strerror( errno ) );
+     } else {
+     }    e// populate and send ack message
+     }}
+ }
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_free_msg(3), rmr_init(3), 
+rmr_payload_size(3), rmr_send_msg(3), rmr_rcv_msg(3), 
+rmr_rcv_specific(3), rmr_rts_msg(3), rmr_ready(3), 
+rmr_fib(3), rmr_has_str(3), rmr_set_stimeout(3), 
+rmr_tokenise(3), rmr_mk_ring(3), rmr_ring_free(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_rts_msg 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ rmr_mbuf_t*  rmr_rts_msg( void* vctx, rmr_mbuf_t* msg );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_rts_msg function sends a message returning it to the 
+endpoint which sent the message rather than selecting an 
+endpoint based on the message type and routing table. Other 
+than this small difference, the behaviour is exactly the same 
+as rmr_send_msg. 
+Retries 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+The send operations in RMr will retry *soft* send failures 
+until one of three conditions occurs: 
+1. 
+   
+  The message is sent without error 
+   
+2. 
+   
+  The underlying transport reports a * hard * failure 
+   
+3. 
+   
+  The maximum number of retry loops has been attempted 
+A retry loop consists of approximately 1000 send attemps ** 
+without** any intervening calls to * sleep() * or * usleep(). 
+* The number of retry loops defaults to 1, thus a maximum of 
+1000 send attempts is performed before returning to the user 
+application. This value can be set at any point after RMr 
+initialisation using the * rmr_set_stimeout() * function 
+allowing the user application to completely disable retires 
+(set to 0), or to increase the number of retry loops. 
+Transport Level Blocking 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+The underlying transport mechanism used to send messages is 
+configured in *non-blocking* mode. This means that if a 
+message cannot be sent immediately the transport mechanism 
+will **not** pause with the assumption that the inability to 
+send will clear quickly (within a few milliseconds). This 
+means that when the retry loop is completely disabled (set to 
+0), that the failure to accept a message for sending by the 
+underlying mechanisms (software or hardware) will be reported 
+immediately to the user application. 
+It should be noted that depending on the underlying transport 
+mechanism being used, it is extremly possible that during 
+normal operations that retry conditions are very likely to 
+happen. These are completely out of RMr's control, and there 
+is nothing that RMr can do to avoid or midigate these other 
+than by allowing RMr to retry the send operation, and even 
+then it is possible (e.g. during connection reattempts), that 
+a single retry loop is not enough to guarentee a successful 
+send. 
+PAYLOAD SIZE 
+-------------------------------------------------------------------------------------------- 
+When crafting a response based on a received message, the 
+user application must take care not to write more bytes to 
+the message payload than the allocated message has. In the 
+case of a received message, it is possible that the response 
+needs to be larger than the payload associated with the 
+inbound message. In order to use the return to sender 
+function, the source infomration in the orignal message must 
+be present in the response; information which cannot be added 
+to a message buffer allocated through the standard RMR 
+allocation function. To allocate a buffer with a larger 
+payload, and which retains the necessary sender data needed 
+by this function, the *rmr_realloc_payload()* function must 
+be used to extend the payload to a size suitable for the 
+response. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+On success, a new message buffer, with an empty payload, is 
+returned for the application to use for the next send. The 
+state in this buffer will reflect the overall send operation 
+state and should be RMR_OK. 
+If the state in the returned buffer is anything other than 
+UT_OK, the user application may need to attempt a 
+retransmission of the message, or take other action depending 
+on the setting of errno as described below. 
+In the event of extreme failure, a NULL pointer is returned. 
+In this case the value of errno might be of some use, for 
+documentation, but there will be little that the user 
+application can do other than to move on. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+The following values may be passed back in the *state* field 
+of the returned message buffer. 
+RMR_ERR_BADARG 
+   
+  The message buffer pointer did not refer to a valid 
+  message. 
+RMR_ERR_NOHDR 
+   
+  The header in the message buffer was not valid or 
+  corrupted. 
+RMR_ERR_NOENDPT 
+   
+  The message type in the message buffer did not map to a 
+  known endpoint. 
+RMR_ERR_SENDFAILED 
+   
+  The send failed; errno has the possible reason. 
+The following values may be assigned to errno on failure. 
+INVAL 
+   
+  Parameter(s) passed to the function were not valid, or the 
+  underlying message processing environment was unable to 
+  interpret the message. 
+   
+ENOKEY 
+   
+  The header information in the message buffer was invalid. 
+   
+ENXIO 
+   
+  No known endpoint for the message could be found. 
+   
+EMSGSIZE 
+   
+  The underlying transport refused to accept the message 
+  because of a size value issue (message was not attempted 
+  to be sent). 
+   
+EFAULT 
+   
+  The message referenced by the message buffer is corrupt 
+  (NULL pointer or bad internal length). 
+   
+EBADF 
+   
+  Internal RMR error; information provided to the message 
+  transport environment was not valid. 
+   
+ENOTSUP 
+   
+  Sending was not supported by the underlying message 
+  transport. 
+   
+EFSM 
+   
+  The device is not in a state that can accept the message. 
+   
+EAGAIN 
+   
+  The device is not able to accept a message for sending. 
+  The user application should attempt to resend. 
+   
+EINTR 
+   
+  The operation was interrupted by delivery of a signal 
+  before the message was sent. 
+   
+ETIMEDOUT 
+   
+  The underlying message environment timed out during the 
+  send process. 
+   
+ETERM 
+   
+  The underlying message environment is in a shutdown state. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), rmr_init(3), 
+rmr_payload_size(3), rmr_send_msg(3), rmr_rcv_msg(3), 
+rmr_rcv_specific(3), rmr_ready(3), rmr_fib(3), 
+rmr_has_str(3), rmr_set_stimeout(3), rmr_tokenise(3), 
+rmr_mk_ring(3), rmr_ring_free(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_send_msg 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ rmr_mbuf_t* rmr_send_msg( void* vctx, rmr_mbuf_t* msg );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_send_msg function accepts a message buffer from the 
+user application and attempts to send it. The destination of 
+the message is selected based on the message type specified 
+in the message buffer, and the matching information in the 
+routing tables which are currently in use by the RMR library. 
+This may actually result in the sending of the message to 
+multiple destinations which could degrade expected overall 
+performance of the user application. (Limiting excessive 
+sending of messages is the responsibility of the 
+application(s) responsible for building the routing table 
+used by the RMR library, and not the responsibility of the 
+library.) 
+Retries 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+The send operations in RMr will retry *soft* send failures 
+until one of three conditions occurs: 
+1. 
+   
+  The message is sent without error 
+   
+2. 
+   
+  The underlying transport reports a * hard * failure 
+   
+3. 
+   
+  The maximum number of retry loops has been attempted 
+A retry loop consists of approximately 1000 send attemps ** 
+without** any intervening calls to * sleep() * or * usleep(). 
+* The number of retry loops defaults to 1, thus a maximum of 
+1000 send attempts is performed before returning to the user 
+application. This value can be set at any point after RMr 
+initialisation using the * rmr_set_stimeout() * function 
+allowing the user application to completely disable retires 
+(set to 0), or to increase the number of retry loops. 
+Transport Level Blocking 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+The underlying transport mechanism used to send messages is 
+configured in *non-blocking* mode. This means that if a 
+message cannot be sent immediately the transport mechanism 
+will **not** pause with the assumption that the inability to 
+send will clear quickly (within a few milliseconds). This 
+means that when the retry loop is completely disabled (set to 
+0), that the failure to accept a message for sending by the 
+underlying mechanisms (software or hardware) will be reported 
+immediately to the user application. 
+It should be noted that depending on the underlying transport 
+mechanism being used, it is extremly possible that during 
+normal operations that retry conditions are very likely to 
+happen. These are completely out of RMr's control, and there 
+is nothing that RMr can do to avoid or midigate these other 
+than by allowing RMr to retry the send operation, and even 
+then it is possible (e.g. during connection reattempts), that 
+a single retry loop is not enough to guarentee a successful 
+send. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+On success, a new message buffer, with an empty payload, is 
+returned for the application to use for the next send. The 
+state in this buffer will reflect the overall send operation 
+state and should be RMR_OK. 
+When the message cannot be successfully sent this function 
+will return the unsent (original) message buffer with the 
+state set to indicate the reason for failure. The value of * 
+errno * may also be set to reflect a more detailed failure 
+reason if it is known. 
+In the event of extreme failure, a NULL pointer is returned. 
+In this case the value of errno might be of some use, for 
+documentation, but there will be little that the user 
+application can do other than to move on. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+The following values may be passed back in the *state* field 
+of the returned message buffer. 
+RMR_RETRY 
+   
+  The message could not be sent, but the underlying 
+  transport mechanism indicates that the failure is 
+  temporary. If the send operation is tried again it might 
+  be successful. 
+RMR_SEND_FAILED 
+   
+  The send operation was not successful and the underlying 
+  transport mechanism indicates a permanent (hard) failure; 
+  retrying the send is not possible. 
+RMR_ERR_BADARG 
+   
+  The message buffer pointer did not refer to a valid 
+  message. 
+RMR_ERR_NOHDR 
+   
+  The header in the message buffer was not valid or 
+  corrupted. 
+RMR_ERR_NOENDPT 
+   
+  The message type in the message buffer did not map to a 
+  known endpoint. 
+The following values may be assigned to errno on failure. 
+INVAL 
+   
+  Parameter(s) passed to the function were not valid, or the 
+  underlying message processing environment was unable to 
+  interpret the message. 
+   
+ENOKEY 
+   
+  The header information in the message buffer was invalid. 
+   
+ENXIO 
+   
+  No known endpoint for the message could be found. 
+   
+EMSGSIZE 
+   
+  The underlying transport refused to accept the message 
+  because of a size value issue (message was not attempted 
+  to be sent). 
+   
+EFAULT 
+   
+  The message referenced by the message buffer is corrupt 
+  (NULL pointer or bad internal length). 
+   
+EBADF 
+   
+  Internal RMR error; information provided to the message 
+  transport environment was not valid. 
+   
+ENOTSUP 
+   
+  Sending was not supported by the underlying message 
+  transport. 
+   
+EFSM 
+   
+  The device is not in a state that can accept the message. 
+   
+EAGAIN 
+   
+  The device is not able to accept a message for sending. 
+  The user application should attempt to resend. 
+   
+EINTR 
+   
+  The operation was interrupted by delivery of a signal 
+  before the message was sent. 
+   
+ETIMEDOUT 
+   
+  The underlying message environment timed out during the 
+  send process. 
+   
+ETERM 
+   
+  The underlying message environment is in a shutdown state. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+The following is a simple example of how the rmr_send_msg 
+function is called. In this example, the send message buffer 
+is saved between calls and reused eliminating alloc/free 
+cycles. 
+:: 
+  
+     static rmr_mbuf_t*  send_msg = NULL;        // message to send; reused on each call
+     msg_t*  send_pm;                            // payload for send
+     msg_t*  pm;                                 // our message format in the received payload
+     mif( send_msg  == NULL ) {
+         send_msg = rmr_alloc_msg( mr, MAX_SIZE );    r// new buffer to send
+      }
+      // reference payload and fill in message type
+     pm = (msg_t*) send_msg->payload;
+     send_msg->mtype = MT_ANSWER;    
+     msg->len = generate_data( pm );         e// something that fills the payload in
+     msg = rmr_send_msg( mr, send_msg );
+     mif( ! msg ) {
+     m    !return ERROR;
+     m} else {
+     m    sif( msg->state != RMR_OK ) {
+     m    s    m// check for eagain, and resend if needed
+     m    s    m// else return error
+     m    s}
+     m}
+     mreturn OK;
+     m    r    ;
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), rmr_init(3), 
+rmr_payload_size(3), rmr_rcv_msg(3), rmr_rcv_specific(3), 
+rmr_rts_msg(3), rmr_ready(3), rmr_mk_ring(3), 
+rmr_ring_free(3), rmr_torcv_rcv(3), rmr_wh_send_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_set_stimeout 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ rmr_mbuf_t* rmr_set_stimeout( void* vctx, int rloops );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_set_stimeout function sets the configuration for how 
+RMr will retry message send operations which complete with 
+either a * timeout * or * again * completion value. (Send 
+operations include all of the possible message send 
+functions: * rmr_send_msg(), rmr_call(), rmr_rts_msg() * and 
+* rmr_wh_send_msg(). * The * rloops * parameter sets the 
+maximum number of retry loops that will be attempted before 
+giving up and returning the unsuccessful state to the user 
+application. Each retry loop is approximately 1000 attempts, 
+and RMr does ** not ** invoke any sleep function between 
+retries in the loop; a small, 1 mu-sec, sleep is executed 
+between loop sets if the * rloops * value is greater than 1. 
+Disabling Retries 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+By default, the send operations will execute with an * rloop 
+* setting of 1; each send operation will attempt to resend 
+the message approximately 1000 times before giving up. If the 
+user application does not want to have send operations retry 
+when the underlying transport mechanism indicates * timeout * 
+or * again, * the application should invoke this function and 
+pass a value of 0 (zero) for * rloops. * With this setting, 
+all RMr send operations will attempt a send operation only ** 
+once, ** returning immediately to the caller with the state 
+of that single attempt. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+This function returns a -1 to indicate that the * rloops * 
+value could not be set, and the value * RMR_OK * to indicate 
+success. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+Currently errno is ** not ** set by this function; the only 
+cause of a failure is an invalid context (* vctx *) pointer. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+The following is a simple example of how the rmr_set_stimeout 
+function is called. 
+:: 
+  
+     #define NO_FLAGS    0
+     char*    Oport = "43086";     // port for message router listen
+     int         rmax_size = 4096;    // max message size for default allocations
+     void*     mr_context;         // message router context
+     mr_context = rmr_init( port, max_size, NO_FLAGS );
+     if( mr_context != NULL ) {
+         rmr_set_stimeout( mr_context, 0 );    // turn off retries
+     }
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), rmr_init(3), 
+rmr_payload_size(3), rmr_rcv_msg(3), rmr_rcv_specific(3), 
+rmr_rts_msg(3), rmr_ready(3), rmr_mk_ring(3), 
+rmr_ring_free(3), rmr_send_msg(3), rmr_torcv_rcv(3), 
+rmr_wh_send_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_set_trace 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ int rmr_bytes2payload( rmr_mbuf_t* mbuf, unsigned char* data, int len )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_set_trace function will copy len bytes from data into 
+the trace portion of mbuf. If the trace area of mbuf is not 
+the correct size, the message buffer will be reallocated to 
+ensure that enough space is available for the trace data. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+The rmr_set_trace function returns the number of bytes 
+successfully copied to the message. If 0 is returned either 
+the message pointer was nil, or the size in the parameters 
+was <= 0. 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_tralloc_msg(3), rmr_bytes2xact(3), 
+rmr_bytes2payload(3), rmr_call(3), rmr_free_msg(3), 
+rmr_get_rcvfd(3), rmr_get_meid(3), rmr_get_trace(3), 
+rmr_get_trlen(3), rmr_init(3), rmr_init_trace(3), 
+rmr_payload_size(3), rmr_send_msg(3), rmr_rcv_msg(3), 
+rmr_rcv_specific(3), rmr_rts_msg(3), rmr_ready(3), 
+rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), rmr_mk_ring(3), 
+rmr_ring_free(3), rmr_str2meid(3), rmr_str2xact(3), 
+rmr_wh_open(3), rmr_wh_send_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_str2meid 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ int rmr_str2meid( rmr_mbuf_t* mbuf, unsigned char* src, int len )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_str2meid function will copy the string pointed to by 
+src to the managed equipment ID (meid) field in the given 
+message. The field is a fixed length, gated by the constant 
+RMR_MAX_MEID and if string length is larger than this value, 
+then **nothing** will be copied. (Note, this differs slightly 
+from the behaviour of the lrmr_bytes2meid() function.) 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+On success, the value RMR_OK is returned. If the string 
+cannot be copied to the message, the return value will be one 
+of the errors listed below. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+If the return value is not RMR_OK, then it will be set to one 
+of the values below. 
+RMR_ERR_BADARG 
+   
+  The message, or an internal portion of the message, was 
+  corrupted or the pointer was invalid. 
+   
+RMR_ERR_OVERFLOW 
+   
+  The length passed in was larger than the maximum length of 
+  the field; only a portion of the source bytes were copied. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), 
+rmr_get_meid(3), rmr_get_rcvfd(3), rmr_payload_size(3), 
+rmr_send_msg(3), rmr_rcv_msg(3), rmr_rcv_specific(3), 
+rmr_rts_msg(3), rmr_ready(3), rmr_fib(3), rmr_has_str(3), 
+rmr_tokenise(3), rmr_mk_ring(3), rmr_ring_free(3), 
+rmr_bytes2meid(3), rmr_wh_open(3), rmr_wh_send_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_str2xact 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ int rmr_str2xact( rmr_mbuf_t* mbuf, unsigned char* src, int len )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_str2xact function will copy the string pointed to by 
+src to the transaction ID (xaction) field in the given 
+message. The field is a fixed length, gated by the constant 
+RMR_MAX_XID and if string length is larger than this value, 
+then **nothing** will be copied. (Note, this differs slightly 
+from the behaviour of the lrmr_bytes2xact() function.) 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+On success, the value RMR_OK is returned. If the string 
+cannot be copied to the message, the return value will be 
+one of the errors listed below. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+If the return value is not RMR_OK, then it will be set to 
+one of the values below. 
+RMR_ERR_BADARG 
+   
+  The message, or an internal portion of the message, was 
+  corrupted or the pointer was invalid. 
+   
+RMR_ERR_OVERFLOW 
+   
+  The length passed in was larger than the maximum length of 
+  the field; only a portion of the source bytes were copied. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_bytes2meid(3), rmr_bytes2xact(3), 
+rmr_call(3), rmr_free_msg(3), rmr_get_meid(3), 
+rmr_get_rcvfd(3), rmr_get_xact(3), rmr_payload_size(3), 
+rmr_send_msg(3), rmr_rcv_msg(3), rmr_rcv_specific(3), 
+rmr_rts_msg(3), rmr_ready(3), rmr_fib(3), rmr_has_str(3), 
+rmr_tokenise(3), rmr_mk_ring(3), rmr_ring_free(3), 
+rmr_str2meid(3), rmr_wh_open(3), rmr_wh_send_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+RMR support functions 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ #include <rmr/ring_inline.h>
+ char* rmr_fib( char* fname );
+ int rmr_has_str( char const* buf, char const* str, char sep, int max );
+ int rmr_tokenise( char* buf, char** tokens, int max, char sep );
+ void* rmr_mk_ring( int size );
+ void rmr_ring_free( void* vr );
+ static inline void* rmr_ring_extract( void* vr )
+ static inline int rmr_ring_insert( void* vr, void* new_data )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+These functions support the RMR library, and are made 
+available to user applications as some (e.g. route table 
+generators) might need and/or want to make use of them. The 
+rmr_fib function accepts a file name and reads the entire 
+file into a single buffer. The intent is to provide an easy 
+way to load a static route table without a lot of buffered 
+I/O hoops. 
+The rmr_has_str function accepts a *buffer* containing a set 
+of delimited tokens (e.g. foo,bar,goo) and returns true if 
+the target string, *str,* matches one of the tokens. The 
+*sep* parameter provides the separation character in the 
+buffer (e.g a comma) and *max* indicates the maximum number 
+of tokens to split the buffer into before checking. 
+The rmr_tokenise function is a simple tokeniser which splits 
+*buf* into tokens at each occurrence of *sep*. Multiple 
+occurrences of the separator character (e.g. a,,b) result in 
+a nil token. Pointers to the tokens are placed into the 
+*tokens* array provided by the caller which is assumed to 
+have at least enough space for *max* entries. 
+The rmr_mk_ring function creates a buffer ring with *size* 
+entries. 
+The rmr_ring_free function accepts a pointer to a ring 
+context and frees the associated memory. 
+The rmr_ring_insert and rmr_ring_extract functions are 
+provided as static inline functions via the 
+*rmr/ring_inline.h* header file. These functions both accept 
+the ring *context* returned by mk_ring, and either insert a 
+pointer at the next available slot (tail) or extract the data 
+at the head. 
+RETURN VALUES 
+-------------------------------------------------------------------------------------------- 
+The following are the return values for each of these 
+functions. 
+The rmr_fib function returns a pointer to the buffer 
+containing the contents of the file. The buffer is terminated 
+with a single nil character (0) making it a legitimate C 
+string. If the file was empty or nonexistent, a buffer with 
+an immediate nil character. If it is important to the calling 
+programme to know if the file was empty or did not exist, the 
+caller should use the system stat function call to make that 
+determination. 
+The rmr_has_str function returns 1 if *buf* contains the 
+token referenced by &ita and false (0) if it does not. On 
+error, a -1 value is returned and errno is set accordingly. 
+The rmr_tokenise function returns the actual number of token 
+pointers placed into *tokens* 
+The rmr_mk_ring function returns a void pointer which is the 
+*context* for the ring. 
+The rmr_ring_insert function returns 1 if the data was 
+successfully inserted into the ring, and 0 if the ring is 
+full and the pointer could not be deposited. 
+The rmr_ring_extract will return the data which is at the 
+head of the ring, or NULL if the ring is empty. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+Not many of these functions set the value in errno, however 
+the value may be one of the following: 
+INVAL 
+   
+  Parameter(s) passed to the function were not valid. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), rmr_init(3), 
+rmr_payload_size(3), rmr_send_msg(3), rmr_rcv_msg(3), 
+rmr_rcv_specific(3), rmr_rts_msg(3), rmr_ready(3), 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_torcv_msg 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ rmr_mbuf_t* rmr_torcv_msg( void* vctx, rmr_mbuf_t* old_msg, int ms_to );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_torcv_msg function will pause for *ms_to* 
+milliseconds waiting for a message to arrive. If a message 
+arrives before the timeout expires the message buffer 
+returned will have a status of RMR_OK and the payload will 
+contain the data received. If the timeout expires before the 
+message is received, the status will have the value 
+RMR_ERR_TIMEOUT. When a received message is returned the 
+message buffer will also contain the message type and length 
+set by the sender. If messages were queued while waiting for 
+the response to a previous invocation of rmr_call, the oldest 
+message is removed from the queue and returned without delay. 
+The *vctx* pointer is the pointer returned by the rmr_init 
+function. *Old_msg* is a pointer to a previously used message 
+buffer or NULL. The ability to reuse message buffers helps to 
+avoid alloc/free cycles in the user application. When no 
+buffer is available to supply, the receive function will 
+allocate one. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+The function returns a pointer to the rmr_mbuf_t structure 
+which references the message information (state, length, 
+payload), or a NULL pointer in the case of an extreme error. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+The *state* field in the message buffer will be one of the 
+following: 
+RMR_OK 
+   
+  The message buffer (payload) references the received data. 
+   
+RMR_ERR_INITFAILED 
+   
+  The first call to this function must initialise an 
+  underlying system notification mechanism. On failure, this 
+  error is returned and errno will have the system error 
+  status set. If this function fails to intialise, the poll 
+  mechansim, it is likely that message receives will never 
+  be successful. 
+   
+RMR_ERR_TIMEOUT 
+   
+  The timeout expired before a complete message was 
+  received. All other fields in the message buffer are not 
+  valid. 
+   
+RMR_ERR_EMPTY 
+   
+  A message was received, but it had no payload. All other 
+  fields in the message buffer are not valid. 
+INVAL 
+   
+  Parameter(s) passed to the function were not valid. 
+   
+EBADF 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+ENOTSUP 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+EFSM 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+EAGAIN 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+EINTR 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+ETIMEDOUT 
+   
+  The underlying message transport is unable to process the 
+  request. 
+   
+ETERM 
+   
+  The underlying message transport is unable to process the 
+  request. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), 
+rmr_get_rcvfd(3), rmr_init(3), rmr_payload_size(3), 
+rmr_rcv_msg(3), rmr_send_msg(3), rmr_rcv_specific(3), 
+rmr_rts_msg(3), rmr_ready(3), rmr_fib(3), rmr_has_str(3), 
+rmr_tokenise(3), rmr_mk_ring(3), rmr_ring_free(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_trace_ref 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ int rmr_trace_ref( rmr_mbuf_t* mbuf, int* sizeptr )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_trace_ref function return a pointer to the trace area 
+in the message, and optionally populate the user programme 
+supplied size integer with the trace area size, if *sizeptr* 
+is not nil. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+On success, a void pointer to the trace area of the message 
+is returned. A nil pointer is returned if the message has no 
+trace data area allocated, or if the message itself is 
+invalid. 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_tralloc_msg(3), rmr_bytes2xact(3), 
+rmr_bytes2meid(3), rmr_call(3), rmr_free_msg(3), 
+rmr_get_rcvfd(3), rmr_get_trlen(3), rmr_init(3), 
+rmr_init_trace(3), rmr_payload_size(3), rmr_send_msg(3), 
+rmr_rcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), 
+rmr_ready(3), rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), 
+rmr_mk_ring(3), rmr_ring_free(3), rmr_str2meid(3), 
+rmr_str2xact(3), rmr_wh_open(3), rmr_wh_send_msg(3), 
+rmr_set_trace(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_tralloc_msg 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ rmr_mbuf_t* rmr_tralloc_msg( void* vctx, int size, 
+                              int trace_size, unsigned const char *tr_data );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_alloc_msg function is used to allocate a buffer which 
+the user programme can write into and then send through the a 
+library. The buffer is allocated such that sending it 
+requires no additional copying from the buffer as it passes 
+through the underlying transport mechanism. 
+The *size* parameter is used to set the payload length in the 
+message and If it is 0, then the default size supplied on the 
+*rmr_init* call will be used. In addition to allocating the 
+payload, a space in the buffer is reserved for *trace* data 
+(tr_size bytes), and the bytes pointed to by *tr_data* are 
+copied into that portion of the message. The *vctx* parameter 
+is the void context pointer that was returned by the 
+*rmr_init* function. 
+The pointer to the message buffer returned is a structure 
+which has some user application visible fields; the structure 
+is described in rmr.h, and is illustrated below. 
+:: 
+  
+ typedef struct {
+     int state;
+     int mtype;
+     int len;
+     unsigned char* payload;
+     unsigned char* xaction;
+ } rmr_mbuf_t;
+state 
+   
+  Is the current buffer state. Following a call to 
+  rmr_send_msg the state indicates whether the buffer was 
+  successfully sent which determines exactly what the 
+  payload points to. If the send failed, the payload 
+  referenced by the buffer is the message that failed to 
+  send (allowing the application to attempt a 
+  retransmission). When the state is a_OK the buffer 
+  represents an empty buffer that the application may fill 
+  in in preparation to send. 
+   
+mtype 
+   
+  When sending a message, the application is expected to set 
+  this field to the appropriate message type value (as 
+  determined by the user programme). Upon send this value 
+  determines how the a library will route the message. For a 
+  buffer which has been received, this field will contain 
+  the message type that was set by the sending application. 
+   
+len 
+   
+  The application using a buffer to send a message is 
+  expected to set the length value to the actual number of 
+  bytes that it placed into the message. This is likely less 
+  than the total number of bytes that the message can carry. 
+  For a message buffer that is passed to the application as 
+  the result of a receive call, this will be the value that 
+  the sending application supplied and should indicate the 
+  number of bytes in the payload which are valid. 
+   
+payload 
+   
+  The payload is a pointer to the actual received data. The 
+  user programme may read and write from/to the memory 
+  referenced by the payload up until the point in time that 
+  the buffer is used on a rmr_send, rmr_call or rmr_reply 
+  function call. Once the buffer has been passed back to a a 
+  library function the user programme should **NOT** make 
+  use of the payload pointer. 
+   
+xaction 
+   
+  The *xaction* field is a pointer to a fixed sized area in 
+  the message into which the user may write a transaction 
+  ID. The ID is optional with the exception of when the user 
+  application uses the rmr_call function to send a message 
+  and wait for the reply; the underlying a processing 
+  expects that the matching reply message will also contain 
+  the same data in the *xaction* field. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+The function returns a pointer to a rmr_mbuf structure, or 
+NULL on error. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+ENOMEM 
+   
+  Unable to allocate memory. 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_mbuf(3) rmr_call(3), rmr_free_msg(3), 
+rmr_init(3), rmr_init_trace(3), rmr_get_trace(3), 
+rmr_get_trlen(3), rmr_payload_size(3), rmr_send_msg(3), 
+rmr_rcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), 
+rmr_ready(3), rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), 
+rmr_mk_ring(3), rmr_ring_free(3), rmr_set_trace(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_wh_open 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ void rmr_close( void* vctx, rmr_whid_t whid )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_wh_close function closes the wormhole associated with 
+the wormhole id passed in. Future calls to rmr_wh_send_msg 
+with this ID will fail. 
+The underlying TCP connection to the remote endpoint is 
+**not** closed as this session may be reqruired for 
+regularlly routed messages (messages routed based on message 
+type). There is no way to force a TCP session to be closed at 
+this point in time. 
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), 
+rmr_get_rcvfd(3), rmr_payload_size(3), rmr_send_msg(3), 
+rmr_rcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), 
+rmr_ready(3), rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), 
+rmr_mk_ring(3), rmr_ring_free(3), rmr_wh_open(3), 
+rmr_wh_send_msg(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_wh_open 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ void* rmr_wh_open( void* vctx, char* target )
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_wh_open function creates a direct link for sending, a 
+wormhole, to another RMr based process. Sending messages 
+through a wormhole requires that the connection be 
+established overtly by the user application (via this 
+function), and that the ID returned by rmr_wh_open be passed 
+to the rmr_wh_send_msg function. 
+*Target* is the *name* or *IP-address* combination of the 
+processess that the wormhole should be connected to. *Vctx* 
+is the RMr void context pointer that was returned by the 
+rmr_init function. 
+When invoked, this function immediatly attempts to connect to 
+the target process. If the connection cannot be established, 
+an error is returned to the caller, and no direct messages 
+can be sent to the target. Once a wormhole is connected, the 
+underlying transport mechanism (e.g. NNG) will provide 
+reconnects should the connection be lost, however the 
+handling of messages sent when a connection is broken is 
+undetermined as each underlying transport mechanism may 
+handle buffering and retries differently. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+The rmr_wh_open function returns a type rmr_whid_t which must 
+be passed to the rmr_wh_send_msg function when sending a 
+message. The id may also be tested to determine success or 
+failure of the connection by using the RMR_WH_CONNECTED macro 
+and passing the ID as the parameter; a result of 1 indicates 
+that the connection was esablished and that the ID is valid. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+The following error values are specifically set by this RMR 
+function. In some cases the error message of a system call is 
+propagated up, and thus this list might be incomplete. 
+EINVAL 
+   
+  A parameter passed was not valid. 
+EACCESS 
+   
+  The user applicarion does not have the ability to 
+  establish a wormhole to the indicated target (or maybe any 
+  target). 
+ECONNREFUSED 
+   
+  The connection was refused. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+    void*  rmc;
+    rmr_whid_t wh;
+    rmc = rmr_init( "43086", 4096, 0 ); // init context
+    wh = rmr_wh_open( rmc, "localhost:6123" );
+    if( !RMR_WH_CONNECTED( wh ) ) { 
+     f fprintf( stderr, "unable to connect wormhole: %s\\n",
+              strerror( errno ) );
+    }
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), 
+rmr_get_rcvfd(3), rmr_payload_size(3), rmr_send_msg(3), 
+rmr_rcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), 
+rmr_ready(3), rmr_fib(3), rmr_has_str(3), rmr_tokenise(3), 
+rmr_mk_ring(3), rmr_ring_free(3), rmr_wh_send_msg(3), 
+rmr_wh_close(3) 
+NAME 
+-------------------------------------------------------------------------------------------- 
+rmr_wh_send_msg 
+SYNOPSIS 
+-------------------------------------------------------------------------------------------- 
+:: 
+  
+ #include <rmr/rmr.h>
+ rmr_mbuf_t* rmr_wh_send_msg( void* vctx, rmr_whid_t id, rmr_mbuf_t* msg );
+DESCRIPTION 
+-------------------------------------------------------------------------------------------- 
+The rmr_wh_send_msg function accepts a message buffer from 
+the user application and attempts to send it using the 
+wormhole ID provided (id). Unlike *rmr_send_msg,* this 
+function attempts to send the message directly to a process 
+at the other end of a wormhole which was created with 
+*rmr_wh-open().* When sending message via wormholes, the 
+normal RMr routing based on message type is ignored, and the 
+caller may leave the message type unspecified in the message 
+buffer (unless it is needed by the receiving process). 
+The message buffer (msg) used to send is the same format as 
+used for regular RMr send and reply to sender operations, 
+thus any buffer allocated by these means, or calls to 
+*rmr_rcv_msg()* can be passed to this function. 
+Retries 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+The send operations in RMr will retry *soft* send failures 
+until one of three conditions occurs: 
+1. 
+   
+  The message is sent without error 
+   
+2. 
+   
+  The underlying transport reports a * hard * failure 
+   
+3. 
+   
+  The maximum number of retry loops has been attempted 
+A retry loop consists of approximately 1000 send attemps ** 
+without** any intervening calls to * sleep() * or * usleep(). 
+* The number of retry loops defaults to 1, thus a maximum of 
+1000 send attempts is performed before returning to the user 
+application. This value can be set at any point after RMr 
+initialisation using the * rmr_set_stimeout() * function 
+allowing the user application to completely disable retires 
+(set to 0), or to increase the number of retry loops. 
+Transport Level Blocking 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+The underlying transport mechanism used to send messages is 
+configured in *non-blocking* mode. This means that if a 
+message cannot be sent immediately the transport mechanism 
+will **not** pause with the assumption that the inability to 
+send will clear quickly (within a few milliseconds). This 
+means that when the retry loop is completely disabled (set to 
+0), that the failure to accept a message for sending by the 
+underlying mechanisms (software or hardware) will be reported 
+immediately to the user application. 
+It should be noted that depending on the underlying transport 
+mechanism being used, it is extremly possible that during 
+normal operations that retry conditions are very likely to 
+happen. These are completely out of RMr's control, and there 
+is nothing that RMr can do to avoid or midigate these other 
+than by allowing RMr to retry the send operation, and even 
+then it is possible (e.g. during connection reattempts), that 
+a single retry loop is not enough to guarentee a successful 
+send. 
+RETURN VALUE 
+-------------------------------------------------------------------------------------------- 
+On success, a new message buffer, with an empty payload, is 
+returned for the application to use for the next send. The 
+state in this buffer will reflect the overall send operation 
+state and should be RMR_OK. 
+If the state in the returned buffer is anything other than 
+RMR_OK, the user application may need to attempt a 
+retransmission of the message, or take other action depending 
+on the setting of errno as described below. 
+In the event of extreme failure, a NULL pointer is returned. 
+In this case the value of errno might be of some use, for 
+documentation, but there will be little that the user 
+application can do other than to move on. 
+ERRORS 
+-------------------------------------------------------------------------------------------- 
+The following values may be passed back in the *state* field 
+of the returned message buffer. 
+RMR_ERR_WHID 
+   
+  The wormhole ID passed in was not associated with an open 
+  wormhole, or was out of range for a valid ID. 
+RMR_ERR_NOWHOPEN 
+   
+  No wormholes exist, further attempt to validate the ID are 
+  skipped. 
+RMR_ERR_BADARG 
+   
+  The message buffer pointer did not refer to a valid 
+  message. 
+RMR_ERR_NOHDR 
+   
+  The header in the message buffer was not valid or 
+  corrupted. 
+The following values may be assigned to errno on failure. 
+INVAL 
+   
+  Parameter(s) passed to the function were not valid, or the 
+  underlying message processing environment was unable to 
+  interpret the message. 
+   
+ENOKEY 
+   
+  The header information in the message buffer was invalid. 
+   
+ENXIO 
+   
+  No known endpoint for the message could be found. 
+   
+EMSGSIZE 
+   
+  The underlying transport refused to accept the message 
+  because of a size value issue (message was not attempted 
+  to be sent). 
+   
+EFAULT 
+   
+  The message referenced by the message buffer is corrupt 
+  (NULL pointer or bad internal length). 
+   
+EBADF 
+   
+  Internal RMR error; information provided to the message 
+  transport environment was not valid. 
+   
+ENOTSUP 
+   
+  Sending was not supported by the underlying message 
+  transport. 
+   
+EFSM 
+   
+  The device is not in a state that can accept the message. 
+   
+EAGAIN 
+   
+  The device is not able to accept a message for sending. 
+  The user application should attempt to resend. 
+   
+EINTR 
+   
+  The operation was interrupted by delivery of a signal 
+  before the message was sent. 
+   
+ETIMEDOUT 
+   
+  The underlying message environment timed out during the 
+  send process. 
+   
+ETERM 
+   
+  The underlying message environment is in a shutdown state. 
+EXAMPLE 
+-------------------------------------------------------------------------------------------- 
+The following is a simple example of how the a wormhole is 
+created (rmr_wh_open) and then how rmr_wh_send_msg function 
+is used to send messages. Some error checking is omitted for 
+clarity. 
+:: 
+  
+ #include <rmr/rmr.h>    .// system headers omitted for clarity
+ int main() {
+    rmr_whid_t whid = -1;   // wormhole id for sending
+    void* mrc;      //msg router context
+         int i;
+    rmr_mbuf_t*  sbuf;      // send buffer
+    int     count = 0;
+    mrc = rmr_init( "43086", RMR_MAX_RCV_BYTES, RMRFL_NONE );
+    if( mrc == NULL ) {
+       fprintf( stderr, "[FAIL] unable to initialise RMr environment\\n" );
+       exit( 1 );
+    }
+    while( ! rmr_ready( mrc ) ) {    e    i// wait for routing table info
+       sleep( 1 );
+    }
+    sbuf = rmr_alloc_msg( mrc, 2048 );
+    while( 1 ) {
+      if( whid < 0 ) {
+        whid = rmr_wh_open( mrc, "localhost:6123" );  // open fails if endpoint refuses conn
+        w   if( RMR_WH_CONNECTED( wh ) ) { 
+            snprintf( sbuf->payload, 1024, "periodic update from sender: %d", count++ );
+            sbuf->len =  strlen( sbuf->payload );
+            sbuf = rmr_wh_send_msg( mrc, whid, sbuf );
+           }
+       }
+       sleep( 5 );
+    }
+ }
+SEE ALSO 
+-------------------------------------------------------------------------------------------- 
+rmr_alloc_msg(3), rmr_call(3), rmr_free_msg(3), rmr_init(3), 
+rmr_payload_size(3), rmr_rcv_msg(3), rmr_rcv_specific(3), 
+rmr_rts_msg(3), rmr_ready(3), rmr_fib(3), rmr_has_str(3), 
+rmr_tokenise(3), rmr_mk_ring(3), rmr_ring_free(3), 
+rmr_set_stimeout(3), rmr_wh_open(3), rmr_wh_close(3)