E. Scott Daniels | ece5bbe | 2020-07-21 13:39:18 -0400 | [diff] [blame] | 1 | .. This work is licensed under a Creative Commons Attribution 4.0 International License. |
| 2 | .. SPDX-License-Identifier: CC-BY-4.0 |
| 3 | .. CAUTION: this document is generated from source in doc/src/rtd. |
| 4 | .. To make changes edit the source and recompile the document. |
| 5 | .. Do NOT make changes directly to .rst or .md files. |
| 6 | |
| 7 | ============================================================================================ |
| 8 | Man Page: rmr_call |
| 9 | ============================================================================================ |
| 10 | |
| 11 | |
E. Scott Daniels | a3a121c | 2020-05-06 09:07:08 -0400 | [diff] [blame] | 12 | |
| 13 | |
| 14 | RMR LIBRARY FUNCTIONS |
| 15 | ===================== |
| 16 | |
| 17 | |
| 18 | |
| 19 | NAME |
| 20 | ---- |
| 21 | |
E. Scott Daniels | ece5bbe | 2020-07-21 13:39:18 -0400 | [diff] [blame] | 22 | rmr_call |
E. Scott Daniels | a3a121c | 2020-05-06 09:07:08 -0400 | [diff] [blame] | 23 | |
| 24 | |
| 25 | SYNOPSIS |
| 26 | -------- |
| 27 | |
E. Scott Daniels | ece5bbe | 2020-07-21 13:39:18 -0400 | [diff] [blame] | 28 | |
| 29 | :: |
| 30 | |
| 31 | #include <rmr/rmr.h> |
| 32 | |
| 33 | extern rmr_mbuf_t* rmr_call( void* vctx, rmr_mbuf_t* msg ); |
| 34 | |
E. Scott Daniels | a3a121c | 2020-05-06 09:07:08 -0400 | [diff] [blame] | 35 | |
| 36 | |
| 37 | DESCRIPTION |
| 38 | ----------- |
| 39 | |
E. Scott Daniels | ece5bbe | 2020-07-21 13:39:18 -0400 | [diff] [blame] | 40 | The ``rmr_call`` function sends the user application message |
| 41 | to a remote endpoint, and waits for a corresponding response |
| 42 | message before returning control to the user application. The |
| 43 | user application supplies a completed message buffer, as it |
| 44 | would for a ``rmr_send`` call, but unlike with the send, the |
| 45 | buffer returned will have the response from the application |
| 46 | that received the message. |
| 47 | |
| 48 | Messages which are received while waiting for the response |
| 49 | are queued internally by RMR, and are returned to the user |
| 50 | application when ``rmr_rcv_msg`` is invoked. These messages |
| 51 | are returned in the order received, one per call to |
| 52 | ``rmr_rcv_msg.`` |
E. Scott Daniels | a3a121c | 2020-05-06 09:07:08 -0400 | [diff] [blame] | 53 | |
| 54 | |
| 55 | Call Timeout |
| 56 | ------------ |
| 57 | |
E. Scott Daniels | ece5bbe | 2020-07-21 13:39:18 -0400 | [diff] [blame] | 58 | The ``rmr_call`` function implements a timeout failsafe to |
| 59 | prevent, in most cases, the function from blocking forever. |
| 60 | The timeout period is **not** based on time (calls to clock |
| 61 | are deemed too expensive for a low latency system level |
| 62 | library), but instead the period is based on the number of |
| 63 | received messages which are not the response. Using a |
| 64 | mechanism which is not time based for *timeout* prevents the |
| 65 | async queue from filling (which would lead to message drops) |
| 66 | in an environment where there is heavy message traffic. |
| 67 | |
| 68 | When the threshold number of messages have been queued |
| 69 | without receiving a response message, control is returned to |
| 70 | the user application and a nil pointer is returned to |
| 71 | indicate that no message was received to process. Currently |
| 72 | the threshold is fixed at 20 messages, though in future |
| 73 | versions of the library this might be extended to be a |
| 74 | parameter which the user application may set. |
E. Scott Daniels | a3a121c | 2020-05-06 09:07:08 -0400 | [diff] [blame] | 75 | |
| 76 | |
| 77 | Retries |
| 78 | ------- |
| 79 | |
E. Scott Daniels | ece5bbe | 2020-07-21 13:39:18 -0400 | [diff] [blame] | 80 | The send operations in RMR will retry *soft* send failures |
| 81 | until one of three conditions occurs: |
| 82 | |
| 83 | |
| 84 | * The message is sent without error |
| 85 | |
| 86 | * The underlying transport reports a *hard* failure |
| 87 | |
| 88 | * The maximum number of retry loops has been attempted |
| 89 | |
| 90 | |
| 91 | A retry loop consists of approximately 1000 send attempts |
| 92 | **without** any intervening calls to *sleep()* or *usleep().* |
| 93 | The number of retry loops defaults to 1, thus a maximum of |
| 94 | 1000 send attempts is performed before returning to the user |
| 95 | application. This value can be set at any point after RMR |
| 96 | initialisation using the *rmr_set_stimeout()* function |
| 97 | allowing the user application to completely disable retires |
| 98 | (set to 0), or to increase the number of retry loops. |
E. Scott Daniels | a3a121c | 2020-05-06 09:07:08 -0400 | [diff] [blame] | 99 | |
| 100 | |
| 101 | Transport Level Blocking |
| 102 | ------------------------ |
| 103 | |
E. Scott Daniels | ece5bbe | 2020-07-21 13:39:18 -0400 | [diff] [blame] | 104 | The underlying transport mechanism used to send messages is |
| 105 | configured in *non-blocking* mode. This means that if a |
| 106 | message cannot be sent immediately the transport mechanism |
| 107 | will **not** pause with the assumption that the inability to |
| 108 | send will clear quickly (within a few milliseconds). This |
| 109 | means that when the retry loop is completely disabled (set to |
| 110 | 0), that the failure to accept a message for sending by the |
| 111 | underlying mechanisms (software or hardware) will be reported |
| 112 | immediately to the user application. |
| 113 | |
| 114 | It should be noted that depending on the underlying transport |
| 115 | mechanism being used, it is extremely likely that retry |
| 116 | conditions will happen during normal operations. These are |
| 117 | completely out of RMR's control, and there is nothing that |
| 118 | RMR can do to avoid or mitigate these other than by allowing |
| 119 | RMR to retry the send operation, and even then it is possible |
| 120 | (e.g., during connection reattempts), that a single retry |
| 121 | loop is not enough to guarantee a successful send. |
E. Scott Daniels | a3a121c | 2020-05-06 09:07:08 -0400 | [diff] [blame] | 122 | |
| 123 | |
| 124 | RETURN VALUE |
| 125 | ------------ |
| 126 | |
E. Scott Daniels | ece5bbe | 2020-07-21 13:39:18 -0400 | [diff] [blame] | 127 | The ``rmr_call`` function returns a pointer to a message |
| 128 | buffer with the state set to reflect the overall state of |
| 129 | call processing (see Errors below). In some cases a nil |
| 130 | pointer will be returned; when this is the case only *errno* |
| 131 | will be available to describe the reason for failure. |
E. Scott Daniels | a3a121c | 2020-05-06 09:07:08 -0400 | [diff] [blame] | 132 | |
| 133 | |
| 134 | ERRORS |
| 135 | ------ |
| 136 | |
E. Scott Daniels | ece5bbe | 2020-07-21 13:39:18 -0400 | [diff] [blame] | 137 | These values are reflected in the state field of the returned |
| 138 | message. |
| 139 | |
| 140 | |
| 141 | .. list-table:: |
| 142 | :widths: auto |
| 143 | :header-rows: 0 |
| 144 | :class: borderless |
| 145 | |
| 146 | * - **RMR_OK** |
| 147 | - |
| 148 | The call was successful and the message buffer references the |
| 149 | response message. |
| 150 | |
| 151 | * - **RMR_ERR_CALLFAILED** |
| 152 | - |
| 153 | The call failed and the value of *errno,* as described below, |
| 154 | should be checked for the specific reason. |
| 155 | |
| 156 | |
| 157 | |
| 158 | The global "variable" *errno* will be set to one of the |
| 159 | following values if the overall call processing was not |
| 160 | successful. |
| 161 | |
| 162 | |
| 163 | .. list-table:: |
| 164 | :widths: auto |
| 165 | :header-rows: 0 |
| 166 | :class: borderless |
| 167 | |
| 168 | * - **ETIMEDOUT** |
| 169 | - |
| 170 | Too many messages were queued before receiving the expected |
| 171 | response |
| 172 | |
| 173 | * - **ENOBUFS** |
| 174 | - |
| 175 | The queued message ring is full, messages were dropped |
| 176 | |
| 177 | * - **EINVAL** |
| 178 | - |
| 179 | A parameter was not valid |
| 180 | |
| 181 | * - **EAGAIN** |
| 182 | - |
| 183 | The underlying message system was interrupted or the device |
| 184 | was busy; the message was **not** sent, and the user |
| 185 | application should call this function with the message again. |
| 186 | |
| 187 | |
E. Scott Daniels | a3a121c | 2020-05-06 09:07:08 -0400 | [diff] [blame] | 188 | |
| 189 | |
| 190 | EXAMPLE |
| 191 | ------- |
| 192 | |
E. Scott Daniels | ece5bbe | 2020-07-21 13:39:18 -0400 | [diff] [blame] | 193 | The following code snippet shows one way of using the |
| 194 | ``rmr_call`` function, and illustrates how the transaction ID |
| 195 | must be set. |
| 196 | |
| 197 | |
| 198 | :: |
| 199 | |
| 200 | int retries_left = 5; // max retries on dev not available |
| 201 | int retry_delay = 50000; // retry delay (usec) |
| 202 | static rmr_mbuf_t* mbuf = NULL; // response msg |
| 203 | msg_t* pm; // application struct for payload |
| 204 | |
| 205 | // get a send buffer and reference the payload |
| 206 | mbuf = rmr_alloc_msg( mr, sizeof( pm->req ) ); |
| 207 | pm = (msg_t*) mbuf->payload; |
| 208 | |
| 209 | // generate an xaction ID and fill in payload with data and msg type |
| 210 | snprintf( mbuf->xaction, RMR_MAX_XID, "%s", gen_xaction() ); |
| 211 | snprintf( pm->req, sizeof( pm->req ), "{ \\"req\\": \\"num users\\"}" ); |
| 212 | mbuf->mtype = MT_REQ; |
| 213 | |
| 214 | msg = rmr_call( mr, msg ); |
| 215 | if( ! msg ) { // probably a timeout and no msg received |
| 216 | return NULL; // let errno trickle up |
| 217 | } |
| 218 | |
| 219 | if( mbuf->state != RMR_OK ) { |
| 220 | while( retries_left-- > 0 && // loop as long as eagain |
| 221 | errno == EAGAIN && |
| 222 | (msg = rmr_call( mr, msg )) != NULL && |
| 223 | mbuf->state != RMR_OK ) { |
| 224 | |
| 225 | usleep( retry_delay ); |
| 226 | } |
| 227 | |
| 228 | if( mbuf == NULL || mbuf->state != RMR_OK ) { |
| 229 | rmr_free_msg( mbuf ); // safe if nil |
| 230 | return NULL; |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | // do something with mbuf |
| 235 | |
E. Scott Daniels | a3a121c | 2020-05-06 09:07:08 -0400 | [diff] [blame] | 236 | |
| 237 | |
| 238 | SEE ALSO |
| 239 | -------- |
| 240 | |
E. Scott Daniels | ece5bbe | 2020-07-21 13:39:18 -0400 | [diff] [blame] | 241 | rmr_alloc_msg(3), rmr_free_msg(3), rmr_init(3), |
| 242 | rmr_payload_size(3), rmr_send_msg(3), rmr_rcv_msg(3), |
| 243 | rmr_rcv_specific(3), rmr_rts_msg(3), rmr_ready(3), |
| 244 | rmr_fib(3), rmr_has_str(3), rmr_set_stimeout(3), |
| 245 | rmr_tokenise(3), rmr_mk_ring(3), rmr_ring_free(3) |