2 ==================================================================================
3 Copyright (c) 2019 Nokia
4 Copyright (c) 2018-2019 AT&T Intellectual Property.
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 ==================================================================================
22 Mnemonic rmr_mt_call_man.xfm
23 Abstract The manual page for the rmr multi-threaded call function.
24 Author E. Scott Daniels
28 .** if formatting with tfm, the roff.im will cause roff output to be generated
29 .** if formatting with pfm, then pretty postscript will be generated
32 .im &{lib}/generic_ps.im
34 .gv e OUTPUT_RST use_rst
44 &h1(RMR Library Functions)
53 extern rmr_mbuf_t* rmr_mt_call( void* vctx, rmr_mbuf_t* msg, int id, int timeout );
58 The &cw(rmr_mt_call) function sends the user application message to a remote
59 endpoint, and waits for a corresponding response message before returning
60 control to the user application.
61 The user application supplies a completed message buffer, as it would for
62 a &cw(rmr_send_msg) call, but unlike with a send, the buffer returned will have
63 the response from the application that received the message.
64 The thread invoking the &ital( rmr_mt_call()) will block until a message arrives
65 or until &ital(timeout) milliseconds has passed; which ever comes first.
66 Using a timeout value of zero (0) will cause the thread to block without a timeout.
69 The &ital( id ) supplied as the third parameter is an integer in the range of 2 through
71 This is a caller defined "thread number" and is used to match the response message
72 with the correct user application thread.
73 If the ID value is not in the proper range, the attempt to make the call will fail.
76 Messages which are received while waiting for the response are queued on a &ital(normal)
77 receive queue and will be delivered to the user application with the next invocation
78 of &ital( rmr_mt_rcv() ) or &ital( rmr_rvv_msg().)
79 by RMR, and are returned to the user application when &cw(rmr_rcv_msg) is
81 These messages are returned in th order received, one per call to &cw(rmr_rcv_msg.)
84 NOTE: Currently the multi-threaded functions are supported only when the NNG
85 transport mechanism is being used. It will not be possible to link a programme
86 using the Nanomsg version of the library when references to this function are
89 &h3(The Transaction ID)
90 The user application is responsible for setting the value of the transaction ID field
91 before invoking &ital(rmr_mt_call.)
92 The transaction ID is a &cw(RMR_MAX_XID) byte field that is used to match the
93 response message when it arrives.
94 RMr will compare &bold(all) of the bytes in the field, so the caller must ensure
95 that they are set correctly to avoid missing the response message.
96 (The application which returns the response message is also expected to ensure that
97 the return buffer has the matching transaction ID. This can be done transparently if
98 the application uses the &ital( rmr_rts_msg() ) function and does not adjust the
101 .** pull in common retry text
102 .im &{lib}/man/retry.im
105 The &cw(rmr_mt_call) function returns a pointer to a message buffer with the state set to reflect
106 the overall state of call processing.
107 If the state is &cw(RMR_OK) then the buffer contains the response message; otherwise
108 the state indicates the error encountered while attempting to send the message.
111 If no response message is received when the timeout period has expired, a nil pointer
112 will be returned (NULL).
115 These values are reflected in the state field of the returned message.
118 &beg_dlist(.75i : ^&bold_font )
119 &di(RMR_OK) The call was successful and the message buffer references the response message.
122 &di(RMR_ERR_BADARG) An argument passed to the function was invalid.
125 &di(RMR_ERR_CALLFAILED) The call failed and the value of &ital(errno,) as described below,
126 should be checked for the specific reason.
129 &di(RMR_ERR_NOENDPT) An endpoint associated with the message type could not be found in the
133 &di(RMR_ERR_RETRY) The underlying transport mechanism was unable to accept the message
134 for sending. The user application can retry the call operation if appropriate to
140 The global "variable" &ital(errno) will be set to one of the following values if the
141 overall call processing was not successful.
144 &beg_dlist(.75i : ^&bold_font )
145 &di(ETIMEDOUT) Too many messages were queued before receiving the expected response
148 &di(ENOBUFS) The queued message ring is full, messages were dropped
151 &di(EINVAL) A parameter was not valid
154 &di(EAGAIN) The underlying message system wsa interrupted or the device was busy;
155 the message was &bold(not) sent, and user application should call
156 this function with the message again.
160 The following code bit shows one way of using the &cw(rmr_mt_call) function, and illustrates
161 how the transaction ID must be set.
165 int retries_left = 5; // max retries on dev not available
166 static rmr_mbuf_t* mbuf = NULL; // response msg
167 msg_t* pm; // private message (payload)
169 // get a send buffer and reference the payload
170 mbuf = rmr_alloc_msg( mr, RMR_MAX_RCV_BYTES );
171 pm = (msg_t*) mbuf->payload;
173 // generate an xaction ID and fill in payload with data and msg type
174 rmr_bytes2xact( mbuf, xid, RMR_MAX_XID );
175 snprintf( pm->req, sizeof( pm->req ), "{ \"req\": \"num users\"}" );
176 mbuf->mtype = MT_USR_RESP;
178 msg = rmr_mt_call( mr, msg, my_id, 100 ); // wait up to 100ms
179 if( ! msg ) { // probably a timeout and no msg received
180 return NULL; // let errno trickle up
183 if( mbuf->state != RMR_OK ) {
184 while( retries_left-- > 0 && // loop as long as eagain
185 mbuf->state == RMR_ERR_RETRY &&
186 (msg = rmr_mt_call( mr, msg )) != NULL &&
187 mbuf->state != RMR_OK ) {
189 usleep( retry_delay );
192 if( mbuf == NULL || mbuf->state != RMR_OK ) {
193 rmr_free_msg( mbuf ); // safe if nil
198 // do something with mbuf