blob: 985e9d7f2497cd502e1671c15cf421d688d5006f [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_mt_call
============================================================================================
RMR LIBRARY FUNCTIONS
=====================
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 the order received, one per
call to ``rmr_rcv_msg.``
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:
* 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_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.
.. 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_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.
.. 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 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; // appl message struct (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
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 ); // 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)