blob: a8e02e5344d64b09cbd0d0ee03313c8dbb7cb96e [file] [log] [blame]
.. 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.
============================================================================================
Man Page: rmr_call
============================================================================================
RMR LIBRARY FUNCTIONS
=====================
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 the 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
mechanism which is not time based 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 nil 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:
* The message is sent without error
* The underlying transport reports a *hard* failure
* The maximum number of retry loops has been attempted
A retry loop consists of approximately 1000 send attempts
**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 extremely likely that retry
conditions will happen during normal operations. These are
completely out of RMR's control, and there is nothing that
RMR can do to avoid or mitigate 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 guarantee 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 nil
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.
.. list-table::
:widths: auto
:header-rows: 0
:class: borderless
* - **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.
.. list-table::
:widths: auto
:header-rows: 0
:class: borderless
* - **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 was interrupted or the device
was busy; the message was **not** sent, and the user
application should call this function with the message again.
EXAMPLE
-------
The following code snippet 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; // application struct for payload
// get a send buffer and reference the payload
mbuf = rmr_alloc_msg( mr, sizeof( pm->req ) );
pm = (msg_t*) mbuf->payload;
// 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)