blob: 2aa1f9ae37492319a2191b022118e90b15cf1dfc [file] [log] [blame]
E. Scott Daniels392168d2019-11-06 15:12:38 -05001.. 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
E. Scott Daniels5a9d1752020-04-17 17:07:06 -04007============================================================================================
E. Scott Danielsa3a121c2020-05-06 09:07:08 -04008User's Guide
9============================================================================================
10--------------------------------------------------------------------------------------------
E. Scott Daniels5a9d1752020-04-17 17:07:06 -040011RIC Message Router -- RMR
E. Scott Daniels5a9d1752020-04-17 17:07:06 -040012--------------------------------------------------------------------------------------------
E. Scott Danielsa3a121c2020-05-06 09:07:08 -040013
14
15Overview
16========
17
18The RIC Message Router (RMR) is a library for peer-to-peer
19communication. Applications use the library to send and
20receive messages where the message routing and endpoint
21selection is based on the message type rather than DNS host
22name-IP port combinations. The library provides the following
23major features:
Lott, Christopher (cl778h)fe6a8562020-04-06 15:05:22 -040024
E. Scott Daniels5a9d1752020-04-17 17:07:06 -040025
E. Scott Danielsa3a121c2020-05-06 09:07:08 -040026* Routing and endpoint selection is based on *message type.*
27
28* Application is insulated from the underlying transport
29 mechanism and/or protocols.
30
31* Message distribution (round robin or fanout) is selectable
32 by message type.
33
34* Route management updates are received and processed
35 asynchronously and without overt application involvement.
E. Scott Daniels392168d2019-11-06 15:12:38 -050036
37
E. Scott Danielsa3a121c2020-05-06 09:07:08 -040038
39
40Purpose
41-------
42
E. Scott Daniels5a9d1752020-04-17 17:07:06 -040043RMR's main purpose is to provide an application with the
44ability to send and receive messages to/from other peer
45applications with minimal effort on the application's part.
46To achieve this, RMR manages all endpoint information,
47connections, and routing information necessary to establish
48and maintain communication. From the application's point of
49view, all that is required to send a message is to allocate
50(via RMR) a message buffer, add the payload data, and set the
51message type. To receive a message, the application needs
52only to invoke the receive function; when a message arrives a
53message buffer will be returned as the function result.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -040054
55
56Message Routing
57---------------
58
E. Scott Daniels5a9d1752020-04-17 17:07:06 -040059Applications are required to place a message type into a
60message before sending, and may optionally add a subscription
61ID when appropriate. The combination of message type, and
62subscription ID are refered to as the *message key,* and is
63used to match an entry in a routing table which provides the
64possible endpoints expecting to receive messages with the
65matching key.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -040066
67
68Round Robin Delivery
69--------------------
70
E. Scott Daniels5a9d1752020-04-17 17:07:06 -040071An endpoint from RMR's perspective is an application to which
72RMR may establish a connection, and expect to send messages
73with one or more defined message keys. Each entry in the
74route table consists of one or more endpoint groups, called
75round robin groups. When a message matches a specific entry,
76the entry's groups are used to select the destination of the
77message. A message is sent once to each group, with messages
78being *balanced* across the endpoints of a group via round
79robin selection. Care should be taken when defining multiple
80groups for a message type as there is extra overhead required
81and thus the overall message latency is somewhat increased.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -040082
83
84Routing Table Updates
85---------------------
86
E. Scott Daniels5a9d1752020-04-17 17:07:06 -040087Route table information is made available to RMR a static
88file (loaded once), or by updates sent from a separate route
89manager application. If a static table is provided, it is
90loaded during RMR initialization and will remain in use until
91an external process connects and delivers a route table
92update (often referred to as a dynamic update). Dynamic
93updates are listened for in a separate process thread and
94applied automatically; the application does not need to allow
95for, or trigger, updates.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -040096
97
98Latency And Throughput
99----------------------
100
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400101While providing insulation from the underlying message
102transport mechanics, RMR must also do so in such a manner
103that message latency and throughput are not impacted. In
104general, the RMR induced overhead, incurred due to the
105process of selecting an endpoint for each message, is minimal
106and should not impact the overall latency or throughput of
107the application. This impact has been measured with test
108applications running on the same physical host and the
109average latency through RMR for a message was on the order of
1100.02 milliseconds.
E. Scott Daniels117030c2020-04-10 17:17:02 -0400111
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400112As an application's throughput increases, it becomes easy for
113the application to overrun the underlying transport mechanism
114(e.g. NNG), consume all available TCP transmit buffers, or
115otherwise find itself in a situation where a send might not
116immediately complete. RMR offers different *modes* which
117allow the application to manage these states based on the
118overall needs of the application. These modes are discussed
119in the *Configuration* section of this document.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400120
121
122General Use
123===========
124
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400125To use, the RMR based application simply needs to initialise
126the RMR environment, wait for RMR to have received a routing
127table (become ready), and then invoke either the send or
128receive functions. These steps, and some behind the scenes
129details, are described in the following paragraphs.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400130
131
132Initialisation
133--------------
134
135The RMR function ``rmr_init()`` is used to set up the RMR
136environment and must be called before messages can be sent or
137received. One of the few parameters that the application must
138communicate to RMR is the port number that will be used as
139the listen port for new connections. The port number is
140passed on the initialisation function call and a TCP listen
141socket will be opened with this port. If the port is already
142in use RMR will report a failure; the application will need
143to reinitialise with a different port number, abort, or take
144some other action appropriate for the application.
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400145
146In addition to creating a TCP listen port, RMR will start a
147process thread which will be responsible for receiving
148dynamic updates to the route table. This thread also causes a
149TCP listen port to be opened as it is expected that the
150process which generates route table updates will connect and
151send new information when needed. The route table update port
152is **not** supplied by the application, but is supplied via
153an environment variable as this value is likely determined by
154the mechanism which is starting and configuring the
155application.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400156
157
158The RMR Context
159---------------
160
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400161On successful initialisation, a void pointer, often called a
162*handle* by some programming languages, is returned to the
163application. This is a reference to the RMR control
164information and must be passed as the first parameter on most
165RMR function calls. RMR refers to this as the context, or
166ctx.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400167
168
169Wait For Ready
170--------------
171
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400172An application which is only receiving messages does not need
173to wait for RMR to *become ready* after the call to the
174initialization function. However, before the application can
175successfully send a message, RMR must have loaded a route
176table, and the application must wait for RMR to report that
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400177it has done so. The RMR function ``rmr_ready()`` will return
178the value *true* (1) when a complete route table has been
179loaded and can be used to determine the endpoint for a send
180request.
181
182
183Receiving Messages
184------------------
185
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400186The process of receiving is fairly straight forward. The
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400187application invokes the RMR ``rmr_rcv_msg()`` function which
188will block until a message is received. The function returns
189a pointer to a message block which provides all of the
190details about the message. Specifically, the application has
191access to the following information either directly or
192indirectly:
E. Scott Daniels392168d2019-11-06 15:12:38 -0500193
194
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400195* The payload (actual data)
196
197* The total payload length in bytes
198
199* The number of bytes of the payload which contain valid data
200
201* The message type and subscription ID values
202
203* The hostname and IP address of the source of the message
204 (the sender)
205
206* The transaction ID
207
208* Tracing data (if provided)
E. Scott Daniels392168d2019-11-06 15:12:38 -0500209
210
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400211
212
213The Message Payload
214-------------------
215
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400216The message payload contains the *raw* data that was sent by
217the peer application. The format will likely depend on the
218message type, and is expected to be known by the application.
219A direct pointer to the payload is available from the message
220buffer (see appendix B for specific message buffer details).
221
222Two payload-related length values are also directly
223available: the total payload length, and the number of bytes
224actually filled with data. The used length is set by the
225caller, and may or not be an accurate value. The total
226payload length is determined when the buffer is created for
227sending, and is the maximum number of bytes that the
228application may modify should the buffer be used to return a
229response.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400230
231
232Message Type and Subscription ID
233--------------------------------
234
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400235The message type and subscription ID are both directly
236available from the message buffer, and are the values which
237were used to by RMR in the sending application to select the
238endpoint. If the application resends the message, as opposed
239to returning the message buffer as a response, the message
240number and/or the subscription ID might need to be changed to
241avoid potential issues[1].
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400242
243
244Sender Information
245------------------
246
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400247The source, or sender information, is indirectly available to
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400248the application via the ``rmr_get_src()`` and
249``rmr_get_ip()`` functions. The former returns a string
250containing ``hostname:port,`` while the string
251``ip:port`` is returned by the latter.
252
253
254Transaction ID
255--------------
256
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400257The message buffer contains a fixed length set of bytes which
258applications can set to track related messages across the
259application concept of a transaction. RMR will use the
260transaction ID for matching a response message when the
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400261``rmr_call()`` function is used to send a message.
262
263
264Trace Information
265-----------------
266
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400267RMR supports the addition of an optional trace information to
268any message. The presence and size is controlled by the
269application, and can vary from message to message if desired.
270The actual contents of the trace information is determined by
271the application; RMR provides only the means to set, extract,
272and obtain a direct reference to the trace bytes. The trace
273data field in a message buffer is discussed in greater detail
274in the *Trace Data* section.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400275
276
277Sending Messages
278----------------
279
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400280Sending requires only slightly more work on the part of the
281application than receiving a message. The application must
282allocate an RMR message buffer, populate the message payload
283with data, set the message type and length, and optionally
284set the subscription ID. Information such as the source IP
285address, hostname, and port are automatically added to the
286message buffer by RMR, so there is no need for the
287application to worry about these.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400288
289
290Message Buffer Allocation
291-------------------------
292
293The function ``rmr_msg_alloc()`` allocates a *zero copy*
294buffer and returns a pointer to the RMR ``rmr_mbuf_t``
295structure. The message buffer provides direct access to the
296payload, length, message type and subscription ID fields. The
297buffer must be preallocated in order to allow the underlying
298transport mechanism to allocate the payload space from its
299internal memory pool; this eliminates multiple copies as the
300message is sent, and thus is more efficient.
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400301
302If a message buffer has been received, and the application
303wishes to use the buffer to send a response, or to forward
304the buffer to another application, a new buffer does **not**
305need to be allocated. The application may set the necessary
306information (message type, etc.), and adjust the payload, as
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400307is necessary and then pass the message buffer to
308``rmr_send_msg()`` or ``rmr_rts_msg()`` to be sent or
309returned to the sender.
310
311
312Populating the Message Buffer
313-----------------------------
314
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400315The application has direct access to several of the message
316buffer fields, and should set them appropriately.
E. Scott Daniels392168d2019-11-06 15:12:38 -0500317
318
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400319 .. list-table::
320 :widths: 15,80
321 :header-rows: 0
322 :class: borderless
323
324 * - **len**
325 -
326 This is the number of bytes that the application placed into
327 the payload. Setting length to 0 is allowed, and length may
328 be less than the allocated payload size.
329
330 * - **mtype**
331 -
332 The message type that RMR will use to determine the endpoint
333 used as the target of the send.
334
335 * - **sub_id**
336 -
337 The subscription ID if the message is to be routed based on
338 the combination of message type and subscription ID. If no
339 subscription ID is valid for the message, the application
340 should set the field with the RMR constant
341 ``RMR_VOID_SUBID.``
342
343 * - **payload**
344 -
345 The application should obtain the reference (pointer) to the
346 payload from the message buffer and place any data into the
347 payload. The application is responsible for ensuring that the
348 maximum payload size is not exceeded. The application may
349 obtain the maximum size via the ``rmr_payload_size()``
350 function.
351
352 * - **trace data**
353 -
354 Optionally, the application may add trace information to the
355 message buffer.
356
E. Scott Daniels392168d2019-11-06 15:12:38 -0500357
358
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400359
360
361Sending a Message Buffer
362------------------------
363
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400364Once the application has populated the necessary bits of a
365message, it may be sent by passing the buffer to the
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400366``rmr_send_msg()`` function. This function will select an
367endpoint to receive the message, based on message type and
368subscription ID, and will pass the message to the underlying
369transport mechanism for actual transmission on the
370connection. (Depending on the underlying transport mechanism,
371the actual connection to the endpoint may happen at the time
372of the first message sent to the endpoint, and thus the
373latency of the first send might be longer than expected.)
E. Scott Daniels392168d2019-11-06 15:12:38 -0500374
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400375On success, the send function will return a reference to a
376message buffer; the status within that message buffer will
377indicate what the message buffer contains. When the status is
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400378``RMR_OK`` the reference is to a **new** message buffer for
379the application to use for the next send; the payload size is
380the same as the payload size allocated for the message that
381was just sent. This is a convenience as it eliminates the
382need for the application to call the message allocation
383function at some point in the future, and assumes the
384application will send many messages which will require the
385same payload dimensions.
E. Scott Daniels392168d2019-11-06 15:12:38 -0500386
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400387If the message contains any status other than ``RMR_OK,``
388then the message could **not** be sent, and the reference is
389to the unsent message buffer. The value of the status will
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400390indicate whether the nature of the failure was transient (
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400391``RMR_ERR_RETRY``) or not. Transient failures are likely to
392be successful if the application attempts to send the message
393at a later time. Unfortunately, it is impossible for RMR to
394know the exact transient failure (e.g. connection being
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400395established, or TCP buffer shortage), and thus it is not
396possible to communicate how long the application should wait
397before attempting to resend, if the application wishes to
398resend the message. (More discussion with respect to message
399retries can be found in the *Handling Failures* section.)
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400400
401
402Advanced Usage
403==============
404
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400405Several forms of usage fall into a more advanced category and
406are described in the following sections. These include
407blocking call, return to sender and wormhole functions.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400408
409
410The Call Function
411-----------------
412
413The RMR function ``rmr_call()`` sends a message in the exact
414same manner as the ``rmr_send_msg()()`` function, with the
415endpoint selection based on the message key. But unlike the
416send function, ``rmr_call()`` will block and wait for a
417response from the application that is selected to receive the
418message. The matching message is determined by the
419transaction ID which the application must place into the
420message buffer prior to invoking ``rmr_call()``. Similarly,
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400421the responding application must ensure that the same
422transaction ID is placed into the message buffer before
423returning its response.
E. Scott Daniels392168d2019-11-06 15:12:38 -0500424
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400425The return from the call is a message buffer with the
426response message; there is no difference between a message
427buffer returned by the receive function and one returned by
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400428the ``rmr_call()`` function. If a response is not received in
429a reasonable amount of time, a nil message buffer is returned
430to the calling application.
431
432
433Returning a Response
434--------------------
435
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400436Because of the nature of RMR's routing policies, it is
437generally not possible for an application to control exactly
438which endpoint is sent a message. There are cases, such as
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400439responding to a message delivered via ``rmr_call()`` that the
440application must send a message and guarantee that RMR routes
441it to an exact destination. To enable this, RMR provides the
442``rmr_rts_msg(),`` return to sender, function. Upon receipt
443of any message, an application may alter the payload, and if
444necessary the message type and subscription ID, and pass the
445altered message buffer to the ``rmr_rts_msg()`` function to
446return the altered message to the application which sent it.
447When this function is used, RMR will examine the message
448buffer for the source information and use that to select the
449connection on which to write the response.
450
451
452Multi-threaded Calls
453--------------------
454
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400455The basic call mechanism described above is **not** thread
456safe, as it is not possible to guarantee that a response
457message is delivered to the correct thread. The RMR function
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400458``rmr_mt_call()`` accepts an additional parameter which
459identifies the calling thread in order to ensure that the
460response is delivered properly. In addition, the application
461must specifically initialise the multi-threaded call
462environment by passing the ``RMRFL_MTCALL`` flag as an option
463to the ``rmr_init()`` function.
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400464
465One advantage of the multi-threaded call capability in RMR is
466the fact that only the calling thread is blocked. Messages
467received which are not responses to the call are continued to
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400468be delivered via normal ``rmr_rcv_msg()`` calls.
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400469
470While the process is blocked waiting for the response, it is
471entirely possible that asynchronous, non-matching, messages
472will arrive. When this happens, RMR will queues the messages
473and return them to the application over the next calls to
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400474``rmr_rcv_msg().``
475
476
477Wormholes
478---------
479
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400480As was mentioned earlier, the design of RMR is to eliminate
481the need for an application to know a specific endpoint, even
482when a response message is being sent. In some rare cases it
483may be necessary for an application to establish a direct
484connection to an RMR-based application rather than relying on
485message type and subscription ID based routing. The
486*wormhole* functions provide an application with the ability
487to create a direct connection and then to send and receive
488messages across the connection. The following are the RMR
489functions which provide wormhole communications:
490
491
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400492 .. list-table::
493 :widths: auto
494 :header-rows: 0
495 :class: borderless
496
497 * - **rmr_wh_open**
498 -
499 Open a connection to an endpoint. Name or IP address and port
500 of the endpoint is supplied. Returns a wormhole ID that the
501 application must use when sending a direct message.
502
503 * - **rmr_wh_send_msg**
504 -
505 Sends an RMR message buffer to the connected application. The
506 message type and subscription ID may be set in the message,
507 but RMR will ignore both.
508
509 * - **rmr_wh_close**
510 -
511 Closes the direct connection.
512
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400513
514
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400515
516
517Handling Failures
518=================
519
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400520The vast majority of states reported by RMR are fatal; if
521encountered during setup or initialization, then it is
522unlikely that any message oriented processing should
523continue, and when encountered on a message operation
524continued operation on that message should be abandoned.
525Specifically with regard to message sending, it is very
526likely that the underlying transport mechanism will report a
527*soft,* or transient, failure which might be successful if
528the operation is retried at a later point in time. The
529paragraphs below discuss the methods that an application
530might deal with these soft failures.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400531
532
533Failure Notification
534--------------------
535
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400536When a soft failure is reported, the returned message buffer
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400537returned by the RMR function will be ``RMR_ERR_RETRY.`` These
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400538types of failures can occur for various reasons; one of two
539reasons is typically the underlying cause:
540
541
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400542* The session to the targeted recipient (endpoint) is not
543 connected.
544
545* The transport mechanism buffer pool is full and cannot
546 accept another buffer.
547
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400548
549
550Unfortunately, it is not possible for RMR to determine which
551of these two cases is occurring, and equally as unfortunate
552the time to resolve each is different. The first, no
553connection, may require up to a second before a message can
554be accepted, while a rejection because of buffer shortage is
555likely to resolve in less than a millisecond.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400556
557
558Application Response
559--------------------
560
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400561The action which an application takes when a soft failure is
562reported ultimately depends on the nature of the application
563with respect to factors such as tolerance to extended message
564latency, dropped messages, and over all message rate.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400565
566
567RMR Retry Modes
568---------------
569
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400570In an effort to reduce the workload of an application
571developer, RMR has a default retry policy such that RMR will
572attempt to retransmit a message up to 1000 times when a soft
573failure is reported. These retries generally take less than 1
574millisecond (if all 1000 are attempted) and in most cases
575eliminates nearly all reported soft failures to the
576application. When using this mode, it might allow the
577application to simply treat all bad return values from a send
578attempt as permanent failures.
579
580If an application is so sensitive to any delay in RMR, or the
581underlying transport mechanism, it is possible to set RMR to
582return a failure immediately on any kind of error (permanent
583failures are always reported without retry). In this mode,
584RMR will still set the state in the message buffer to
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400585``RMR_ERR_RETRY,`` but will **not** make any attempts to
586resend the message. This zero-retry policy is enabled by
587invoking the ``rmr_set_stimeout()`` with a value of 0; this
588can be done once immediately after ``rmr_init()`` is invoked.
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400589
590Regardless of the retry mode which the application sets, it
591will ultimately be up to the application to handle failures
592by queuing the message internally for resend, retrying
593immediately, or dropping the send attempt all together. As
594stated before, only the application can determine how to best
595handle send failures.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400596
597
598Other Failures
599--------------
600
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400601RMR will return the state of processing for message based
602operations (send/receive) as the status in the message
603buffer. For non-message operations, state is returned to the
604caller as the integer return value for all functions which
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400605are not expected to return a pointer (e.g.
606``rmr_init()``.) The following are the RMR state constants
607and a brief description of their meaning.
E. Scott Daniels392168d2019-11-06 15:12:38 -0500608
609
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400610 .. list-table::
611 :widths: auto
612 :header-rows: 0
613 :class: borderless
614
615 * - **RMR_OK**
616 -
617 state is good; operation finished successfully
618
619 * - **RMR_ERR_BADARG**
620 -
621 argument passed to function was unusable
622
623 * - **RMR_ERR_NOENDPT**
624 -
625 send/call could not find an endpoint based on msg type
626
627 * - **RMR_ERR_EMPTY**
628 -
629 msg received had no payload; attempt to send an empty message
630
631 * - **RMR_ERR_NOHDR**
632 -
633 message didn't contain a valid header
634
635 * - **RMR_ERR_SENDFAILED**
636 -
637 send failed; errno may contain the transport provider reason
638
639 * - **RMR_ERR_CALLFAILED**
640 -
641 unable to send the message for a call function; errno may
642 contain the transport provider reason
643
644 * - **RMR_ERR_NOWHOPEN**
645 -
646 no wormholes are open
647
648 * - **RMR_ERR_WHID**
649 -
650 the wormhole id provided was invalid
651
652 * - **RMR_ERR_OVERFLOW**
653 -
654 operation would have busted through a buffer/field size
655
656 * - **RMR_ERR_RETRY**
657 -
658 request (send/call/rts) failed, but caller should retry
659 (EAGAIN for wrappers)
660
661 * - **RMR_ERR_RCVFAILED**
662 -
663 receive failed (hard error)
664
665 * - **RMR_ERR_TIMEOUT**
666 -
667 response message not received in a reasonable amount of time
668
669 * - **RMR_ERR_UNSET**
670 -
671 the message hasn't been populated with a transport buffer
672
673 * - **RMR_ERR_TRUNC**
674 -
675 length in the received buffer is longer than the size of the
676 allocated payload, received message likely truncated (length
677 set by sender could be wrong, but we can't know that)
678
679 * - **RMR_ERR_INITFAILED**
680 -
681 initialisation of something (probably message) failed
682
683 * - **RMR_ERR_NOTSUPP**
684 -
685 the request is not supported, or RMR was not initialised for
686 the request
687
E. Scott Daniels392168d2019-11-06 15:12:38 -0500688
689
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400690Depending on the underlying transport mechanism, and the
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400691nature of the call that RMR attempted, the system
692``errno`` value might reflect additional detail about the
693failure. Applications should **not** rely on errno as some
694transport mechanisms do not set it with any consistency.
695
696
697Configuration and Control
698=========================
699
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400700With the assumption that most RMR based applications will be
701executed in a containerised environment, there are some
702underlying mechanics which the developer may need to know in
703order to properly provide a configuration specification to
704the container management system. The following paragraphs
705briefly discuss these.
E. Scott Daniels392168d2019-11-06 15:12:38 -0500706
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400707
708
709TCP Ports
710---------
711
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400712RMR requires two (2) TCP listen ports: one for general
713application-to-application communications and one for
714route-table updates. The general communication port is
715specified by the application at the time RMR is initialised.
716The port used to listen for route table updates is likely to
717be a constant port shared by all applications provided they
718are running in separate containers. To that end, the port
719number defaults to 4561, but can be configured with an
720environment variable (see later paragraph in this section).
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400721
722
723Host Names
724----------
725
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400726RMR is typically host name agnostic. Route table entries may
727contain endpoints defined either by host name or IP address.
728In the container world the concept of a *service name* might
729exist, and likely is different than a host name. RMR's only
730requirement with respect to host names is that a name used on
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400731a route table entry must be resolvable via the
732``gethostbyname`` system call.
733
734
735Environment Variables
736---------------------
737
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400738Several environment variables are recognised by RMR which, in
739general, are used to define interfaces and listen ports (e.g.
740the route table update listen port), or debugging
741information. Generally this information is system controlled
742and thus RMR expects this information to be defined in the
743environment rather than provided by the application. The
744following is a list of the environment variables which RMR
745recognises:
E. Scott Daniels392168d2019-11-06 15:12:38 -0500746
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400747
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400748 .. list-table::
749 :widths: auto
750 :header-rows: 0
751 :class: borderless
752
753 * - **RMR_BIND_IF**
754 -
755 The interface to bind to listen ports to. If not defined
756 0.0.0.0 (all interfaces) is assumed.
757
758 * - **RMR_RTG_SVC**
759 -
760 The port RMR will listen on for route manager connections. If
761 not defined 4561 is used.
762
763 * - **RMR_SEED_RT**
764 -
765 Where RMR expects to find the name of the seed (static) route
766 table. If not defined no static table is read.
767
768 * - **RMR_RTG_ISRAW**
769 -
770 If the value set to 0, RMR expects the route table manager
771 messages to be messages with and RMR header. If this is not
772 defined messages are assumed to be "raw" (without an RMR
773 header.
774
775 * - **RMR_VCTL_FILE**
776 -
777 Provides a file which is used to set the verbose level of the
778 route table collection thread. The first line of the file is
779 read and expected to contain an integer value to set the
780 verbose level. The value may be changed at any time and the
781 route table thread will adjust accordingly.
782
783 * - **RMR_SRC_NAMEONLY**
784 -
785 If the value of this variable is greater than 0, RMR will not
786 permit the IP address to be sent as the message source. Only
787 the host name will be sent as the source in the message
788 header.
789
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400790
791
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400792
793
794Logging
795-------
796
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400797RMR does **not** use any logging libraries; any error or
798warning messages are written to standard error. RMR messages
799are written with one of three prefix strings:
E. Scott Daniels392168d2019-11-06 15:12:38 -0500800
801
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400802 .. list-table::
803 :widths: auto
804 :header-rows: 0
805 :class: borderless
806
807 * - **[CRI]**
808 -
809 The event is of a critical nature and it is unlikely that RMR
810 will continue to operate correctly if at all. It is almost
811 certain that immediate action will be needed to resolve the
812 issue.
813
814 * - **[ERR]**
815 -
816 The event is not expected and RMR is not able to handle it.
817 There is a small chance that continued operation will be
818 negatively impacted. Eventual action to diagnose and correct
819 the issue will be necessary.
820
821 * - **[WRN]**
822 -
823 The event was not expected by RMR, but can be worked round.
824 Normal operation will continue, but it is recommended that
825 the cause of the problem be investigated.
826
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400827
828
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400829
830
831Notes
832=====
833
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400834
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400835 [1] It is entirely possible to design a routing table, and
836 application group, such that the same message type is is
837 left unchanged and the message is forwarded by an
838 application after updating the payload. This type of
839 behaviour is often referred to as service chaining, and can
840 be done without any "knowledge" by an application with
841 respect to where the message goes next. Service chaining is
842 supported by RMR in as much as it allows the message to be
843 resent, but the actual complexities of designing and
844 implementing service chaining lie with the route table
845 generator process.
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400846
847
848
849
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400850
851
852Appendix A -- Quick Reference
853=============================
854
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400855Please refer to the RMR manual pages on the Read the Docs
856site
857
858https://docs.o-ran-sc.org/projects/o-ran-sc-ric-plt-lib-rmr/en/latest/index.html
859
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400860
861
862Appendix B -- Message Buffer Details
863====================================
864
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400865The RMR message buffer is a C structure which is exposed in
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400866the ``rmr.h`` header file. It is used to manage a message
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400867received from a peer endpoint, or a message that is being
868sent to a peer. Fields include payload length, amount of
869payload actually used, status, and a reference to the
870payload. There are also fields which the application should
871ignore, and could be hidden in the header file, but we chose
872not to. These fields include a reference to the RMR header
873information, and to the underlying transport mechanism
874message struct which may or may not be the same as the RMR
875header reference.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400876
877
878The Structure
879-------------
880
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400881The following is the C structure. Readers are cautioned to
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400882examine the ``rmr.h`` header file directly; the information
883here may be out of date (old document in some cache), and
884thus it may be incorrect.
E. Scott Daniels392168d2019-11-06 15:12:38 -0500885
886
887::
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400888
889
890 typedef struct {
891 int state; // state of processing
892 int mtype; // message type
893 int len; // length of data in the payload (send or received)
894 unsigned char* payload; // transported data
895 unsigned char* xaction; // pointer to fixed length transaction id bytes
896 int sub_id; // subscription id
897 int tp_state; // transport state (errno)
898
899 // these things are off limits to the user application
900 void* tp_buf; // underlying transport allocated pointer (e.g. nng message)
901 void* header; // internal message header (whole buffer: header+payload)
902 unsigned char* id; // if we need an ID in the message separate from the xaction id
903 int flags; // various MFL_ (private) flags as needed
904 int alloc_len; // the length of the allocated space (hdr+payload)
905 void* ring; // ring this buffer should be queued back to
906 int rts_fd; // SI fd for return to sender
907 int cookie; // cookie to detect user misuse of free'd msg
908 } rmr_mbuf_t;
E. Scott Daniels392168d2019-11-06 15:12:38 -0500909
910
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400911
912
913State vs Transport State
914------------------------
915
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400916The state field reflects the state at the time the message
917buffer is returned to the calling application. For a send
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400918operation, if the state is not ``RMR_OK`` then the message
919buffer references the payload that could not be sent, and
920when the state is ``RMR_OK`` the buffer references a *fresh*
921payload that the application may fill in.
E. Scott Daniels392168d2019-11-06 15:12:38 -0500922
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400923When the state is not ``RMR_OK,`` C programmes may examine
924the global ``errno`` value which RMR will have left set, if
925it was set, by the underlying transport mechanism. In some
926cases, wrapper modules are not able to directly access the
927C-library ``errno`` value, and to assist with possible
928transport error details, the send and receive operations
929populate ``tp_state`` with the value of ``errno.``
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400930
931Regardless of whether the application makes use of the
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400932``tp_state,`` or the ``errno`` value, it should be noted that
933the underlying transport mechanism may not actually update
934the errno value; in other words: it might not be accurate. In
935addition, RMR populates the ``tp_state`` value in the message
936buffer **only** when the state is not ``RMR_OK.``
937
938
939Field References
940----------------
941
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400942The transaction field was exposed in the first version of
943RMR, and in hindsight this shouldn't have been done. Rather
944than break any existing code the reference was left, but
945additional fields such as trace data, were not directly
946exposed to the application. The application developer is
947strongly encouraged to use the functions which get and set
948the transaction ID rather than using the pointer directly;
949any data overruns will not be detected if the reference is
950used directly.
951
952In contrast, the payload reference should be used directly by
953the application in the interest of speed and ease of
954programming. The same care to prevent writing more bytes to
955the payload buffer than it can hold must be taken by the
956application. By the nature of the allocation of the payload
957in transport space, RMR is unable to add guard bytes and/or
958test for data overrun.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400959
960
961Actual Transmission
962-------------------
963
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400964When RMR sends the application's message, the message buffer
965is **not** transmitted. The transport buffer (tp_buf) which
966contains the RMR header and application payload is the only
967set of bytes which are transmitted. While it may seem to the
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400968caller like the function ``rmr_send_msg()`` is returning a
969new message buffer, the same struct is reused and only a new
970transport buffer is allocated. The intent is to keep the
971alloc/free cycles to a minimum.
E. Scott Daniels392168d2019-11-06 15:12:38 -0500972
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400973
974
975Appendix C -- Glossary
976======================
977
E. Scott Daniels5a9d1752020-04-17 17:07:06 -0400978Many terms in networking can be interpreted with multiple
E. Scott Danielsa3a121c2020-05-06 09:07:08 -0400979meanings, and several terms used in various RMR documentation
980are RMR specific. The following definitions are the meanings
981of terms used within RMR documentation and should help the
982reader to understand the intent of meaning.
983
984 .. list-table::
985 :widths: 25,70
986 :header-rows: 0
987 :class: borderless
988
989 * - **application**
990 -
991 A programme which uses RMR to send and/or receive messages
992 to/from another RMR based application.
993
994 * - **Critical error**
995 -
996 An error that RMR has encountered which will prevent further
997 successful processing by RMR. Critical errors usually
998 indicate that the application should abort.
999
1000 * - **Endpoint**
1001 -
1002 An RMR based application that is defined as being capable of
1003 receiving one or more types of messages (as defined by a
1004 *message key.*)
1005
1006 * - **Environment variable**
1007 -
1008 A key/value pair which is set externally to the application,
1009 but which is available to the application (and referenced
1010 libraries) through the ``getenv`` system call. Environment
1011 variables are the main method of communicating information
1012 such as port numbers to RMR.
1013
1014 * - **Error**
1015 -
1016 An abnormal condition that RMR has encountered, but will not
1017 affect the overall processing by RMR, but may impact certain
1018 aspects such as the ability to communicate with a specific
1019 endpoint. Errors generally indicate that something, usually
1020 external to RMR, must be addressed.
1021
1022 * - **Host name**
1023 -
1024 The name of the host as returned by the ``gethostbyname``
1025 system call. In a containerised environment this might be the
1026 container or service name depending on how the container is
1027 started. From RMR's point of view, a host name can be used to
1028 resolve an *endpoint* definition in a *route* table.)
1029
1030 * - **IP**
1031 -
1032 Internet protocol. A low level transmission protocol which
1033 governs the transmission of datagrams across network
1034 boundaries.
1035
1036 * - **Listen socket**
1037 -
1038 A *TCP* socket used to await incoming connection requests.
1039 Listen sockets are defined by an interface and port number
1040 combination where the port number is unique for the
1041 interface.
1042
1043 * - **Message**
1044 -
1045 A series of bytes transmitted from the application to another
1046 RMR based application. A message is comprised of RMR specific
1047 data (a header), and application data (a payload).
1048
1049 * - **Message buffer**
1050 -
1051 A data structure used to describe a message which is to be
1052 sent or has been received. The message buffer includes the
1053 payload length, message type, message source, and other
1054 information.
1055
1056 * - **Messgae type**
1057 -
1058 A signed integer (0-32000) which identifies the type of
1059 message being transmitted, and is one of the two components
1060 of a *routing key.* See *Subscription ID.*
1061
1062 * - **Payload**
1063 -
1064 The portion of a message which holds the user data to be
1065 transmitted to the remote *endpoint.* The payload contents
1066 are completely application defined.
1067
1068 * - **RMR context**
1069 -
1070 A set of information which defines the current state of the
1071 underlying transport connections that RMR is managing. The
1072 application will be give a context reference (pointer) that
1073 is supplied to most RMR functions as the first parameter.
1074
1075 * - **Round robin**
1076 -
1077 The method of selecting an *endpoint* from a list such that
1078 all *endpoints* are selected before starting at the head of
1079 the list.
1080
1081 * - **Route table**
1082 -
1083 A series of "rules" which define the possible *endpoints* for
1084 each *message key.*
1085
1086 * - **Route table manager**
1087 -
1088 An application responsible for building a *route table* and
1089 then distributing it to all applicable RMR based
1090 applications.
1091
1092 * - **Routing**
1093 -
1094 The process of selecting an *endpoint* which will be the
1095 recipient of a message.
1096
1097 * - **Routing key**
1098 -
1099 A combination of *message type* and *subscription ID* which
1100 RMR uses to select the destination *endpoint* when sending a
1101 message.
1102
1103 * - **Source**
1104 -
1105 The sender of a message.
1106
1107 * - **Subscription ID**
1108 -
1109 A signed integer value (0-32000) which identifies the
1110 subscription characteristic of a message. It is used in
1111 conjunction with the *message type* to determine the *routing
1112 key.*
1113
1114 * - **Target**
1115 -
1116 The *endpoint* selected to receive a message.
1117
1118 * - **TCP**
1119 -
1120 Transmission Control Protocol. A connection based internet
1121 protocol which provides for lossless packet transportation,
1122 usually over IP.
1123
1124 * - **Thread**
1125 -
1126 Also called a *process thread, or pthread.* This is a
1127 lightweight process which executes in concurrently with the
1128 application and shares the same address space. RMR uses
1129 threads to manage asynchronous functions such as route table
1130 updates. &Term An optional portion of the message buffer that
1131 the application may populate with data that allows for
1132 tracing the progress of the transaction or application
1133 activity across components. RMR makes no use of this data.
1134
1135 * - **Transaction ID**
1136 -
1137 A fixed number of bytes in the *message* buffer) which the
1138 application may populate with information related to the
1139 transaction. RMR makes use of the transaction ID for matching
1140 response messages with the &c function is used to send a
1141 message.
1142
1143 * - **Transient failure**
1144 -
1145 An error state that is believed to be short lived and that
1146 the operation, if retried by the application, might be
1147 successful. C programmers will recognise this as
1148 ``EAGAIN.``
1149
1150 * - **Warning**
1151 -
1152 A warning occurs when RMR has encountered something that it
1153 believes isn't correct, but has a defined work round.
1154
1155 * - **Wormhole**
1156 -
1157 A direct connection managed by RMR between the user
1158 application and a remote, RMR based, application.
1159
E. Scott Daniels5a9d1752020-04-17 17:07:06 -04001160
1161
E. Scott Danielsa3a121c2020-05-06 09:07:08 -04001162
1163
1164Appendix D -- Code Examples
1165===========================
1166
1167The following snippet of code illustrate some of the basic
1168operation of the RMR library. Please refer to the examples
1169and test directories in the RMR repository for complete RMR
E. Scott Daniels5a9d1752020-04-17 17:07:06 -04001170based programmes.
E. Scott Danielsa3a121c2020-05-06 09:07:08 -04001171
1172
1173Sender Sample
1174-------------
1175
E. Scott Daniels5a9d1752020-04-17 17:07:06 -04001176The following code segment shows how a message buffer can be
1177allocated, populated, and sent. The snippet also illustrates
E. Scott Danielsa3a121c2020-05-06 09:07:08 -04001178how the result from the ``rmr_send_msg()`` function is used
1179to send the next message. It does not illustrate error and/or
1180retry handling.
E. Scott Daniels8633a0b2020-03-09 13:57:39 -04001181
1182
1183::
E. Scott Daniels392168d2019-11-06 15:12:38 -05001184
E. Scott Danielsa3a121c2020-05-06 09:07:08 -04001185
1186 #include <unistd.h>
1187 #include <errno.h>
1188 #include <string.h>
1189 #include <stdio.h>
1190 #include <stdlib.h>
1191 #include <sys/epoll.h>
1192 #include <time.h>
1193
1194 #include <rmr/rmr.h>
1195
1196 int main( int argc, char** argv ) {
1197 void* mrc; // msg router context
1198 struct epoll_event events[1]; // list of events to give to epoll
1199 struct epoll_event epe; // event definition for event to listen to
1200 int ep_fd = -1; // epoll's file des (given to epoll_wait)
1201 int rcv_fd; // file des for epoll checks
1202 int nready; // number of events ready for receive
1203 rmr_mbuf_t* sbuf; // send buffer
1204 rmr_mbuf_t* rbuf; // received buffer
1205 int count = 0;
1206 int rcvd_count = 0;
1207 char* listen_port = "43086";
1208 int delay = 1000000; // mu-sec delay between messages
1209 int mtype = 0;
1210 int stats_freq = 100;
1211
1212 if( argc > 1 ) { // simplistic arg picking
1213 listen_port = argv[1];
1214 }
1215 if( argc > 2 ) {
1216 delay = atoi( argv[2] );
1217 }
1218 if( argc > 3 ) {
1219 mtype = atoi( argv[3] );
1220 }
1221
1222 fprintf( stderr, "<DEMO> listen port: %s; mtype: %d; delay: %d\\n",
1223 listen_port, mtype, delay );
1224
1225 if( (mrc = rmr_init( listen_port, 1400, RMRFL_NONE )) == NULL ) {
1226 fprintf( stderr, "<DEMO> unable to initialise RMR\\n" );
1227 exit( 1 );
1228 }
1229
1230 rcv_fd = rmr_get_rcvfd( mrc ); // set up epoll things, start by getting the FD from RMR
1231 if( rcv_fd < 0 ) {
1232 fprintf( stderr, "<DEMO> unable to set up polling fd\\n" );
1233 exit( 1 );
1234 }
1235 if( (ep_fd = epoll_create1( 0 )) < 0 ) {
1236 fprintf( stderr, "[FAIL] unable to create epoll fd: %d\\n", errno );
1237 exit( 1 );
1238 }
1239 epe.events = EPOLLIN;
1240 epe.data.fd = rcv_fd;
1241
1242 if( epoll_ctl( ep_fd, EPOLL_CTL_ADD, rcv_fd, &epe ) != 0 ) {
1243 fprintf( stderr, "[FAIL] epoll_ctl status not 0 : %s\\n", strerror( errno ) );
1244 exit( 1 );
1245 }
1246
1247 sbuf = rmr_alloc_msg( mrc, 256 ); // alloc 1st send buf; subsequent bufs alloc on send
1248 rbuf = NULL; // don't need to alloc receive buffer
1249
1250 while( ! rmr_ready( mrc ) ) { // must have route table
1251 sleep( 1 ); // wait til we get one
1252 }
1253 fprintf( stderr, "<DEMO> rmr is ready\\n" );
1254
1255
1256 while( 1 ) { // send messages until the cows come home
1257 snprintf( sbuf->payload, 200,
1258 "count=%d received= %d ts=%lld %d stand up and cheer!", // create the payload
1259 count, rcvd_count, (long long) time( NULL ), rand() );
1260
1261 sbuf->mtype = mtype; // fill in the message bits
1262 sbuf->len = strlen( sbuf->payload ) + 1; // send full ascii-z string
1263 sbuf->state = 0;
1264 sbuf = rmr_send_msg( mrc, sbuf ); // send & get next buf to fill in
1265 while( sbuf->state == RMR_ERR_RETRY ) { // soft failure (device busy?) retry
1266 sbuf = rmr_send_msg( mrc, sbuf ); // w/ simple spin that doesn't give up
1267 }
1268 count++;
1269
1270 // check to see if anything was received and pull all messages in
1271 while( (nready = epoll_wait( ep_fd, events, 1, 0 )) > 0 ) { // 0 is non-blocking
1272 if( events[0].data.fd == rcv_fd ) { // waiting on 1 thing, so [0] is ok
1273 errno = 0;
1274 rbuf = rmr_rcv_msg( mrc, rbuf ); // receive and ignore; just count
1275 if( rbuf ) {
1276 rcvd_count++;
1277 }
1278 }
1279 }
1280
1281 if( (count % stats_freq) == 0 ) { // occasional stats out to tty
1282 fprintf( stderr, "<DEMO> sent %d received %d\\n", count, rcvd_count );
1283 }
1284
1285 usleep( delay );
1286 }
1287 }
1288
E. Scott Daniels392168d2019-11-06 15:12:38 -05001289
E. Scott Danielsa3a121c2020-05-06 09:07:08 -04001290
1291
1292Receiver Sample
1293---------------
1294
E. Scott Daniels5a9d1752020-04-17 17:07:06 -04001295The receiver code is even simpler than the sender code as it
1296does not need to wait for a route table to arrive (only
1297senders need to do that), nor does it need to allocate an
1298initial buffer. The example assumes that the sender is
1299transmitting a zero terminated string as the payload.
E. Scott Daniels4d1f9bf2020-03-06 12:29:28 -05001300
1301
1302::
E. Scott Daniels4d1f9bf2020-03-06 12:29:28 -05001303
E. Scott Danielsa3a121c2020-05-06 09:07:08 -04001304
1305 #include <unistd.h>
1306 #include <errno.h>
1307 #include <stdio.h>
1308 #include <stdlib.h>
1309 #include <time.h>
1310
1311 #include <rmr/rmr.h>
1312
1313
1314 int main( int argc, char** argv ) {
1315 void* mrc; // msg router context
1316 long long total = 0;
1317 rmr_mbuf_t* msg = NULL; // message received
1318 int stat_freq = 10; // write stats after reciving this many messages
1319 int i;
1320 char* listen_port = "4560"; // default to what has become the standard RMR port
1321 long long count = 0;
1322 long long bad = 0;
1323 long long empty = 0;
1324
1325 if( argc > 1 ) {
1326 listen_port = argv[1];
1327 }
1328 if( argc > 2 ) {
1329 stat_freq = atoi( argv[2] );
1330 }
1331 fprintf( stderr, "<DEMO> listening on port: %s\\n", listen_port );
1332 fprintf( stderr, "<DEMO> stats will be reported every %d messages\\n", stat_freq );
1333
1334 mrc = rmr_init( listen_port, RMR_MAX_RCV_BYTES, RMRFL_NONE );
1335 if( mrc == NULL ) {
1336 fprintf( stderr, "<DEMO> ABORT: unable to initialise RMr\\n" );
1337 exit( 1 );
1338 }
1339
1340 while( ! rmr_ready( mrc ) ) { // wait for RMR to get a route table
1341 fprintf( stderr, "<DEMO> waiting for ready\\n" );
1342 sleep( 3 );
1343 }
1344 fprintf( stderr, "<DEMO> rmr now shows ready\\n" );
1345
1346 while( 1 ) { // receive until killed
1347 msg = rmr_rcv_msg( mrc, msg ); // block until one arrives
1348
1349 if( msg ) {
1350 if( msg->state == RMR_OK ) {
1351 count++; // nothing fancy, just count
1352 } else {
1353 bad++;
1354 }
1355 } else {
1356 empty++;
1357 }
1358
1359 if( (count % stat_freq) == 0 ) {
1360 fprintf( stderr, "<DEMO> total received: %lld; errors: %lld; empty: %lld\\n",
1361 count, bad, empty );
1362 }
1363 }
1364 }
1365
E. Scott Daniels4d1f9bf2020-03-06 12:29:28 -05001366
E. Scott Danielsa3a121c2020-05-06 09:07:08 -04001367
1368
1369Receive and Send Sample
1370-----------------------
1371
E. Scott Daniels5a9d1752020-04-17 17:07:06 -04001372The following code snippet receives messages and responds to
1373the sender if the message type is odd. The code illustrates
1374how the received message may be used to return a message to
1375the source. Variable type definitions are omitted for clarity
1376and should be obvious.
E. Scott Daniels4d1f9bf2020-03-06 12:29:28 -05001377
E. Scott Daniels5a9d1752020-04-17 17:07:06 -04001378It should also be noted that things like the message type
1379which id returned to the sender (99) is a random value that
1380these applications would have agreed on in advance and is
1381**not** an RMR definition.
E. Scott Daniels4d1f9bf2020-03-06 12:29:28 -05001382
E. Scott Daniels4d1f9bf2020-03-06 12:29:28 -05001383
E. Scott Daniels5a9d1752020-04-17 17:07:06 -04001384::
E. Scott Daniels4d1f9bf2020-03-06 12:29:28 -05001385
E. Scott Danielsa3a121c2020-05-06 09:07:08 -04001386 mrc = rmr_init( listen_port, MAX_BUF_SZ, RMRFL_NOFLAGS );
1387 rmr_set_stimeout( mrc, 1 ); // allow RMR to retry failed sends for ~1ms
1388
1389 while( ! rmr_ready( mrc ) ) { // we send, therefore we need a route table
1390 sleep( 1 );
1391 }
1392
1393 mbuf = NULL; // ensure our buffer pointer is nil for 1st call
1394
1395 while( TRUE ) {
1396 mbuf = rmr_rcv_msg( mrc, mbuf ); // wait for message
1397
1398 if( mbuf == NULL || mbuf->state != RMR_OK ) {
1399 break;
1400 }
1401
1402 if( mbuf->mtype % 2 ) { // respond to odd message types
1403 plen = rmr_payload_size( mbuf ); // max size
1404
1405 // reset necessary fields in msg
1406 mbuf->mtype = 99; // response type
1407 mbuf->sub_id = RMR_VOID_SUBID; // we turn subid off
1408 mbuf->len = snprintf( mbuf->payload, plen, "pong: %s", get_info() );
1409
1410 mbuf = rmr_rts_msg( mrc, mbuf ); // return to sender
1411 if( mbuf == NULL || mbuf->state != RMR_OK ) {
1412 fprintf( stderr, "return to sender failed\\n" );
1413 }
1414 }
1415 }
1416
1417 fprintf( stderr, "abort: receive failure\\n" );
1418 rmr_close( mrc );
1419
E. Scott Daniels4d1f9bf2020-03-06 12:29:28 -05001420
1421