set( major_version "1" ) # should be automatically populated from git tag later, but until CI process sets a tag we use this
set( minor_version "1" )
-set( patch_level "0" )
+set( patch_level "1" )
set( install_root "${CMAKE_INSTALL_PREFIX}" )
set( install_inc "include/rmr" )
--- /dev/null
+
+Directories within this directory contains collections of documents
+such as the manual pages and main RMR user guide. Three are some
+imbed files at this level which make setup to generate document
+output in different flavours (e.g. postscript and troff) possible.
+
+For the most part, document output is genreated during the build
+process and left at the top level build directory. Manual pages
+are the noted exception as the troff output is placed into the
+development pacage files and will be installed with the RMR library
+(archive) such that the standard UNIX man command will generate
+the needed documentation that develoers expect.
+
+
+Directory overview:
+ library - Documentation on the RMR libraray itself. User manual
+ and internal doc.
+
+ binding - Any documentation needed for the language wrappers
+ or bindings.
+
+ man - Manual page source.
+
+ tools - Some useful things that migth make building and/or
+ maintaining documents easier.
.dv center_start .bc start
.dv center_end .bc end
- .dv line_len .ll $1
+ .dv line_len .ll $1 .dv cn_line_len $1 ^:
.dv space .sp 1
.dv mult_space .sp $1
.dv half_space .sp .5
+
.dv beg_list .bl $1
.dv end_list .el
+ .dv lic1 n
+ .dv lic2 m
+ .dv lic3 l
+
.dv beg_dlist .bd $1 $2
.dv end_dlist .ed
- .dv ditem .di $1 ^:
- .dv di .di $1 ^:
- .dv li .li
+ .dv ditem .cc 2 .di $1 ^:
+ .dv di .cc 2 .di $1 ^:
+ .dv li .cc 2 .li
+ .dv item .cc 2 .li
- .dv ex_start .st ^&ex_size .sf ^&cw_font .nf
+ .dv proto_start .sp 1 .cc .5i .st 9 .sf Courier-bold .nf
+ .dv proto_end .fo on .sf ^&text_font .st ^&text_size .sp .3
+
+ .dv ex_start .sp .5 .st ^&ex_size .sf ^&cw_font .nf
.dv ex_end .fo on .sf ^&text_font .st ^&text_size .sp 1
.** fonts and font macros
.dv cw .tf ^&cw_font ^&text_size $1 ^:
.dv set_font_prop .sf ^&text_font
- .cd 1 6.5i
+ .cd 1 6.0i
.ll 6i
.pn off
.ju on
.in .5i
+ .dv cn_indent .5i
+ .dv cn_line_len 6i
.dv indent .ll -0.5i .in +0.25i
.dv uindent .in -0.25i .ll +0.5i
.dv super .sm ^[ .sm ^&{ss_num}]
+ .dv ss_num 1
.dv note .dv ss_num ^[ ?%.0f ^&ss_num 1 + ] ^: .sm .tf superscript /2 ^&{ss_num} ^:
+ .dv atbot atbot
--- /dev/null
+*.ca
+*.bncfile
+*.ecnfile
+*.ps
+*.pdf
+*.txt
+*.rst
+*.md
+*.toc
--- /dev/null
+
+#==================================================================================
+# Copyright (c) 2019 Nokia
+# Copyright (c) 2018-2019 AT&T Intellectual Property.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#==================================================================================
+
+%.ps: %.xfm
+ pfm $< $@
+
+%.md: %.xfm
+ OUTPUT_TYPE=markdown tfm $< stdout | sed 's/^ //' >$@
+
+%.rst: %.xfm
+ OUTPUT_TYPE=rst tfm $< stdout | sed 's/^ //' >$@
+
+%.txt: %.xfm
+ OUTPUT_TYPE=txt tfm $< stdout
+ OUTPUT_TYPE=txt tfm $< $@
+
+%.pdf: %.ps
+ gs -dQUIET -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=$@ $<
+
+src = user.xfm advanced_use.im api_qref.im code_appendix.im code_send.im config.im failures.im general_use.im glossary.im index_snatch.im setup.im mbuf.im front_junk.im license.im
+code_src = $(shell ls code_*.im)
+
+all: user.pdf user.txt user.rst user.md
+
+# two pass build for pfm to allow for toc insertion
+user.ps: $(src) $(code_src)
+ XFM_PASS=1 pfm $< /dev/null
+ XFM_PASS=2 pfm $< $@
+
+user.md: $(src) $(code_src)
+ OUTPUT_TYPE=markdown XFM_PASS=1 tfm $< /dev/null
+ OUTPUT_TYPE=markdown XFM_PASS=2 tfm $< $@
+
+user.rst: $(src) $(code_src)
+ OUTPUT_TYPE=rst XFM_PASS=1 tfm $< /dev/null
+ OUTPUT_TYPE=rst XFM_PASS=2 tfm $< $@
+
+user.txt: $(src) $(code_src)
+ OUTPUT_TYPE=txt XFM_PASS=1 tfm $< /dev/null
+ OUTPUT_TYPE=txt XFM_PASS=2 tfm $< $@
+
+# intermeidate junk that might straggle
+clean:
+ rm -fr *.bcnfile *.ca *.ecnfile
+
+# Anything that can be built
+nuke: clean
+ rm -fr *.ps *.pdf *.txt *.rst
+
--- /dev/null
+
+This directory contains the main RMR library documentation
+such as the user guide and any internal doc; all of which will
+likely share a common set of figures, glossary, and index
+lists. The "main" for each doc is the single .xfm file and
+all modules are contained in .im files to allow sharing between
+documents as makes sense (e.g. glossary).
+
+Illustrations are all located in the ./figures directory and
+are created as .fig files [1] which describe drawings using an
+open ASCII format (rather than as a binary and/or propriatory
+descritption). ASCII descriptions are easily maintained as
+source code to track changes and revert when necessary.
+A Dockerfile in the tools directory can be used to build a
+"development image" with all of the tools needed to render
+the PNG and encapsulated postscript derivations from the ASCII
+descriptions. Use of this image is not required, but might be
+needed if a development environment doesn't provide Xfig and
+the related tools.
+
+[1]
+ Defacto standard tools for creating and managing .fig files:
+
+ Install Xfig on a Linux system with:
+ apt-get install xfig (ubuntu-ish)
+ zypper install xfig (OpenSuse)
+
+ The fig2dev tool is used to "batch" process .fig files in
+ order to generate desired output (.eps, .png, etc.). These
+ can be installed with commands such as:
+ apt-get install fig2dev
+ zypper install transfig
--- /dev/null
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+.if false
+ Mnemonic: advanced_use.im
+ Abstract: Major section discussion the advanced features of RMR
+ Date: 30 July 2019
+ Author: E. Scott Daniels
+.fi
+
+&h1(Advanced Usage)
+Several forms of usage fall into a more advanced category and are described in the following sections.
+These include blocking call, return to sender and wormhole functions.
+
+&h2(The Call Function)
+The RMR function &func(rmr_call) will send a message in the exact same manner as the &cw(rmr_send_msg()) function,
+with the endpoint selection based on the message key.
+Unlike the send function, &func(rmr_call) will block and wait for a response from the application that is selected
+to receive the message.
+The matching message is determined by the transaction ID which the application must place into the message buffer
+prior to invoking &func(rmr_call) .sm .
+Similarly, the responding application must ensure that the same transaction ID is placed into the message buffer
+before returning its response.
+
+&space
+The return from the call is a message buffer with the response message; there is no difference between a message
+buffer returned by the receive function and one returned by the &fucnt(rmr_call) function.
+If a response is not received in a reasonable amount of time, a nil message buffer is returned to the calling
+application.
+
+&h3(Returning a Response)
+Because of the nature of RMR's routing policies, it is generally not possible for an application to control
+exactly which endpoint is sent a message.
+There are cases, such as responding to a message delivered via &func(rmr_call:) that the application must
+send a message and guarantee that RMR routes it to an exact destination.
+To enable this, RMR provides the &func(rmr_rts_msg:,) return to sender, function.
+Upon receipt of any message, an application may alter the payload, and if necessary the message type and subscription
+ID, an pass the altered message buffer to the &func(rmr_rts_msg:) function to return the altered message
+to the application which sent it.
+When this function is used, RMR will examine the message buffer for the source information and use that to
+select the connection on which to write the response.
+
+&h3(Multi-threaded Calls)
+The basic call mechanism described above is &bold(not) thread safe, as it is not possible to guarantee that a response
+message is delivered to the correct thread.
+The RMR function &func(rmr_mt_call) accepts an additional parameter which identifies the calling thread in order
+to ensure that the response is delivered properly.
+In addition, the application must specifically initialise the multi-threaded call environment by passing the
+&cw(RMRFL_MTCALL) flag as an option to the &func(rmr_init) function ¬e .sm .
+.if pfm
+.dv cnopts l=&cn_line_len i=&cn_indent
+.dv cncmd .cn start &cnopts &atbot Times-roman 8p .7i
+.ei
+.dv cncmd .cn start &atbot Times-roman 8p .7i
+.fi
+
+&cncmd
+ There is additional overhead to support multi-threaded call as a special listener thread must be used
+ in order to deliver responses to the proper application thread.
+.cn end
+
+&space
+One advantage of the multi-threaded call capability in RMR is the fact that only the calling thread is
+blocked. Messages received which are not responses to the call are continued to be delivered via normal
+&func(rmr_rcv_msg) calls.
+
+
+&space
+While the process is blocked waiting for the response, it is entirely possible that asynchronous, nonmatching,
+messages will arrive.
+When this happens, RMR will queues the messages and return them to the application over the next calls to
+&func(rmr_rcv_msg:.)
+
+
+&h2(Wormholes)
+As was mentioned earlier, the design of RMR is to eliminate the need for an application to know a specific
+endpoint, even when a response message is being sent.
+In some rare cases it may be necessary for an application to establish a direct connection to an RMR based
+application rather than relying on message type and subscription ID based routing.
+The &ital(wormhole) functions provide an application with the ability to create a direct connection and then
+to send and receive messages across the connection.
+The following are the RMR functions which provide wormhole communications:
+
+&space
+&indent
+&beg_dlist( 1i Helvetica )
+ &di(rmr_wh_open) Open a connection to an endpoint. Name or IP address and port of the endpoint is supplied.
+ Returns a wormhole ID that the application must use when sending a direct message.
+ &half_space
+
+ &di(rmr_wh_send_msg) Sends an RMR message buffer to the connected application. The message type and subscription
+ ID may be set in the message, but RMR will ignore both.
+ &half_space
+
+ &di(rmr_wh_close) Closes the direct connection.
+&end_dlist
+&uindent
+&space
--- /dev/null
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+.if false
+ Mnemonic: api_qr.im
+ Abstract: A quick reference to all external function calls
+ Date: 2 August, 2019
+ Author: E. Scott Daniels
+.fi
+
+&h1(Appendix &qr_appendix -- Quick Reference)
+The prototype for each of the externally available functions which comprise the RMR API is listed
+in alphabetical order below.
+For each prototype a brief description of the function is given.
+The developer is encouraged to install the RMR development package which contains the manual pages.
+The manual pages completely describe each function in a level of detail consistent with UNIX man pages.
+
+&h2(Context Specific Functions)
+These functions require that the RMR context (provided as the result of an &func(rmr_init:) call, be
+passed as the first argument (vctx).
+
+&proto_start
+rmr_mbuf_t* rmr_alloc_msg( void* vctx, int size );
+&proto_end
+This function allocates a &ital(zero copy) message buffer.
+The payload portion is allocated from the underlying transport space such that on send the buffer
+does not require a second copy.
+The size parameter is the size of the payload portion of the buffer; if the recipient of the
+message is expected to send a response, this should be large enough to accomodate the response
+which will enable the remote application to reuse the message for the response and avoid a costly
+reallocation.
+
+&proto_start
+rmr_mbuf_t* rmr_call( void* vctx, rmr_mbuf_t* msg );
+&proto_end
+The call function accepts a message, selects an endpoint to receive the message and sends the message.
+RMR will block the return to the application until a matching response is received, or a timeout period
+is reached.
+The transaction ID in the outbound message is used to match a response, so it is imperative that
+the application making the response reuse the received message, or copy the transaction ID to the new
+message before sending.
+Messages arriving which do not match the expected response are queued and will be delivered to the
+application on subsequent calls to &func(rmr_rcv_msg:.)
+
+&proto_start
+void rmr_close( void* vctx );
+&proto_end
+This function terminates all sessions with the underlying transport mechanism.
+Buffers pending may or may not be flushed (depending on the underlying mechanism), thus it is
+recommended that before using this function the application pause for a second or two to
+ensure that the pending transmissions have completed.
+
+&proto_start
+int rmr_get_rcvfd( void* vctx );
+&proto_end
+When the underlying transport mechanism supports this, a file descriptor suitable for use with
+the &cw(select, poll) and &cw(epoll) system calls is returned.
+The file descriptor may not be used for read or write operations; doing so will have unpredictable
+results.
+
+&proto_start
+void* rmr_init( char* proto_port, int max_msg_size, int flags );
+&proto_end
+This function must be used before all other RMR functions to initialise the environment.
+The &cw(max_msg_size) parameter defines the maximum receive buffer size which will be
+used if required by the underlying transport mechanism.
+The value is also used as the default payload size if a zero length is given to &func(rmr_alloc_msg:.)
+
+&proto_start
+rmr_mbuf_t* rmr_mt_call( void* vctx, rmr_mbuf_t* mbuf, int call_id, int max_wait );
+&proto_end
+Similar to the &func(rmr_call:) function, the message is sent to an endpoint and a response message
+is waited for.
+This call is thread safe, and while the thread that invokes this function blocks on the response,
+it is possible for other application threads to continue to receive messages via the &func(rmr_rcv_msg:)
+function.
+&space
+In order to use the multi-threaded call functions, the option to enable threaded receive support
+must be set on the call to &func(rmr_init:.)
+
+&proto_start
+rmr_mbuf_t* rmr_mtosend_msg( void* vctx, rmr_mbuf_t* msg, int max_to );
+&proto_end
+This function sends the provided message allowing RMR to retry soft failures for approximately
+&ccw(max_to) milliseconds.
+When a value of zero (0) is given for the maximum timeout, RMR will not attempt any retires
+and will return the state after the first attempt.
+It is unlikely that a user application will use this function as it is possible (and recommended)
+to set the max timeout via the specific, one time, function call, and then to allow that value
+to be used as the default when &func(rmr_send_msg:) is invoked.
+
+&proto_start
+rmr_mbuf_t* rmr_mt_rcv( void* vctx, rmr_mbuf_t* mbuf, int max_wait );
+&proto_end
+This function waits for a message to arrive and returns a message buffer with the received
+message.
+The function will timeout after &cw(max_wait) milliseconds (approximately) if no message is
+received.
+
+&proto_start
+rmr_mbuf_t* rmr_send_msg( void* vctx, rmr_mbuf_t* msg );
+&proto_end
+This function accepts a message, selects a destination endpoint using the message type and subscription ID,
+and then attempts to send the message to the destination.
+The function returns a message buffer to the caller with the state set to indicate the state of the
+send operation.
+On success, the message buffer is a new buffer that the application can "fill in," and send without the
+need to overtly allocate a new buffer.
+On failure, the message buffer is the buffer that the application attempted to send.
+
+&proto_start
+int rmr_init_trace( void* vctx, int size );
+&proto_end
+This function is used to set the default trace data size.
+The size defaults to zero until this function is called; after the application sets a non-zero value
+messages created with the &func(rmr_alloc_msg:) function will be allocated with trace data set to
+the size provided.
+
+&proto_start
+rmr_mbuf_t* rmr_rcv_msg( void* vctx, rmr_mbuf_t* old_msg );
+&proto_end
+The &func(rmr_rcv_msg:) function is used to block and wait for a message to arrive.
+When a message is received a pointer to an RMR message buffer structure is returned to the caller.
+The &cw(old_msg) parameter allows the application to to pass a message buffer for reuse.
+If the application does not have an old buffer, a nil pointer is given and the function will
+allocate a new buffer.
+
+&proto_start
+rmr_mbuf_t* rmr_rcv_specific( void* uctx, rmr_mbuf_t* msg, char* expect,
+ int allow2queue );
+&proto_end
+This function blocks until a message with a specific transaction ID is received.
+If the &cw(allowd2queue) parameter is set to 1, messagess which do not match the ID are queued
+and returned to the application on subsequent calls to &func(rmr_rcv_msg:.)
+
+
+&proto_start
+int rmr_ready( void* vctx );
+&proto_end
+This function is used to test whether RMR is capable of sending messages.
+In other words once this function returns true (!0) RMR has received a route table (either from a static
+file or from a route manager process, and can map message types to endpoints.
+If the application attempts to send a message before this function returns true, the sends
+will fail.
+Applications which are only message receivers do not need to use this function.
+
+&proto_start
+rmr_mbuf_t* rmr_rts_msg( void* vctx, rmr_mbuf_t* msg );
+&proto_end
+The &func(rmr_rts_msg:) function allows the application to send a response message to the endpoint
+from which the message originated.
+This requires that the application use the same message buffer that was received for the
+response as it contains the sender information that is needed for this function to be successful.
+If the message cannot be sent, a pointer to the message buffer is returned and the status in the
+message buffer is set to indicate the reason.
+On success, a nil pointer will be returned.
+
+
+&proto_start
+int rmr_set_rtimeout( void* vctx, int time );
+&proto_end
+This function provides the ability to return from a receive operation after a timeout threshold
+is reached before a message is received, and is intended only to support the underlying Nanomsg
+transport mechanism (support for Nanomsg is deprecated).
+The &func(rmr_torcv_msg) function should be used if timed receives are required.
+&space
+
+For transport mechanisms which support a receive timeout, this function allows the application to
+set a default timeout for receive operations.
+If a call to &func(rmr_rcv_msg) does not complete before &ital(time) milliseconds has elapsed,
+the receive function will return a nil message buffer.
+This may not be supported by the underlying transport mechanism, and if it is not the return
+from this function will be -1.
+
+&proto_start
+int rmr_set_stimeout( void* vctx, int rounds );
+&proto_end
+This function allows the application to set a maximum number of retry &ital(rounds) that RMR will
+attempt when send operations report a transient (retry) failure.
+Each &ital(round) of retries requires approximately 1 millisecond, and setting the number of
+rounds to zero (0) causes RMR to report the transient failure to the application without
+any retry attempts.
+If the user application does not invoke this function, the default is one (1) round of retries.
+
+&proto_start
+rmr_mbuf_t* rmr_torcv_msg( void* vctx, rmr_mbuf_t* old_msg, int ms_to );
+&proto_end
+This function because identically to the &func(rmr_rcv_msg) function, and allows the application to
+set a specific timeout value for the receive operation.
+If a message is not received before the timeout period expires (ms_to milliseconds), a message buffer
+is returned with the state set to &cw(RMR_ERR_TIMEOUT.)
+
+
+&proto_start
+rmr_mbuf_t* rmr_tralloc_msg( void* context, int msize, int trsize,
+ unsigned const char* data );
+&proto_end
+Similar to the &func(rmr_alloc_msg) this function allocates a message buffer, and adds the
+referenced trace data to the buffer.
+The new message buffer is returned.
+
+&proto_start
+void rmr_wh_close( void* vctx, int whid );
+&proto_end
+This function closes an existing wormhole connection.
+
+
+&proto_start
+rmr_whid_t rmr_wh_open( void* vctx, char const* target );
+&proto_end
+This function allows the application to create a &ital(wormhole,) direct, connection to another application.
+The peer application must also be using RMR (messages sent on a wormhole connection are RMR messages).
+The target may be a hostname:port or IP-address:port combination.
+Upon successful completion, the &ital(wormhole ID) is returned; this ID must be passed on all
+subsequent calls to wormhole functions for this connection.
+
+&proto_start
+rmr_mbuf_t* rmr_wh_send_msg( void* vctx, rmr_whid_t whid, rmr_mbuf_t* msg );
+&proto_end
+Once a wormhole has been established to a peer application, this function allows the application
+to send a message to the peer.
+All semantics of normal RMR sends (retries, etc.) are observed.
+The application may opt not to supply the message type or subscription ID in the message as
+neither are used by RMR; they may be required by the peer application depending on the application
+level protocol(s) in use.
+
+
+.** ------------------------------------
+&space
+&h2(Message Buffer Functions)
+The message buffer functions operate directly on a message buffer, and as such do not
+require that RMR context as a parameter.
+&space
+
+&proto_start
+int rmr_bytes2meid( rmr_mbuf_t* mbuf, unsigned char const* src, int len );
+&proto_end
+Copy the bytes referenced by &ital(src) to the &ital(meid) field in the RMR message header.
+Up to &ital(len) bytes are copied, though the maximum length of the field as
+governed by &cw(RMR_MAX_MEID) is enforced.
+
+&proto_start
+void rmr_bytes2payload( rmr_mbuf_t* mbuf, unsigned char const* src, int len );
+&proto_end
+This function copies &ital(len) bytes from &ital(src) into the message buffer payload.
+This function is primarily provided to support wrappers which don't directly support
+C pointers.
+
+
+&proto_start
+int rmr_bytes2xact( rmr_mbuf_t* mbuf, unsigned char const* src, int len );
+&proto_end
+This function copies &ital(len) bytes of data from &ital(src) to the transaction ID
+field in the message buffer.
+The number of bytes provided will be limited to a maximum of &cw(RMR_MAX_XID.)
+
+&proto_start
+void rmr_free_msg( rmr_mbuf_t* mbuf );
+&proto_end
+This function should be used by the application to release the storage used by a message buffer.
+
+&proto_start
+unsigned char* rmr_get_meid( rmr_mbuf_t* mbuf, unsigned char* dest );
+&proto_end
+The bytes from the &cw(meid) field of the message buffer are copied to the &ital(dest) buffer
+provided by the application.
+The full field of &cw(RMR_MAX_MEID) bytes are copied; the caller must ensure that &ital(dest)
+is large enough.
+
+&proto_start
+unsigned char* rmr_get_src( rmr_mbuf_t* mbuf, unsigned char* dest );
+&proto_end
+The source of a message is copied to the &ital(dest) buffer provided by the caller.
+This is generally the hostname and port, separated by a colon, of the application
+which sent the message, and is a zero terminated string.
+Up to &cw(RMR_MAX_SRC) bytes will be copied, so the caller must ensure that &ital(dest)
+is at least this large.
+
+&proto_start
+unsigned char* rmr_get_srcip( rmr_mbuf_t* msg, unsigned char* dest );
+&proto_end
+This function copies the source IP address and port, separated by a colon, to the
+&ital(dest) buffer provided by the caller.
+This is the address of the application which sent the message.
+Up to &cw(RMR_MAX_SRC) bytes will be copied, so the caller must ensure that &ital(dest)
+is at least this large.
+
+&proto_start
+int rmr_get_trlen( rmr_mbuf_t* msg );
+&proto_end
+This function can be used to determine the size of the trace information in the message buffer.
+If no trace data is present, then 0 is returned.
+
+&proto_start
+int rmr_get_trace( rmr_mbuf_t* msg, unsigned char* dest, int size );
+&proto_end
+The bytes from the trace data, up to &tial(size) bytes, is copied from the message buffer
+to the &ital(dest) buffer provided by the caller.
+The return value is the number of bytes actually copied.
+
+&proto_start
+int rmr_payload_size( rmr_mbuf_t* msg );
+&proto_end
+This function returns the number of bytes in the message buffer's payload that are available
+for the application to use.
+
+
+&proto_start
+rmr_mbuf_t* rmr_realloc_msg( rmr_mbuf_t* mbuf, int new_tr_size );
+&proto_end
+This function allows the application to reallocate a message buffer with a different trace
+data size.
+The contents of the message buffer supplied are copied to the new buffer, and a reference to
+the new buffer is returned.
+
+&proto_start
+int rmr_set_trace( rmr_mbuf_t* msg, unsigned const char* data, int size );
+&proto_end
+The &ital(size) bytes, up to the size of the trace data in the message buffer,
+at &ital(data) are copied to the trace portion of the message buffer.
+The return value is the actual number of bytes copied which could be less than the number
+requested.
+
+
+&proto_start
+int rmr_str2meid( rmr_mbuf_t* mbuf, unsigned char const* str );
+&proto_end
+Accepts a pointer to a zero terminated string an copies it to the &cw(meid) field in the
+message header.
+Up to &cw(RMR_MAX_MEID) bytes are copied (including the final 0), and the number
+copied is returned.
+
+&proto_start
+void rmr_str2payload( rmr_mbuf_t* mbuf, unsigned char const* str );
+&proto_end
+Accepts a pointer to a zero terminated string, and copies the string to the payload
+portion of the message buffer.
+If the string is longer than the allocated payload, the string will be truncated
+and will &bold(not) be terminated with a zero byte.
+
+
+&proto_start
+int rmr_str2xact( rmr_mbuf_t* mbuf, unsigned char const* str );
+&proto_end
+Accepts a pointer to a zero terminated string and copies the string to the transaction ID
+portion of the message buffer.
+If the string is longer than &cw(RMR_MAX_XID,) the string will be truncated and will &bold(not)
+be zero terminated.
+
+&proto_start
+void* rmr_trace_ref( rmr_mbuf_t* msg, int* sizeptr );
+&proto_end
+This function returns a pointer to the trace information in the message buffer.
+The intent is that the application will treat this as a read/only field and will not
+write trace data into the message buffer.
+The length of data available should be determined by calling &func(rmr_get_trlen:.)
+
+
+
--- /dev/null
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+&h1(Appendix &code_appendix -- Code Examples)
+The following snippet of code illustrate some of the basic operation of the RMR
+library.
+Please refer to the examples and test directories in the RMR repository for
+complete RMR based programmes.
+
+.im code_send.im
+.im code_rcv.im
+.im code_sr.im
--- /dev/null
+
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+.** example sender code
+
+&h2(Receiver Sample)
+The receiver code is even more simple than the sender code as it does not
+need to wait for a route table to arrive (only senders need to do that), nor
+does it need to allocate an initial buffer.
+The example assumes that the sender is transmitting a zero terminated string
+as the payload.
+
+&space
+
+&indent
+&ex_start
+rmr_mbuf_t* rbuf = NULL;
+void* mrc = rmr_init( listen_port, MAX_BUF_SZ, RMRFL_NOFLAGS );
+
+while( TRUE ) {
+ rbuf = rmr_rcv_msg( mrc, rbuf ); // reuse buffer on all but first loop
+ if( rbuf == NULL || rbuf->state != RMR_OK ) {
+ break;
+ }
+
+ fprintf( stdout, "mtype=%d sid=%d pay=%s\n",
+ rbuf->mtype, rbuf->sub_id, rbuf->payload );
+ sleep( delay_sec );
+}
+
+fprintf( stderr, "receive error\n" );
+rmr_close( mrc );
+
+&ex_end
+&uindent
--- /dev/null
+
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+.** example sender code
+
+&h2(Sender Sample)
+The following code segment shows how a message buffer can be allocated,
+populated, and sent.
+The snippet also illustrates how the result from the &func(rmr_send_msg)
+function is used to send the next message.
+It does not illustrate error and/or retry handling.
+&space
+
+&indent
+&ex_start
+mrc = rmr_init( listen_port, MAX_BUF_SZ, RMRFL_NOFLAGS );
+rmr_set_stimeout( mrc, rmr_retries );
+
+while( ! rmr_ready( mrc ) ) {
+ sleep( 1 );
+}
+
+sbuf = rmr_alloc_msg( mrc, 256 ); // 1st send buffer
+
+while( TRUE ) {
+ sbuf->len = gen_status( (status_msg *) sbuf->payload );
+ sbuf->mtype = STATUS_MSG;
+ sbuf->sub_id = RMR_VOID_SUBID; // subscription not used
+ sbuf = rmr_send_msg( mrc, sbuf );
+
+ sleep( delay_sec );
+}
+
+rmr_close( mrc );
+
+&ex_end
+&uindent
--- /dev/null
+
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+.** example sender code
+
+&h2(Receive and Send Sample)
+The following code snippet receives messages and responds to the sender
+if the message type is odd.
+The code illustrates how the received message may be used to return
+a message to the source.
+Variable type definitions are omitted for clarity and should be obvious.
+
+&space
+It should also be noted that
+things like the message type which id returned to the sender (99) is
+a random value that these applications would have agreed on in advance
+and is &bold(not) an RMR definition.
+
+&space
+
+&indent
+&ex_start
+mrc = rmr_init( listen_port, MAX_BUF_SZ, RMRFL_NOFLAGS );
+rmr_set_stimeout( mrc, 1 ); // allow RMR to retry failed sends for ~1ms
+
+while( ! rmr_ready( mrc ) ) { // we send, therefore we need a route table
+ sleep( 1 );
+}
+
+mbuf = NULL; // ensure our buffer pointer is nil for 1st call
+
+while( TRUE ) {
+ mbuf = rmr_rcv_msg( mrc, mbuf ); // wait for message
+
+ if( mbuf == NULL || mbuf->state != RMR_OK ) {
+ break;
+ }
+
+ if( mbuf->mtype % 2 ) { // respond to odd message types
+ plen = rmr_payload_size( mbuf ); // max size
+
+ // reset necessary fields in msg
+ mbuf->mtype = 99; // response type
+ mbuf->sub_id = RMR_VOID_SUBID; // we turn subid off
+ mbuf->len = snprintf( mbuf->payload, plen, "pong: %s", get_info() );
+
+ mbuf = rmr_rts_msg( mrc, mbuf ); // return to sender
+ if( mbuf == NULL || mbuf->state != RMR_OK ) {
+ fprintf( stderr, "return to sender failed\n" );
+ }
+ }
+}
+
+fprintf( stderr, "abort: receive failure\n" );
+rmr_close( mrc );
+
+&ex_end
+&uindent
--- /dev/null
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+.if false
+ Mnemonic: config.im
+ Abstract: Major section discussing for configuration.
+ Date: 2 August 2019
+ Author: E. Scott Daniels
+.fi
+
+&h1(Configuration and Control)
+With the assumption that most RMR based applications will be executed in a containerised
+environment, there are some underlying mechanics which the developer may need to know
+in order to properly provide a configuration specification to the container management
+system.
+The following paragraphs briefly discuss these.
+
+.sp .1
+&h2(TCP Ports)
+RMR requires two (2) TCP listen ports: one for general application to application communications
+and one for route table updates.
+The general communication port is specified by the application at the time RMR is initialised.
+The port used to listen for route table updates is likely to be a constant port shared by all
+applications provided they are running in separate containers.
+To that end, the port number defaults to 4561, but can be configured with an environment variable
+(see later paragraph in this section).
+
+
+&h2(Host Names)
+RMR is typically host name agnostic.
+Route table entries may contain endpoints defined either by host name or IP address.
+In the container world the concept of a &ital(service name) might exist, and likely is different
+than a host name.
+RMR's only requirement with respect to host names is that a name used on a route table entry must
+be resolvable via the &cw(gethostbyname) system call.
+
+
+&h2(Environment Variables)
+Several environment variables are recognised by RMR which,
+in general, are used to define interfaces and listen ports (e.g. the route table update
+listen port), or debugging information.
+Generally this information is system controlled and thus RMR expects this information to
+be defined in the environment rather than provided by the application.
+The following is a list of the environment variables which RMR recognises:
+
+&half_space
+.st 8p
+&indent
+&beg_dlist( 1.25i &ditext )
+ &di(RMR_BIND_IF) The interface to bind to listen ports to. If not defined 0.0.0.0 (all interfaces) is assumed.
+ &half_space
+
+ &di(RMR_RTG_SVC) The port RMR will listen on for route manager connections. If not defined 4561 is used.
+ &half_space
+
+ &di(RMR_SEED_RT) Where RMR expects to find the name of the seed (static) route table. If not defined no static table is read.
+ &half_space
+
+ &di(RMR_RTG_ISRAW) If the value set to 0, RMR expects the route table manager messages to be messages with and RMR header.
+ If this is not defined messages are assumed to be "raw" (without an RMR header.
+ &half_space
+
+ &di(RMR_VCTL_FILE) Provides a file which is used to set the verbose level of the route table collection thread.
+ The first line of the file is read and expected to contain an integer value to set the verbose level.
+ The value may be changed at any time and the route table thread will adjust accordingly.
+ &half_space
+
+ &di(RMR_SRC_NAMEONLY) If the value of this variable is greater than 0, RMR will not permit the IP address to be
+ sent as the message source. Only the host name will be sent as the source in the message header.
+&end_dlist
+&uindent
+.st &textsize
+&space
+
+&h2(Logging)
+RMR does &bold(not) use any logging libraries; any error or warning messages are written to standard error.
+.if false
+ ¬e .sm .
+.cn l=&cn_line_len i=0 start &atbot Times-roman 8p .7i
+ This is standard practice for container based applications as it makes error output easily available to operations.
+.cn end
+.fi
+RMR messages are written with one of three prefix strings:
+
+
+&half_space
+&indent
+&beg_dlist( .6i &ditext )
+ &di(^[CRI]) The event is of a critical nature and it is unlikely that RMR will continue to operate correctly if at all.
+ It is almost certain that immediate action will be needed to resolve the issue.
+ &half_space
+
+ &di(^[ERR]) The event is not expected and RMR is not able to handle it. There is a small chance that continued operation
+ will be negatively impacted.
+ Eventual action to diagnose and correct the issue will be necessary.
+ &half_space
+
+ &di(^[WRN]) The event was not expected by RMR, but can be worked round. Normal operation will continue, but it is recommended
+ that the cause of the problem be investigated.
+&end_dlist
+&space
+&uindent
--- /dev/null
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+.if false
+ Mnemonic: failures.im
+ Abstract: This is the major section on how an application might handle failures
+ Date: 2 August 2019
+ Author: E. Scott Daniels
+.fi
+
+&h1(Handling Failures)
+The vast majority of states reported by RMR are fatal; if encountered during setup or initialisation,
+then it is unlikely that any message oriented processing should continue, and when encountered on
+a message operation continued operation on that message should be abandoned.
+Specifically with regard to message sending, it is very likely that the underlying transport mechanism
+will report a &ital(soft,) or transient, failure which might be successful if the operation is retried at a
+later point in time.
+The paragraphs below discuss the methods that an application might deal with these soft failures.
+
+&h2(Failure Notification)
+When a soft failure is reported, the returned message buffer returned by the RMR function will be &cw(RMR_ERR_RETRY.)
+These types of failures can occur for various reasons; one of two reasons is typically the underlying cause:
+
+&half_space
+&indent
+&beg_list( &lic1 )
+ &li The session to the targeted recipient (endpoint) is not connected.
+ &half_space
+
+ &li The transport mechanism buffer pool is full and cannot accept another buffer.
+ &half_space
+&end_list
+&uindent
+&space
+
+Unfortunately, it is not possible for RMR to determine which of these two cases is occurring, and equally
+as unfortunate the time to resolve each is different.
+The first, no connection, may require up to a second before a message can be accepted, while a rejection
+because of buffer shortage is likely to resolve in less than a millisecond.
+
+&h2(Application Response)
+The action which an application takes when a soft failure is reported ultimately depends on the nature
+of the application with respect to factors such as tolerance to extended message latency, dropped messages,
+and over all message rate.
+
+&h2(RMR Retry Modes)
+In an effort to reduce the workload of an application developer, RMR has a default retry policy such that
+RMR will attempt to retransmit a message up to 1000 times when a soft failure is reported.
+These retries generally take less than 1 millisecond (if all 1000 are attempted) and in most cases eliminates
+nearly all reported soft failures to the application.
+When using this mode, it might allow the application to simply treat all bad return values from a send attempt
+as permanent failures.
+&space
+
+If an application is so sensitive to any delay in RMR, or the underlying transport mechanism, it is possible to
+set RMR to return a failure immediately on any kind of error (permanent failures are always reported without retry).
+In this mode, RMR will still set the state in the message buffer to &cw(RMR_ERR_RETRY,) but will &bold(not)
+make any attempts to resend the message.
+This zero-retry policy is enabled by invoking the &func(rmr_set_stimeout) with a value of 0; this can be done once
+immediately after &func(rmr_init:) is invoked.
+
+&space
+Regardless of the retry mode which the application sets, it will ultimately be up to the application to
+handle failures by queuing the message internally for resend, retrying immediately, or dropping the
+send attempt all together.
+As stated before, only the application can determine how to best handle send failures.
+
+
+&h2(Other Failures)
+RMR will return the state of processing for message based operations (send/receive) as the status in
+the message buffer.
+For non-message operations, state is returned to the caller as the integer return value for all functions
+which are not expected to return a pointer (e.g. &func(rmr_init:).)
+The following are the RMR state constants and a brief description of their meaning.
+
+&space
+.st 8p
+&indent
+&beg_dlist( 1.5i &ditext )
+ &di(RMR_OK) state is good; operation finished successfully
+ &half_space
+
+ &di(RMR_ERR_BADARG) argument passed to function was unusable
+ &half_space
+
+ &di(RMR_ERR_NOENDPT) send/call could not find an endpoint based on msg type
+ &half_space
+
+ &di(RMR_ERR_EMPTY) msg received had no payload; attempt to send an empty message
+ &half_space
+
+ &di(RMR_ERR_NOHDR) message didn't contain a valid header
+ &half_space
+
+ &di(RMR_ERR_SENDFAILED) send failed; errno may contain the transport provider reason
+ &half_space
+
+ &di(RMR_ERR_CALLFAILED) unable to send the message for a call function; errno may contain the transport provider reason
+ &half_space
+
+ &di(RMR_ERR_NOWHOPEN) no wormholes are open
+ &half_space
+
+ &di(RMR_ERR_WHID) the wormhole id provided was invalid
+ &half_space
+
+ &di(RMR_ERR_OVERFLOW) operation would have busted through a buffer/field size
+ &half_space
+
+ &di(RMR_ERR_RETRY) request (send/call/rts) failed, but caller should retry (EAGAIN for wrappers)
+ &half_space
+
+ &di(RMR_ERR_RCVFAILED) receive failed (hard error)
+ &half_space
+
+ &di(RMR_ERR_TIMEOUT) response message not received in a reasonable amount of time
+ &half_space
+
+ &di(RMR_ERR_UNSET) the message hasn't been populated with a transport buffer
+ &half_space
+
+ &di(RMR_ERR_TRUNC) length in the received buffer is longer than the size of the allocated payload,
+ received message likely truncated (length set by sender could be wrong, but we can't know that)
+ &half_space
+
+ &di(RMR_ERR_INITFAILED) initialisation of something (probably message) failed
+ &half_space
+
+ &di(RMR_ERR_NOTSUPP) the request is not supported, or RMr was not initialised for the request
+&end_dlist
+&uindent
+.st &textsize
+&space
+
+Depending on the underlying transport mechanism, and the nature of the call that RMR attempted, the
+system &cw(errno) value might reflect additional detail about the failure.
+Applications should &bold(not) rely on errno as some transport mechanisms do not set it with
+any consistency.
--- /dev/null
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+.if false
+ Title page, toc and license for page oriented output
+.fi
+
+.sp 20
+.st 24
+.bc start
+&doc_title
+.br
+&doc_subtitle
+.bc end
+.st &textsize
+
+.sp 25
+Original: 30 July 2019 .br
+.gv Date
+Revised: &_date
+.pa
+
+
+.im license.im
+.pa
+
+.if &pass 1 =
+ .tc on
+.ei
+ .tc off
+ .pn on noline center roman 0
+
+ .im user.toc .** initial page eject inside
+ .pa
+.fi
+
+.** ensure this is restored after toc spits
+.cd 1 6.0i
--- /dev/null
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+.if false
+ Mnemonic: general_use.im
+ Abstract: Major section -- Describes the general use of RMR.
+ Date: 1 August 2019
+ Author: E. Scott Daniels
+.fi
+
+&h1(General Use)
+To use, the RMR based application simply needs to initialise the RMR environment, wait for RMR to
+have received a routing table (become ready), and then invoke either the send or receive functions.
+These steps, and some behind the scenes details, are described in the following paragraphs.
+
+&h2(Initialisation)
+The RMR function &func(rmr_init:) is used to set up the RMR environment and must be called before messages
+can be sent or received.
+One of the few parameters that the application must communicate to RMR is the port number that will be
+used as the listen port for new connections.
+The port number is passed on the initialisation function call and a TCP listen socket will be opened
+with this port.
+If the port is already in use RMR will report a failure; the application will need to reinitialise with
+a different port number, abort, or take some other action appropriate for the application.
+.sp
+In addition to creating a TCP listen port, RMR will start a process thread which will be responsible for
+receiving dynamic updates to the route table.
+This thread also causes a TCP listen port to be opened as it is expected that the process which generates
+route table updates will connect and send new information when needed.
+The route table update port is &bold(not) supplied by the application, but is supplied via an environment
+variable as this value is likely determined by the mechanism which is starting and configuring the application.
+
+&h3(The RMR Context)
+On successful initialisation, a void pointer, often called a &ital(handle) by some programming languages,
+is returned to the application. This is a reference to the RMR control information and must be passed as the
+first parameter on most RMR functions calls.
+RMR refers to this as the context, or ctx.
+
+&h2(Wait For Ready)
+An application which is only receiving messages does not need to wait for RMR to &ital(become ready) after
+the call to the initialisation function.
+However, before the application can successfully send a message, RMR must have loaded a route table, and
+the application must wait for RMR to report that it has done so.
+The RMR function &func(rmr_ready:) will return the value &ital(true) (1) when a complete route table has
+been loaded and can be used to determine the endpoint for a send request.
+
+&h2(Receiving Messages)
+The process of receiving is fairly straight forward.
+The application invokes the RMR &func(rmr_rcv_msg:) function which will block until a message is received.
+The function returns a pointer to a message block which provides all of the details about the message.
+Specifically, the application has access to the following information either directly or indirectly:
+
+&half_space
+&indent
+&beg_list( &lic1 )
+ &li The payload (actual data)
+ &half_space
+ &li The total payload length in bytes
+ &half_space
+ &li The number of bytes of the payload which contain valid data
+ &half_space
+ &li The message type and subscription ID values
+ &half_space
+ &li The hostname and IP address of the source of the message (the sender)
+ &half_space
+ &li The transaction ID
+ &half_space
+ &li Tracing data (if provided)
+&end_list
+&uindent
+&space
+
+&h3(The Message Payload)
+The message payload contains the &ital(raw) data that was sent by the peer application.
+The format will likely depend on the message type, and is expected to be known by the application.
+A direct pointer to the payload is available from the message buffer (see appendix &mbuf_appendix
+for specific message buffer details).
+
+&space
+Two payload related length values are also directly available: the total payload length, and the number of bytes
+actually filled with data.
+The used length is set by the caller, and may or not be an accurate value.
+The total payload length is determined when the buffer is created for sending, and is the maximum
+number of bytes that the application may modify should the buffer be used to return a response.
+
+&h3(Message Type and Subscription ID)
+The message type and subscription ID are both directly available from the message buffer, and
+are the values which were used to by RMR in the sending application to select the endpoint.
+If the application resends the message, as opposed to returning the message buffer as a response,
+the message number and/or the subscription ID might need to be changed to avoid potential issues ¬e .sm .
+.cn l=&cn_line_len i=&cn_ident start &atbot Times-roman 8p 1i
+ It is entirely possible to design a routing table, and application group, such that the same message type is
+ is left unchanged and the message is forwarded by an application after updating the payload. This type
+ of behaviour is often referred to as service chaining, and can be done without any "knowledge" by
+ an application with respect to where the message goes next. Service chaining is supported by RMR
+ in as much as it allows the message to be resent, but the actual complexities of designing
+ and implementing service chaining lie with the route table generator process.
+.cn end
+
+&h3(Sender Information)
+The source, or sender information, is indirectly available to the application via the &func(rmr_get_src:) and
+&func(rmr_get_ip:) functions.
+The former returns a string containing &cw(hostname^:port,) while the string &cw(ip^:port) is returned
+by the latter.
+
+&h3(Transaction ID)
+The message buffer contains a fixed length set of bytes which applications can set to track related messages
+across the application concept of a transaction.
+RMR will use the transaction ID for matching a response message when the &func(rmr_call:) function is used to
+send a message.
+
+&h3(Trace Information)
+RMR supports the addition of an optional trace information to any message.
+The presence and size is controlled by the application, and can vary from message to message if desired.
+The actual contents of the trace information is determined by the application; RMR provides only the means to
+set, extract, and obtain a direct reference to the trace bytes.
+The trace data field in a message buffer is discussed in greater detail in the &ital(Trace Data) section.
+
+&h2(Sending Messages)
+Sending requires only slightly more work on the part of the application than receiving a message.
+The application must allocate an RMR message buffer, populate the message payload with data, set the
+message type and length, and optionally set the subscription ID.
+Information such as the source IP address, hostname, and port are automatically added to the message buffer
+by RMR, so there is no need for the application to worry about these.
+
+
+&h3(Message Buffer Allocation)
+The function &func(rmr_msg_alloc:) allocates a &ital(zero copy) buffer and returns a pointer to the RMR
+&cw(rmr_mbuf_t) structure.
+The message buffer provides direct access to the payload, length, message type and subscription ID fields.
+The buffer must be preallocated in order to allow the underlying transport mechanism to allocate the payload
+space from it's internal memory pool; this eliminates multiple copies as the message is sent, and thus is
+more efficient.
+
+.sp
+If a message buffer has been received, and the application wishes to use the buffer to send a response, or
+to forward the buffer to another application, a new buffer does &bold(not) need to be allocated.
+The application may set the necessary information (message type, etc.), and adjust the payload, as is
+necessary and then pass the message buffer to &func(rmr_send_msg:) or &func(rmr_rts_msg:) to be sent or
+returned to the sender.
+
+&h3(Populating the Message Buffer)
+The application has direct access to several of the message buffer fields, and should set them appropriately.
+&half_space
+&indent
+&beg_dlist( 1i &ditext )
+ &di(len) This is the number of bytes that the application placed into the payload. Setting length to 0 is
+ allowed, and length may be less than the allocated payload size.
+
+ &half_space
+ &di(mtype) The message type that RMR will use to determine the endpoint used as the target of the send.
+
+ &half_space
+ &di(sub_id) The subscription ID if the message is to be routed based on the combination of message type and subscription ID.
+ If no subscription ID is valid for the message, the application should set the field with the
+ RMR constant &cw(RMR_VOID_SUBID.)
+
+ &half_space
+ &di(payload) The application should obtain the reference (pointer) to the payload from the message buffer
+ and place any data into the payload. The application is responsible for ensuring that the
+ maximum payload size is not exceeded. The application may obtain the maximum size via the &func(rmr_payload_size:)
+ function.
+
+ &half_space
+ &di(trace data) Optionally, the application may add trace information to the message buffer.
+
+&end_dlist
+&space
+&uindent
+
+&h3(Sending a Message Buffer)
+Once the application has populated the necessary bits of a message, it may be sent by passing the buffer to
+the &func(rmr_send_msg:) function.
+This function will select an endpoint to receive the message, based on message type and subscription ID, and
+will pass the message to the underlying transport mechanism for actual transmission on the connection.
+(Depending on the underlying transport mechanism, the actual connection to the endpoint may happen at the time of
+the first message sent to the endpoint, and thus the latency of the first send might be longer than expected.)
+
+&space
+On success, the send function will return a reference to a message buffer; the status within that message
+buffer will indicate what the message buffer contains.
+When the status is &cw(RMR_OK) the reference is to a &bold(new) message buffer for the application to use for the next
+send; the payload size is the same as the payload size allocated for the message that was just sent.
+This is a convenience as it eliminates the need for the application to call the message allocation function
+at some point in the future, and assumes the application will send many messages which will require the same
+payload dimensions.
+
+&space
+If the message contains any status other than &cw(RMR_OK,) then the message could &bold(not) be sent, and the
+reference is to the unsent message buffer.
+The value of the status will indicate whether the nature of the failure was transient ( .sm &cw(RMR_ERR_RETRY) .sm )
+or not.
+Transient failures are likely to be successful if the application attempts to send the message at a later time.
+Unfortunately, it is impossible for RMR to know the exact transient failure (e.g. connection being established, or
+TCP buffer shortage), and thus it is not possible to communicate how long the application should wait before
+attempting to resend, if the application wishes to resend the message.
+(More discussion with respect to message retries can be found in the &ital(Handling Failures) section.)
+
+
--- /dev/null
+
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+
+.dv term ^&half_space ^&di($1)
+.ix pause
+
+&h1(Appendix &gloss_appendix -- Glossary)
+
+Many terms in networking can be interpreted with multiple meanings, and several terms used
+in this document are RMR specific.
+The following definitions are the meanings of terms used within this document and should
+help the reader to understand the intent of meaning.
+
+&beg_dlist( &1.0i Helvetica-bold )
+&term(application) A programme which uses RMR to send and/or receive messages to/from another RMR based application.
+
+&term(Critical error) An error that RMR has encountered which will prevent further successful processing by
+ RMR. Critical errors usually indicate that the application should abort.
+
+&term(Endpoint) An RMR based application that is defined as being capable of receiving one or more types of messages
+ (as defined by a &ital(message key.) .sm )
+
+&term(Environment variable) A key/value pair which is set externally to the application, but which is available
+ to the application (and referenced libraries) through the &cw(getenv) system call. Environment variables
+ are the main method of communicating information such as port numbers to RMR.
+
+&term(Error) An abnormal condition that RMR has encountered, but will not affect the overall processing by RMR,
+ but may impact certain aspects such as the ability to communicate with a specific endpoint.
+ Errors generally indicate that something, usually external to RMR, must be addressed.
+
+&term(Host name) The name of the host as returned by the &cw(gethostbyname) system call. In a containerised
+ environment this might be the container or service name depending on how the container is started.
+ From RMR's point of view, a host name can be used to resolve an &ital(endpoint) definition in
+ a &ital(route table.)
+
+&term(IP) Internet protocol. A low level transmission protocol which governs the transmission of datagrams
+ across network boundaries.
+
+&term(Listen socket) A &ital(TCP) socket used to await incoming connection requests. Listen sockets are defined
+ by an interface and port number combination where the port number is unique for the interface.
+
+&term(Message) A series of bytes transmitted from the application to another RMR based application. A message
+ is comprised of RMR specific data (a header), and application data (a payload).
+
+&term(Message buffer) A data structure used to describe a message which is to be sent or has been received.
+ The message buffer includes the payload length, message type, message source, and other information.
+
+&term(Messgae type) A signed integer (0-32000) which identifies the type of message being transmitted, and is
+ one of the two components of a &ital(routing key.) See &ital(Subscription ID.)
+
+&term(Payload) The portion of a message which holds the user data to be transmitted to the remote &ital(endpoint.)
+ The payload contents are completely application defined.
+
+&term(RMR context) A set of information which defines the current state of the underlying transport connections that
+ RMR is managing. The application will be give a context reference (pointer) that is supplied to most
+ RMR functions as the first parameter.
+
+&term(Round robin) The method of selecting an &ital(endpoint) from a list such that all &ital(endpoints) are selected
+ before starting at the head of the list.
+
+&term(Route table) A series of "rules" which define the possible &ital(endpoints) for each &ital(message key.)
+
+&term(Route table manager) An application responsible for building a &ital(route table) and then distributing it to
+ all applicable RMR based applications.
+
+&term(Routing) The process of selecting an &ital(endpoint) which will be the recipient of a message.
+
+&term(Routing key) A combination of &ital(message type) and &ital(subscription ID) which RMR uses to select the
+ destination &ital(endpoint) when sending a message.
+
+&term(Source) The sender of a message.
+
+
+&term(Subscription ID) A signed integer value (0-32000) which identifies the subscription characteristic of a message.
+ It is used in conjunction with the &ital(message type) to determine the &ital(routing key.)
+
+&term(Target) The &ital(endpoint) selected to receive a message.
+
+&term(TCP) Transmission Control Protocol. A connection based internet protocol which provides for
+ lossless packet transportation, usually over IP.
+
+&term(Thread) Also called a &ital(process thread, or pthread.) This is a lightweight process which executes in concurrently with
+ the application and shares the same address space.
+ RMR uses threads to manage asynchronous functions such as route table updates.
+
+&Term(Trace information) An optional portion of the message buffer that the application may populate with data
+ that allows for tracing the progress of the transaction or application activity across components.
+ RMR makes no use of this data.
+
+&term(Transaction ID) A fixed number of bytes in the &ital(message buffer) which the application may populate with
+ information related to the transaction. RMR makes use of the transaction ID for matching response messages
+ with the &c(rmr_call) function is used to send a message.
+
+&term(Transient failure) An error state that is believed to be short lived and that the operation, if retried by the
+ application, might be successful. C programmers will recognise this as &cw(EAGAIN.)
+
+&term(Warning) A warning occurs when RMR has encountered something that it believes isn't correct, but has a defined
+ work round.
+
+&term(Wormhole) A direct connection managed by RMR between the user application and a remote, RMR based, application.
+&end_dlist
+
+.ix resume
+
--- /dev/null
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+.if false
+ Mnemonic: index_snarf.im
+ Abstract: Define all terms/synonyms whch {X}fm will yank and reference when
+ it builds the index (pfm only).
+ Date: 31 July 2019
+ Author: E. Scott Daniels
+.fi
+
+
+.if pfm
+.** ensure that index collection is going
+.ix resume
+
+.ix snare context
+.ix synonym context ctx
+
+.ix snare endpoint
+
+.ix snare `message type`
+.ix synonym `message type` MT/SID
+.ix synonym `message type` `message type,`
+
+.ix snare nanomsg
+.ix synonym nanomsg Nanomsg
+.ix snare NNG
+.ix snare payload
+
+.ix snare `round robin`
+.ix synonym `round robin` round-robin
+.ix snare `route table`
+
+.ix snare `subscription ID`
+.ix synonym `subscription ID` `subscription ID,`
+.ix synonym `subscription ID` `subID`
+
+.ix snare `transaction ID`
+.ix snare `trace data`
+
+.ix snare boo
+
+.** ---- functions --------
+.ix snare rmr_call
+.ix snare rmr_init
+.ix snare rmr_get_ip
+.ix snare rmr_get_src
+.ix snare rmr_ready
+.ix snare rmr_rcv_msg
+.ix snare rmr_rts_msg
+.ix snare rmr_send_msg
+.ix snare rmr_init_trace
+.ix snare rmr_wh_open
+.ix snare rmr_wh_close
+.ix snare rmr_wh_send_msg
+
+.** ----- environment variables -----
+.ix snare RMR_BIND_IF
+.ix snare RMR_RTG_SVC
+.ix snare RMR_SEED_RT
+.ix snare RMR_RTG_ISRAW
+.ix snare RMR_VCTL_FILE
+.ix snare RMR_SRC_NAMEONLY
+
+.** ----- errors -------------------
+.if false
+.ix snare RMR_OK
+.ix snare RMR_ERR_BADARG
+.ix snare RMR_ERR_NOENDPT
+.ix snare RMR_ERR_EMPTY
+.ix snare RMR_ERR_NOHDR
+.ix snare RMR_ERR_SENDFAILED
+.ix snare RMR_ERR_CALLFAILED
+.ix snare RMR_ERR_NOWHOPEN
+.ix snare RMR_ERR_WHID
+.ix snare RMR_ERR_OVERFLOW
+.ix snare RMR_ERR_RETRY
+.ix snare RMR_ERR_RCVFAILED
+.ix snare RMR_ERR_TIMEOUT
+.ix snare RMR_ERR_UNSET
+.ix snare RMR_ERR_TRUNC
+.ix snare RMR_ERR_NOTSUPP
+.fi
+
+.ix snare OK
+.ix synonym OK RMR_OK
+.ix snare BADARG
+.ix synonym BADARG RMR_ERR_BADARG
+.ix snare NOENDPT
+.ix synonym NOENDPT RMR_ERR_NOENDPT
+.ix snare EMPTY
+.ix synonym EMPTY RMR_ERR_EMPTY
+.ix snare NOHDR
+.ix synonym NOHDR RMR_ERR_NOHDR
+.ix snare SENDFAILED
+.ix synonym SENDFAILED RMR_ERR_SENDFAILED
+.ix snare CALLFAILED
+.ix synonym CALLFAILED RMR_ERR_CALLFAILED
+.ix snare NOWHOPEN
+.ix synonym NOWHOPEN RMR_ERR_NOWHOPEN
+.ix snare WHID
+.ix synonym WHID RMR_ERR_WHID
+.ix snare OVERFLOW
+.ix synonym OVERFLOW RMR_ERR_OVERFLOW
+.ix snare RETRY
+.ix synonym RETRY RMR_ERR_RETRY
+.ix snare RCVFAILED
+.ix synonym RCVFAILED RMR_ERR_RCVFAILED
+.ix snare TIMEOUT
+.ix synonym TIMEOUT RMR_ERR_TIMEOUT
+.ix snare UNSET
+.ix synonym UNSET RMR_ERR_UNSET
+.ix snare TRUNC
+.ix synonym TRUNC RMR_ERR_TRUNC
+.ix snare NOTSUPP
+.ix synonym NOTSUPP RMR_ERR_NOTSUPP
+
+
+
+.** ------------ groups ------------------------------------------------
+.** order listed on the group is order displayed in the index under the group heading.
+.** labels with no references in the doc are omitted, so safe to add all values
+
+.ix group Functions rmr_call rmr_get_ip rmr_get_src rmr_init rmr_init_trace rmr_rcv_msg rmr_ready rmr_rts_msg rmr_send_msg rmr_wh_close rmr_wh_open rmr_wh_send_msg
+
+.ix group `Env Variables` RMR_BIND_IF RMR_RTG_SVC RMR_RTG_ISRAW RMR_SEED_RT RMR_SRC_NAMEONLY RMR_VCTL_FILE
+
+.ix group `Errors (RMR_ERR_*)` OK BADARG CALLFAILED EMPTY NOENDPT NOHDR NOTSUPP NOWHOPEN OVERFLOW SENDFAILED RETRY RCVFAILED TIMEOUT TRUNC UNSET WHID
+
+.** .ix group Tables `end table` `start table` `table cell` `table row` `table header`
+.fi
+
+
--- /dev/null
+
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+
+.** this file is imbedded after the cover page for Postscript generated
+.** documents, and at the top for text based documents. It's purpose is
+.** to ensure the output doc has the license statement.
+
+.if pfm
+.sp 5
+.fi
+
+This document, and the source used to generate it, is governed by the following
+copyright statement(s).
+
+.sp 2
+.ln
+.nf
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+.fo
+.ln
+.sp 2
--- /dev/null
+
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+&h1(Appendix &mbuf_appendix -- Message Buffer Details)
+
+The RMR message buffer is a C structure which is exposed in the &cw(rmr.h)
+header file.
+It is used to manage a message received from a peer endpoint, or a message
+that is being sent to a peer.
+Fields include payload length, amount of payload actually used, status,
+and a reference to the payload.
+There are also fields which the application should ignore, and could be
+hidden in the header file, but we chose not to. These fields include
+a reference to the RMR header information, and to the underlying transport
+mechanism message struct which may or may not be the same as the RMR
+header reference.
+
+&h2(The Structure)
+The following is the C structure.
+Readers are cautioned to examine the header file directly; the information
+here may be out of date (old document in some cache), and thus it may
+be incorrect.
+
+&space
+&indent
+&ex_start
+
+typedef struct {
+ int state; // state of processing
+ int mtype; // message type
+ int len; // length of data in the payload (send or received)
+ unsigned char* payload; // transported data
+ unsigned char* xaction; // pointer to fixed length transaction id bytes
+ int sub_id; // subscription id
+ int tp_state; // transport state (errno)
+
+ // these things are off limits to the user application
+ void* tp_buf; // underlying transport allocated pointer (e.g. nng message)
+ void* header; // internal message header (whole buffer: header+payload)
+ unsigned char* id; // if we need an ID in the message separate from the xaction id
+ int flags; // various MFL_ (private) flags as needed
+ int alloc_len; // the length of the allocated space (hdr+payload)
+} rmr_mbuf_t;
+&ex_end
+&uindent
+&space
+
+&h2(State vs Transport State)
+The state field reflects the state at the time the message buffer is returned to the
+calling applicaiton.
+For a send operation, if the state is not &cw(RMR_OK) then the message buffer references
+the payload that could not be sent, and when the state is &cw(RMR_OK) the buffer
+references a &ital(fresh) payload that the application may fill in.
+
+&space
+When the state is not &cw(RMR_OK,) C programmes may examine the global &cw(errno) value
+which RMR will have left set, if it was set, by the underlying transport mechanism.
+In some cases, wrapper modules are not able to directly access the C-library &cw(errno)
+value, and to assist with possible transport error details, the send and receive
+operations populate &cw(tp_state) with the value of &cw(errno.)
+
+&space
+Regardless of whether the application makes use of the &cw(tp_state,) or the &cw(errno)
+value, it should be noted that the underlying transport mechanism may not actually update
+the errno value; in other words: it might not be accurate.
+In addition, RMR populates the &cw(tp_state) value in the message buffer &bold(only) when
+the state is not &cw(RMR_OK.)
+
+&h2(Field References)
+The transaction field was exposed in the first version of RMR, and in hindsight this
+shouldn't have been done.
+Rather than break any existing code the reference was left, but additional fields
+such as trace data, were not directly exposed to the application.
+The application developer is strongly encouraged to use the functions which get and
+set the transaction ID rather than using the pointer directly; any data overruns will
+not be detected if the reference is used directly.
+
+&space
+In contrast, the payload reference should be used directly by the application in the
+interest of speed and ease of programming.
+The same care to prevent writing more bytes to the payload buffer than it can hold
+must be taken by the application.
+By the nature of the allocation of the payload in transport space, RMR is unable to
+add guard bytes and/or test for data overrun.
+
+&h2(Actual Transmission)
+When RMR sends the application's message, the message buffer is &bold(not) transmitted.
+The transport buffer (tp_buf) which contains the RMR header and application payload
+is the only set of bytes which are transmitted.
+While it may seem to the caller like the function &func(rmr_send_msg) is returning a
+new message buffer, the same struct is reused and only a new transport buffer is allocated.
+The intent is to keep the alloc/free cycles to a minimum.
--- /dev/null
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+.if false
+ Mnemonic: setup.im
+ Abstract: Look at environment variables and pull in the correct setup prep
+ imbed file based on the desired output type (when running tfm).
+ Obviously, when running pfm we are always generating postscript
+ so this isn't really doing much.
+ Date: 29 July 2019
+.fi
+
+
+.gv e LIB lib
+.if ! lib
+ .dv lib ..
+.fi
+
+.** CAUTION: xfm comparisons are reverse polish so "a b =" is true if a == b.
+.if pfm
+ .im &{lib}/generic_ps.im
+.ei
+ .gv e OUTPUT_TYPE ot
+
+ .if "&ot" "txt" =
+ .im &{lib}/txt.im
+ .fi
+ .if "&ot" "rst" =
+ .im &{lib}/rst.im
+ .fi
+ .if "&ot" "markdown" =
+ .im &{lib}/markdown.im
+ .fi
+ .if "&ot" "troff" =
+ .im &{lib}/roff.im
+ .fi
+.fi
+
+.** set up for an index when using pfm and snare file is defined
+.if pfm
+ .if index_snare_file
+ .ix space .sp 1 .cc 5 %c .ln ^: .sp 0
+ .ix term .br %s `^` ^`` %d
+ .ix groupb .sp .5 %s .br .ll -.25i .in +.25i
+ .ix groupe .sp .1 .in -.25i .ll +.25i
+ .if ! index_cols
+ .dv index_cols 2
+ .fi
+
+ .dv index_col_width [ 6.5 &index_cols / .25 &index_cols 1 - * - ]
+ .dv index_here .pa .ju off .st &textsize .cd 1 i=1i w=7 ^: .h1 INDEX ^: .pn off .lw 0 .sp 0 .tt ^: .cd &index_cols i=1i w=&{index_col_width}i g=.25i ^: .in -i .ll &{index_col_width}i .ix insert
+ .im &index_snare_file
+ .fi
+.fi
+
+
--- /dev/null
+.if false
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+.fi
+
+.if false
+ Mnemonic: user.xfm
+ Abstract: This is the main module for the base RMR user documentation.
+ Date: 30 July 2019
+ Author: E. Scott Daniels
+.fi
+
+.** setup will do the right thing with the index configuration
+.dv index_snare_file index_snatch.im
+.im ./setup.im
+
+.** func is a bit odd; if punct needs to be added, it must be supplied as the second
+.** parm because we add () to the first. E.g. &func(foo_bar:.) will add a parm
+.**
+.dv func .ix force ${1} ^: ^&cw(${1}()$2 )
+
+.dv mtsid message type and subscription ID
+.dv Mtsid Message type and subscription ID
+.dv mt message type
+.dv Mt Message type
+.dv mts message types
+
+.dv textfont Helvetica
+.dv textsize 10p
+.hn off
+
+
+.gv e XFM_PASS pass
+.if &pass 2 =
+ .** two pass mode -- pull in variables captured during pass 1 for forward references
+ .im p1var_setup.ca
+.fi
+
+.** vars picked up by front_junk as it's a generic module
+.dv doc_title RIC Message Router -- RMR
+.dv doc_subtitle User's Manual
+
+.if pfm
+ .** add licence, a title page, and talbe of contents
+ .im front_junk.im
+.ei
+ .** for text based things, nothing more than license
+ .im license.im
+.fi
+
+.if pfm
+ .pn on noline center f=%d 0
+.fi
+
+&mult_space( 5 )
+.st 18
+¢er_start
+.sf &bold_font
+&doc_title
+.br
+.st 12
+&doc_subtitle
+¢er_end
+.sf &textfont
+&mult_space( 2 )
+.st &textsize
+
+&h1(Overview)
+The RIC Message Router (a.k.a. RMR) is a thin library which provides a latency sensitive application with the ability
+to send and receive messages with other RMR based applications.
+The library provides the following major features:
+
+&half_space
+&indent
+&beg_list( &lic1 )
+ &li Routing and endpoint selection is based on &ital(message type.)
+ &half_space
+
+ &li Application is insulated from the underlying transport mechanism and/or protocols.
+ &half_space
+
+ &li Message distribution (round robin or fanout) is selectable by message type.
+ &half_space
+
+ &li Route management updates are received and processed asynchronously and without overt
+ application involvement.
+&end_list
+&uindent
+
+&space
+&h2(Purpose)
+RMR's main purpose is to provide an application with the ability to send and receive messages to/from other
+peer applications with minimal effort on the application's part.
+To achieve this, RMR manages manages all endpoint information, connections, and routing information necessary
+to establish and maintain communication.
+From the application's point of view, all that is required to send a message is to allocate (via RMR) a message
+buffer, add the payload data, and set the message type.
+To receive a message, the application needs only to invoke the receive function; when a message
+arrives a message buffer will be returned as the function result.
+
+
+&h2(Message Routing)
+Applications are required to place a message type into a message before sending, and may optionally add a
+subscription ID when appropriate.
+The combination of message type, and subscription ID are refered to as the &ital(message key,)
+and is used to match an entry in a routing table which provides the possible endpoints expecting
+to receive messages with the matching key.
+
+&h3(Round Robin Delivery)
+An endpoint from RMR's perspective is an application to which RMR may establish a connection, and expect to
+send messages with one or more defined message keys.
+Each entry in the route table consists of one or more endpoint groups, called round robin groups.
+When a message matches a specific entry, the entry's groups are used to select the destination of the message.
+A message is sent once to each group, with messages being &ital(balanced) across the endpoints of a group
+via round robin selection.
+Care should be taken when defining multiple groups for a message type as there is extra overhead required
+and thus the overall message latency is somewhat reduced.
+
+&h3(Routing Table Updates)
+Route table information is made available to RMR a static file (loaded once), or by updates sent from a
+separate route manager application.
+If a static table is provided, it is loaded during RMR initialisation and will remain in use until
+an external process connects and delivers a route table update (often referred to as a dynamic update).
+Dynamic updates are listened for in a separate process thread and applied automatically; the application does not
+need to allow for, or trigger, updates.
+
+&h2(Latency And Throughput)
+While providing insulation from the underlying message transport mechanics, RMR must also do so in such a
+manner that message latency and throughput are not impacted.
+In general, the RMR induced overhead, incurred due to the process of selecting an endpoint for each message,
+is minimal and should not impact the overall latency or throughput of the application.
+This impact has been measured with test applications running on the same physical host and the average
+latency through RMR for a message was on the order of 0.02 milliseconds.
+
+&space
+As an application's throughput increases, it becomes easy for the application to overrun the underlying
+transport mechanism (e.g. NNG), consume all available TCP transmit buffers, or otherwise find itself
+in a situation where a send might not immediately complete.
+RMR offers different &ital(modes) which allow the application to manage these states based on the
+overall needs of the application.
+These modes are discussed in the &ital(Configuration) section of this document.
+
+
+.** snarf in the major sections (to avoid one huge source document and maybe to promote reuse)
+.im general_use.im
+.im advanced_use.im
+.im failures.im
+.im config.im
+
+
+.if tfm
+ .** show all column/foot notes
+ .cn showend
+ &mult_space( 3 )
+.fi
+
+
+
+.dv qr_appendix A
+.pa
+.im api_qref.im
+
+.dv mbuf_appendix B
+.pa
+.im mbuf.im
+
+.dv gloss_appendix C
+.pa
+.im glossary.im
+
+.dv code_appendix D
+.pa
+.im code_appendix.im
+
+.** if pfm and index was setup, include it now
+.if index_here
+ .st 8p
+ &index_here
+ .st &textsize
+.fi
+.pa
+
+.** capture all interesting variables to be used as forward references during pass 2
+.ca expand start p1var_setup.ca
+ .** pass 1 variable settings -- do NOT commit to repo
+
+ .dv qr_appendix &qr_appendix
+ .dv mbuf_appendix &mbuf_appendix
+ .dv gloss_appendix &gloss_appendix
+ .dv code_appendix &code_appendix
+.ca end
+
+.qu
+glossary:
+context
+endpoint
+mt/sid
+NNG
+push back
+route table
.hn off
-.** super sccript number for start_note macro
-.dv ss_num 1
.** these macros are common for prfm/tfm, markdown will override some
.dv indent .ll -.5i .in +.25i
.** ex_end macro calls _must_ be placed in col 0 to cause an exit from no-format mode.
.dv ex_end .fo on .sf ^&textfont .st ^&textsize .in -.25i .ll +.25i .sp .1
+.dv proto_start .sp 1 .cc .5i .st 9 .sf Courier-bold .nf
+.dv proto_end .fo on .sf ^&text_font .st ^&text_size .sp .3
+
+
.dv h1 .sp .1 .h1 $1
.dv h2 .sp .1 .h2 $1
.dv h3 .sp .1 .h3 $1
.dv di .di $1 ^:
+.** superscript number for start_note macro
+.dv ss_num 1
.dv super .sm ^[ .sm ^&{ss_num}]
.dv note .dv ss_num ^[ ^&ss_num 1 + ] ^: .sm ^[ .sm ^&{ss_num}]
+.dv atbot atclose
-.dv start_note .cn start atend Times-roman 8p .5i
+.dv start_note .cn start atclose Times-roman 8p .5i
.dv end_note .cn end
.dv bold $1
.dv cw $1
.dv line_len .ll $1
.dv space .sp 1
.dv half_space .sp 1
+.dv mult_space .sp $1
.** -----------------------------------------------
.** not used, but might be needed if doc expanded
.dv uindent .sp 2
.dv smindent
.dv smuindent .sp 2
-.dv bold ** .sm $1 .sm **
-.dv ital _ .sm $1 .sm _
+.dv bold **${1}**
+.dv ital _${1}_
.dv h1 .sp 2 # $1 .br
.dv h2 .sp 1 ## $1 .br
.dv h3 .sp 1 ### $1 .br
.dv ex_start ^^.IP .br ^^.nf .br ^^.ft CW .br .nf
.dv ex_end .fo on .br ^^.ft P .br ^^.fi .br ^&space
+.dv proto_start .sp 1 .cc .5i .st 9 .sf Courier-bold .nf
+.dv proto_end .fo on .sf ^&text_font .st ^&text_size .sp .3
+
.** fonts and font macros
.dv ital \fI$1\fR
.dv bold \fB$1\fR
.fi
-.if tfm
- .** assume that we're generating rts output when tfm is used. These macros
.** convert {X}fm input into rts.
.** post processing is needed to strip the leading space that tfm insists on adding.
.dv ex_start .sp 1 ^:^: .br .ll -2 .in +2 .nf
.dv ex_end .fo on .in -2 .ll +2 .sp 1
+ .dv proto_start .sp 1 .cc .5i .st 9 .sf Courier-bold .nf
+ .dv proto_end .fo on .sf ^&text_font .st ^&text_size .sp .3
+
.dv center .br $1 .br
.dv center_start .br
.dv center_end .br
.dv tab_cell
.dv tab_row
.dv end_table .fi
+
+ .dv super .sm ^[ .sm ^&{ss_num}]
+ .dv ss_num 1
+ .dv note .dv ss_num ^[ ?%.0f ^&ss_num 1 + ] ^: .sm ^^[^&{ss_num}]
+ .** rst has no concept of a page, so all notes go to the close of the doc
+ .dv atbot atclose
.ju off
-.ei
- .** for postscript output we just need to set macros up to mimic those above; same for
- .** what ever alternate crap we're generating, so defined once:
- .im generic_ps.im
-.fi
.dv ex_start .sp 1 .ll -2 .in +2 .nf
.dv ex_end .fo on .in -2 .ll +2 .sp 1
+.dv proto_start .sp 1 .cc .5i .st 9 .sf Courier-bold .nf
+.dv proto_end .fo on .sf ^&text_font .st ^&text_size .sp .3
+
.** fonts and font macros
.dv ital $1
.dv bold $1
.dv tab_row
.dv end_table .fi
+.dv super .sm ^[ .sm ^&{ss_num}]
+.dv ss_num 1
+.dv note .dv ss_num ^[ ?%.0f ^&ss_num 1 + ] ^: .sm ^^[^&{ss_num}]
+.** pure ascii out has no concept of a page, so all notes go to the close of the doc
+.dv atbot atclose
.ju on