-Change Summaries
+API change summaries and fixes to the code. Doc correctsions
+and/or changes are not mentioned here; see the commit messages.
2019 July 15; Version 1.0.39
Prevent unnecessary usleep in retry loop.
# -DBUILD_DOC=1 Man pages generated
# -DPRESERVE_PTYPE=1 Do not change the processor type when naming deb packages
# -DPACK_EXTERNALS=1 Include external libraries used to build in the run-time package
+# (This makes some stand-alone unit testing of bindings possible, it
+# is not meant to be used for production package generation.)
# -DSKIP_EXTERNALS=1 Do not use Nano/NNG submodules when building; uee installed packages
# -DMAN_PREFIX=<path> Supply a path where man pages are installed (default: /usr/share/man)
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 "0" )
-set( patch_level "39" )
+set( patch_level "43" )
set( install_root "${CMAKE_INSTALL_PREFIX}" )
set( install_lib "lib" )
message( "+++ installing nano/nng with: ${nano_major}.${nano_minor} | ${nng_major}.${nng_minor}" )
else()
if( PACK_EXTERNALS )
+ # This makes some stand-alone unit testing possible for bindings and transport layer testing;
+ # it is not meant for production packages.
+ #
unset( SKIP_EXTERNALS CACHE ) # must remove so as not to trap user into a never ending failure
unset( PACK_EXTERNALS CACHE )
message( FATAL_ERROR "ERROR: PACK_EXTERNALS can be set only if SKIP_EXTERNALS is unset (=0, or not supplied on command line)" )
ADD . /tmp
WORKDIR /tmp
-# build RMr, run unit tests, and generate packages
+# build RMr, run unit tests, and generate packages and package lists
RUN ksh ci/ci_build.ksh
+# Executing the container "as a binary" will cause the CI publish
+# script to execute. This will take the simple package list generated
+# by the ci_build script and copy the list of packages to the target
+# directory. The target directory is /export by default, but can be
+# overridden from the docker run command line. In either case, the
+# assumption is that the target directory is mounted as a volume.
+#
+ENTRYPOINT [ "ci/publish.sh" ]
+
# Date: 14 June 2019
# --------------------------------------------------------------------------------
-# stash a set of packages for a particular flavour ($1)
+# stash a set of packages for a particular flavour ($1). Records what was kept
+# in a yaml file for an external process to grab, and in a simple publication
+# list for our internal publish script to gobble up.
#
function stash_pkgs {
+ mkdir -p $target_dir/exported
+
for pkg in deb rpm
do
ls .build/*.$pkg 2>/dev/null | while read f
do
- cp $f $target_dir/${f##*/}
- echo " - $target_dir/${f##*/}" >>$yaml_file
+ cp $f $target_dir/exported/${f##*/}
+ echo " - $target_dir/exported/${f##*/}" >>$yaml_file
done
done
*) echo "$1 is not recognised"
echo ""
echo "usage: $0 [-t target-dir]"
+ echo " target dir defaults to /tmp and is where packages and lists are placed."
exit 1
;;
esac
if [[ ! -d $target_dir ]]
then
- echo "[FAIL] cannot find directory: $target_dir"
- exit 1
+ if ! -mkdir -p $target_dir
+ then
+ echo "[FAIL] cannot find or create target directory: $target_dir"
+ exit 1
+ fi
fi
if [[ ! -d ./ci ]] # verify we are in the root of the RMr repo filesystem, abort if not
--- /dev/null
+#!/usr/bin/env bash
+
+# -----------------------------------------------------------------------------
+#
+# Copyright (C) 2019 AT&T Intellectual Property and Nokia
+#
+# 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.
+#
+# -----------------------------------------------------------------------------
+
+# Mnemonic: publish
+# Abstract: Simple script which copies files that the build script left
+# for export (packages, but could be anything). This expects
+# that all files in /tmp/exportd are to be copied to the
+# export directory /export The export directory is assumed to be
+# mounted from the outside world as /export, though we will use $1
+# as an override so this can be changed if needed.
+#
+# Date: 30 July 2019
+#
+# -----------------------------------------------------------------------------
+
+echo "$0 starting" >&2
+argv0=${0##*/}
+
+target=${1:-/export}
+exportd=/tmp/exported # build script dumps here
+
+if ! cd $target
+then
+ echo "$argv0: abort: cannot find or switch to: $target" >&2
+ exit 1
+fi
+
+if [[ ! -w ./ ]]
+then
+ echo "$argv0: abort: cannot write to target directory: $target"
+ exit 1
+fi
+
+if [[ ! -d $exportd ]]
+then
+ echo "$argv0: abort: unable to find the exported directory: $exportd" >&2
+ exit 1
+fi
+
+errors=0
+echo "$argv0: copy: $exportd/* --> $target" >&2
+if ! cp -v $exportd/* $target/
+then
+ errors=1
+fi
+
+echo "$argv0: finshed, $errors errors"
+exit $errors
rmr_mt_rcv.3
rmr_get_srcip.3
rmr_trace_ref.3
+ rmr_set_stimeout.3
)
# initialise lists of files we generated
# for each source, build a specific command that runs tfm to generate the
# troff output as a gzipped file. Sed is needed to remove the leading blank
- # that tfm likes to insert even if indention is 0.
+ # that tfm likes to insert even if indention is 0. We also generate postscript
+ # markdown, plain ascii and rts output which are left in the build directory
+ # for the developer to use as needed.
#
foreach( nm IN LISTS man_names )
set( out ${CMAKE_BINARY_DIR}/${nm} )
add_custom_command(
OUTPUT ${out}.gz
DEPENDS ${in}
- COMMAND bash -c "export LIB=${CMAKE_SOURCE_DIR}/doc/src; ${tfm} ${in} stdout | sed 's/^ //' | gzip >${out}.gz; ${pfm} ${in} ${out}.ps"
+ COMMAND bash -c "export LIB=${CMAKE_SOURCE_DIR}/doc/src; \
+ export OUTPUT_TYPE=troff; \
+ ${tfm} ${in} stdout | sed 's/^ //' | gzip >${out}.gz; \
+ export OUTPUT_TYPE=rst; \
+ ${tfm} ${in} ${out}.rst; \
+ export OUTPUT_TYPE=txt; \
+ ${tfm} ${in} ${out}.txt; \
+ export OUTPUT_TYPE=markdown; \
+ ${tfm} ${in} stdout | sed 's/^ //' >${out}.md; \
+ export OUTPUT_TYPE=postscript; \
+ ${pfm} ${in} ${out}.ps"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Building manpage ${out}"
VERBATIM
--- /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: retry.im
+ Abstract: Common text for all send operation functions. This should be imbedded by any
+ function which will ultimately use the internal send_msg funciton which
+ governs retries in this manner.
+ Date: 16 July 2019
+.fi
+
+&h3(Retries)
+The send operations in RMr will retry &ital(soft) send failures until one of three
+conditions occurs:
+&half_space
+&indent
+&beg_dlist( 0.3i : ^&bold_font )
+ &di(1.) The message is sent without error
+ &half_space
+
+ &di(2.) The underlying transport reports a &ital( hard ) failure
+ &half_space
+
+ &di(3.) The maximum number of retry loops has been attempted
+ &end_dlist
+&uindent
+
+&space
+A retry loop consists of approximately 1000 send attemps &bold( without) any intervening
+calls to &ital( sleep() ) or &ital( usleep(). )
+The number of retry loops defaults to 1, thus a maximum of 1000 send attempts is performed
+before returning to the user application.
+This value can be set at any point after RMr initialisation using the &ital( rmr_set_stimeout() )
+function allowing the user application to completely disable retires (set to 0), or to
+increase the number of retry loops.
+
+&h3(Transport Level Blocking)
+The underlying transport mechanism used to send messages is configured in &ital(non-blocking)
+mode.
+This means that if a message cannot be sent immediately the transport mechanism will &bold(not)
+pause with the assumption that the inability to send will clear quickly (within a few milliseconds).
+This means that when the retry loop is completely disabled (set to 0), that the failure to
+accept a message for sending by the underlying mechanisms (software or hardware) will be
+reported immediately to the user application.
+
+&space
+It should be noted that depending on the underlying transport mechanism being used, it is
+extremly possible that during normal operations that retry conditions are very likely to
+happen.
+These are completely out of RMr's control, and there is nothing that RMr can do to avoid or midigate
+these other than by allowing RMr to retry the send operation, and even then it is possible
+(e.g. during connection reattempts), that a single retry loop is not enough to guarentee a
+successful send.
+
Date 29 January 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** and rst.im will cause rst to be generated depending on OUTPUT_TYPE env
-.** var.
-.** if formatting with pfm, then pretty postscript will be generated
-
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 28 January 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
-
&h1(RMR Library Functions)
&h2(NAME)
rmr_alloc_msg
Date 8 March 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 8 March 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 8 March 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 28 January 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Currently the threshold is fixed at 20 messages, though in future versions of the library
this might be extended to be a parameter which the user application may set.
+.** pull in common retry text
+.im &{lib}/man/retry.im
+
&h2(RETURN VALUE)
The &cw(rmr_call) function returns a pointer to a message buffer with the state set to reflect
the overall state of call processing (see Errors below).
rmr_ready(3),
rmr_fib(3),
rmr_has_str(3),
+rmr_set_stimeout(3),
rmr_tokenise(3),
rmr_mk_ring(3),
rmr_ring_free(3)
Date 21 February 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 28 January 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 8 March 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 11 February 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 8 March 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 11 June 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 19 April 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 19 April 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 28 January 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 19 April 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 24 May 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
&space
Messages which are received while waiting for the response are queued on a &ital(normal)
receive queue and will be delivered to the user application with the next invocation
-of &itaL( rmr_mt_rcv() ) or &ital( rmr_rvv_msg().)
+of &ital( rmr_mt_rcv() ) or &ital( rmr_rvv_msg().)
by RMR, and are returned to the user application when &cw(rmr_rcv_msg) is
invoked.
These messages are returned in th order received, one per call to &cw(rmr_rcv_msg.)
&space
NOTE: Currently the multi-threaded functions are supported only when the NNG
transport mechanism is being used. It will not be possible to link a programme
-using the nanomsg version of the library when references to this function are
+using the Nanomsg version of the library when references to this function are
present.
&h3(The Transaction ID)
the application uses the &ital( rmr_rts_msg() ) function and does not adjust the
transaction ID.
+.** pull in common retry text
+.im &{lib}/man/retry.im
&h2(RETURN VALUE)
The &cw(rmr_mt_call) function returns a pointer to a message buffer with the state set to reflect
rmr_ready(3),
rmr_fib(3),
rmr_has_str(3),
+rmr_set_stimeout(3),
rmr_tokenise(3),
rmr_mk_ring(3),
rmr_ring_free(3)
Date 24 May 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 29 January 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 29 January 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 28 January 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 28 January 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Other than this small difference, the behaviour is exactly the same as
&cw(rmr_send_msg.)
+.** pull in common retry text
+.im &{lib}/man/retry.im
+
&h2(RETURN VALUE)
On success, a new message buffer, with an empty payload, is returned for the application
to use for the next send.
rmr_ready(3),
rmr_fib(3),
rmr_has_str(3),
+rmr_set_stimeout(3),
rmr_tokenise(3),
rmr_mk_ring(3),
rmr_ring_free(3)
Date 28 January 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
responsibility of the library.)
+.** pull in common retry text
+.im &{lib}/man/retry.im
+
+
&h2(RETURN VALUE)
On success, a new message buffer, with an empty payload, is returned for the application
to use for the next send.
&cw(RMR_OK.)
&space
-If the state in the returned buffer is anything other than &cw(UT_OK,) the user application
-may need to attempt a retransmission of the message, or take other action depending on the
-setting of &cw(errno) as described below.
+When the message cannot be successfully sent this function will return the unsent (original)
+message buffer with the state set to indicate the reason for failure.
+The value of &ital( errno ) may also be set to reflect a more detailed failure reason if it
+is known.
&space
In the event of extreme failure, a NULL pointer is returned. In this case the value of
&space
&beg_dlist(.75i : ^&bold_font )
+&di(RMR_RETRY) The message could not be sent, but the underlying transport mechanism
+ indicates that the failure is temporary. If the send operation is tried again
+ it might be successful.
+&di(RMR_SEND_FAILED) The send operation was not successful and the underlying transport
+ mechanism indicates a permanent (hard) failure; retrying the send is not possible.
&di(RMR_ERR_BADARG) The message buffer pointer did not refer to a valid message.
&di(RMR_ERR_NOHDR) The header in the message buffer was not valid or corrupted.
&di(RMR_ERR_NOENDPT) The message type in the message buffer did not map to a known endpoint.
--- /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 rmr_set_stimeout.xfm
+ Abstract The manual page for the rmr_set_stimeout function.
+ Author E. Scott Daniels
+ Date 28 January 2019
+.fi
+
+.gv e LIB lib
+.im &{lib}/man/setup.im
+
+&line_len(6i)
+
+&h1(RMR Library Functions)
+&h2(NAME)
+ rmr_set_stimeout
+
+&h2(SYNOPSIS )
+&indent
+&ex_start
+#include <rmr/rmr.h>
+
+rmr_mbuf_t* rmr_set_stimeout( void* vctx, int rloops );
+
+&ex_end
+&uindent
+
+&h2(DESCRIPTION)
+The &cw(rmr_set_stimeout) function sets the configuration for how RMr will retry
+message send operations which complete with either a &ital( timeout ) or &ital( again )
+completion value. (Send operations include all of the possible message send
+functions: &ital( rmr_send_msg(), rmr_call(), rmr_rts_msg() ) and &ital( rmr_wh_send_msg(). )
+The &ital( rloops ) parameter sets the maximum number of retry loops
+that will be attempted before giving up and returning the unsuccessful state to the user
+application.
+Each retry loop is approximately 1000 attempts, and RMr does &bold( not ) invoke any sleep
+function between retries in the loop; a small, 1 mu-sec, sleep is executed between loop
+sets if the &ital( rloops ) value is greater than 1.
+
+.sp
+&h3(Disabling Retries)
+By default, the send operations will execute with an &ital( rloop ) setting of 1; each send
+operation will attempt to resend the message approximately 1000 times before giving up.
+If the user application does not want to have send operations retry when the underlying
+transport mechanism indicates &ital( timeout ) or &ital( again, ) the application should
+invoke this function and pass a value of 0 (zero) for &ital( rloops. )
+With this setting, all RMr send operations will attempt a send operation only &bold( once, )
+returning immediately to the caller with the state of that single attempt.
+
+
+&h2(RETURN VALUE)
+This function returns a -1 to indicate that the &ital( rloops ) value could not be set, and
+the value &ital( RMR_OK ) to indicate success.
+
+
+&h2(ERRORS)
+Currently errno is &bold( not ) set by this function; the only cause of a failure is an
+invalid context ( .sm &ital( vctx ) .sm ) pointer.
+
+&h2(EXAMPLE)
+The following is a simple example of how the &cw(rmr_set_stimeout) function is called.
+
+&space
+&ex_start
+ #define NO_FLAGS 0
+
+ char* port = "43086"; // port for message router listen
+ int max_size = 4096; // max message size for default allocations
+ void* mr_context; // message router context
+
+ mr_context = rmr_init( port, max_size, NO_FLAGS );
+ if( mr_context != NULL ) {
+ rmr_set_stimeout( mr_context, 0 ); // turn off retries
+ }
+
+&ex_end
+
+
+&h2(SEE ALSO )
+.ju off
+rmr_alloc_msg(3),
+rmr_call(3),
+rmr_free_msg(3),
+rmr_init(3),
+rmr_payload_size(3),
+rmr_rcv_msg(3),
+rmr_rcv_specific(3),
+rmr_rts_msg(3),
+rmr_ready(3),
+rmr_mk_ring(3),
+rmr_ring_free(3),
+rmr_send_msg(3),
+rmr_torcv_rcv(3),
+rmr_wh_send_msg(3)
+.ju on
+
+
+.qu
+
Date 19 April 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 8 March 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 8 March 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 28 January 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 29 January 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 11 July 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 19 April 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 21 February 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 20 February 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
Date 28 January 2019
.fi
-.** if formatting with tfm, the roff.im will cause roff output to be generated
-.** if formatting with pfm, then pretty postscript will be generated
.gv e LIB lib
-.if pfm
- .im &{lib}/generic_ps.im
-.ei
- .gv e OUTPUT_RST use_rst
- .if .ev &use_rst 1 =
- .im &{lib}/rst.im
- .ei
- .im &{lib}/roff.im
- .fi
-.fi
+.im &{lib}/man/setup.im
&line_len(6i)
to a process at the other end of a wormhole which was created with &ital(rmr_wh-open().)
When sending message via wormholes, the normal RMr routing based on message type is
ignored, and the caller may leave the message type unspecified in the message buffer
-(unless it is needed by the reeciving process).
+(unless it is needed by the receiving process).
.sp
The message buffer (msg) used to send is the same format as used for regular RMr
send and reply to sender operations, thus any buffer allocated by these means, or
calls to &ital(rmr_rcv_msg()) can be passed to this function.
+.** pull in common retry text
+.im &{lib}/man/retry.im
&h2(RETURN VALUE)
On success, a new message buffer, with an empty payload, is returned for the application
rmr_tokenise(3),
rmr_mk_ring(3),
rmr_ring_free(3),
+rmr_set_stimeout(3),
rmr_wh_open(3),
rmr_wh_close(3)
.ju on
--- /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 postscirpt
+ 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
+.xx 0
--- /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: markdown.im
+ Abstract: This is a setup for a very basic generation of markdown from the few
+ macros which are designed for the RMR doc. It is very scaled down from
+ the markdown imbed file supplied with {X}fm.
+
+ Author: E. Scott Danils
+ Date: 26 October 2016
+-------------------------------------------------------------------------------
+.fi
+
+
+.dh 1 m=.5i e=no s=21 i=0 p=16 f=Helvetica-bold
+.dh 2 m=.5i s=21 i=0 p=14 f=Helvetica-bold
+.dh 3 m=.5i s=10 i=0 p=12 f=Helvetica-bold
+
+.ju on
+.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
+.dv uindent .in -.25i .ll +.5i
+.dv smindent .ll -.2i .in +.1i
+.dv smuindent .in -.1i .ll +.2i
+
+.dv def_list .bd $1
+.dv end_dlist .ed
+.dv bd .bd $1
+.dv ed .ed
+
+.dv ex_start .sp .5 .ll -.25i .in +.25i .sf Courier .st ^&extextsize .fo off
+.** 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 h1 .sp .1 .h1 $1
+.dv h2 .sp .1 .h2 $1
+.dv h3 .sp .1 .h3 $1
+.dv di .di $1 ^:
+
+.dv super .sm ^[ .sm ^&{ss_num}]
+.dv note .dv ss_num ^[ ^&ss_num 1 + ] ^: .sm ^[ .sm ^&{ss_num}]
+
+.dv start_note .cn start atend Times-roman 8p .5i
+.dv end_note .cn end
+.dv bold $1
+.dv cw $1
+.dv set_font_prop
+.dv ital $1
+.dv lic1 *
+.dv lic2 +
+
+.dv line_len .ll $1
+.dv space .sp 1
+.dv half_space .sp 1
+
+.** -----------------------------------------------
+.** not used, but might be needed if doc expanded
+.** .dv ta .br ^.ta .br |
+.** .dv et .br ^.et .br
+.** .dv cl |
+.** .dv tr | .br ^.tr .br |
+.** .dv table_head $1
+.** .dv empty_cell
+.** -----------------------------------------------
+
+.dv break .sm ^` ^` .br
+.dv br .sm ^` ^` .br
+.ju off
+.dv image .ep ^[ .sm $2] ($3)
+
+.** no concept of a definition list in markdown; no start/end and just make the text bold to emulate
+.dv beg_dlist .sp 1
+.dv bd .sp 1
+.dv end_dlist .sp 1
+.dv ed .sp 1
+.dv di ^&break **$1:**
+
+.dv beg_list .bl *
+.dv item .li
+.dv li .li
+.dv end_list .el
+
+.dv line .sp 1 ------
+
+.** leading indention is significant to markdown, so turn it off
+.in 0
+.dv indent
+.dv uindent .sp 2
+.dv smindent
+.dv smuindent .sp 2
+.dv bold ** .sm $1 .sm **
+.dv ital _ .sm $1 .sm _
+.dv h1 .sp 2 # $1 .br
+.dv h2 .sp 1 ## $1 .br
+.dv h3 .sp 1 ### $1 .br
+
+.dv ex_start .sp .5 .ll -4 .in .5i .sp 2 .fo off
+.dv ex_end .fo on .in 0i .ll +4 .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
+
+.if false
+ Mnemonic: txt.im
+ Abstract: To generate raw ASCII we just need to 'disable' the macros which
+ are defined to support things like troff, markdown and rts.
+ For each of those macros, we just map to real {X}fm commandd
+ which do the right thing when generating real .txt output.
+
+ Author: E. Scott Daniels
+ Date: 29 July 2019
+
+.fi
+
+
+.cd 1 6.5i i=0
+.in .25i
+
+.** paragraph headers
+.dv h1 .h1 $1
+.dv h2 .h2 $1
+.dv h3 .h3 $1
+.dv h4 .h4 $1
+
+.dh 1 s=2,1 i=.25i
+.dh 2 s=1,1 i=.25i
+.dh 3 s=1,0 i=.25i
+.hn off
+
+.dv fig .fi t=figure
+.dv set_font_cw
+
+.dv nf .sp 1 ^:^: .br .ll -2 .in +2
+.dv fo .in -2 .ll +2 .sp 1
+
+.dv indent .ll -.25i .in +.25i
+.dv uindent .in -.25i .ll +.25i
+
+.dv lic1 *
+.dv lic2 +
+.dv lic3 -
+
+.dv line_len .ll $1
+.dv space .sp 1
+.dv half_space .sp 1
+.dv beg_list .sp 1 .dv lic $1 ^:
+.dv end_list .sp 1
+
+.dv beg_dlist .sp 1 .bd $1
+.dv end_dlist .ed
+
+.** for now we allow only a single layer of defitems
+.dv di .di $1 ^:
+.dv diitem .di $1 ^:
+.dv item .li
+
+.dv ex_start .sp 1 .ll -2 .in +2 .nf
+.dv ex_end .fo on .in -2 .ll +2 .sp 1
+
+.** fonts and font macros
+.dv ital $1
+.dv bold $1
+.dv cw $1
+.dv set_font_prop
+
+.dv table .sp 1 ^[table not supported in plain txt output] .if false
+.dv tab_cell
+.dv tab_row
+.dv end_table .fi
+
+.ju on
+
See the `examples` directory.
# Compiling rmr (if not already done on your system)
-(Note, you may or may not need sudo in your final command, depending on permissions to `/usr/local`. I need it)
+(Note, you may or may not need sudo in your final command, depending on permissions to `/usr/local`. The pack externals option to CMake is needed only if the NNG libary is not already installed on the system, and you do not wish to manually install it.)
git clone https://gerrit.oran-osc.org/r/ric-plt/lib/rmr
cd rmr
- mkdir .build; cd .build; cmake ..; sudo make install
+ mkdir .build; cd .build; cmake .. -DPACK_EXTERNALS=1; sudo make install
lcaller: lcaller.c
gcc -I $${C_INCLUDE_PATH:-.} $< -g -o $@ -lrmr_nng -lnng -lpthread -lm
+lsender: lsender.c
+ gcc -I $${C_INCLUDE_PATH:-.} $< -g -o $@ -lrmr_nng -lnng -lpthread -lm
# clean removes intermediates; nuke removes everything that can be built
--- /dev/null
+// :vim ts=4 sw=4 noet:
+/*
+==================================================================================
+ 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.
+==================================================================================
+*/
+
+/*
+ Mnemonic: lsender.c
+ Abstract: This is a simple sender, slimiar to sender.c, except that a timestamp
+ is placed into the messages such that latency measurements can be
+ made.
+ The message format is 'binary' defined by the lc_msg struct.
+
+ Parms: argv[1] == number of msgs to send (10)
+ argv[2] == delay (mu-seconds, 1000000 default)
+ argv[3] == listen port
+
+ Sender will send for at most 20 seconds, so if nmsgs and delay extend
+ beyond that period the total number of messages sent will be less
+ than n.
+
+ Date: 18 April 2019
+ Author: E. Scott Daniels
+*/
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/epoll.h>
+#include <time.h>
+#include <pthread.h>
+
+
+#include <rmr/rmr.h>
+
+#define TRACE_SIZE 40 // bytes in header to provide for trace junk
+#define SUCCESS (-1)
+
+/*
+ Thread data
+*/
+typedef struct tdata {
+ int id; // the id we'll pass to RMr mt-call function NOT the thread id
+ int n2send; // number of messages to send
+ int delay; // ms delay between messages
+ void* mrc; // RMr context
+ int state;
+ int* in_bins; // latency count bins
+ int* out_bins;
+ int nbins; // number of bins allocated
+ long long in_max;
+ long long out_max;
+ int out_oor; // out of range count
+ int in_oor;
+ int in_bcount; // total messages tracked in bins
+ int out_bcount; // total messages tracked in bins
+} tdata_t;
+
+
+/*
+ The message type placed into the payload.
+*/
+typedef struct lc_msg {
+ struct timespec out_ts; // time just before call executed
+ struct timespec turn_ts; // time at the receiver, on receipt
+ struct timespec in_ts; // time received back by the caller
+ int out_retries; // number of retries required to send
+ int turn_retries; // number of retries required to send
+} lc_msg_t;
+
+// --------------------------------------------------------------------------------
+
+
+static int sum( char* str ) {
+ int sum = 0;
+ int i = 0;
+
+ while( *str ) {
+ sum += *(str++) + i++;
+ }
+
+ return sum % 255;
+}
+
+static void print_stats( tdata_t* td, int out, int hist ) {
+ int sum; // sum of latencies
+ int csum = 0; // cutoff sum
+ int i95 = 0; // bin for the 95th count
+ int i99 = 0; // bin for the 99th count
+ int mean = -1;
+ int cutoff_95; // 95% of total messages
+ int cutoff_99; // 99% of total messages
+ int oor;
+ int max;
+ int j;
+
+ if( out ) {
+ cutoff_95 = .95 * (td->out_oor + td->out_bcount);
+ cutoff_99 = .95 * (td->out_oor + td->out_bcount);
+ oor = td->out_oor;
+ max = td->out_max;
+ } else {
+ cutoff_95 = .95 * (td->in_oor + td->in_bcount);
+ cutoff_99 = .95 * (td->in_oor + td->in_bcount);
+ oor = td->in_oor;
+ max = td->in_max;
+ }
+
+ sum = 0;
+ for( j = 0; j < td->nbins; j++ ) {
+ if( csum < cutoff_95 ) {
+ i95++;
+ }
+ if( csum < cutoff_99 ) {
+ i99++;
+ }
+
+ if( out ) {
+ csum += td->out_bins[j];
+ sum += td->out_bins[j] * j;
+ } else {
+ csum += td->in_bins[j];
+ sum += td->in_bins[j] * j;
+ }
+ }
+
+ if( out ) {
+ if( td->out_bcount ) {
+ mean = sum/(td->out_bcount);
+ }
+ } else {
+ if( td->in_bcount ) {
+ mean = sum/(td->in_bcount);
+ }
+ }
+
+ if( hist ) {
+ for( j = 0; j < td->nbins; j++ ) {
+ fprintf( stderr, "%3d %d\n", j, out ? td->out_bins[j] : td->in_bins[j] );
+ }
+ }
+
+ fprintf( stderr, "%s: oor=%d max=%.2fms mean=%.2fms 95th=%.2fms 99th=%.2f\n",
+ out ? "out" : " in", oor, (double)max/1000000.0, (double)mean/100.0, (double) i95/100.0, i99/100.0 );
+}
+
+/*
+ Given a message, compute the in/out and round trip latencies.
+*/
+static void compute_latency( tdata_t* td, lc_msg_t* lcm ) {
+ long long out;
+ long long turn;
+ long long in;
+ double rtl; // round trip latency
+ double outl; // caller to receiver latency (out)
+ double inl; // receiver to caller latency (in)
+ int bin;
+
+ if( lcm == NULL || td == NULL ) {
+ return;
+ }
+
+ out = (lcm->out_ts.tv_sec * 1000000000) + lcm->out_ts.tv_nsec;
+ in = (lcm->in_ts.tv_sec * 1000000000) + lcm->in_ts.tv_nsec;
+ turn = (lcm->turn_ts.tv_sec * 1000000000) + lcm->turn_ts.tv_nsec;
+
+ if( in - turn > td->in_max ) {
+ td->in_max = in - turn;
+ }
+ if( turn - out > td->out_max ) {
+ td->out_max = turn-out;
+ }
+
+ bin = (turn-out) / 10000; // 100ths of ms
+
+#ifdef PRINT
+ outl = ((double) turn - out) / 1000000.0; // convert to ms
+ inl = ((double) in - turn) / 1000000.0;
+ rtl = ((double) in - out) / 1000000.0;
+
+ fprintf( stderr, "outl = %5.3fms inl = %5.3fms rtl = %5.3fms bin=%d\n", outl, inl, rtl, bin );
+#else
+
+ bin = (turn - out) / 10000; // 100ths of ms
+ if( bin < td->nbins ) {
+ td->out_bins[bin]++;
+ td->out_bcount++;
+ } else {
+ td->out_oor++;
+ }
+
+ bin = (in - turn) / 10000; // 100ths of ms
+ if( bin < td->nbins ) {
+ td->in_bins[bin]++;
+ td->in_bcount++;
+ } else {
+ td->in_oor++;
+ }
+
+#endif
+}
+
+/*
+ Compute the elapsed time between ts1 and ts2.
+*/
+static int elapsed( struct timespec* start_ts, struct timespec* end_ts ) {
+ long long start;
+ long long end;
+ int bin;
+
+ start = ( start_ts->tv_sec * 1000000000) + start_ts->tv_nsec;
+ end = ( end_ts->tv_sec * 1000000000) + end_ts->tv_nsec;
+
+ bin = (end - start) / 1000000; // ms
+
+ return bin;
+}
+
+/*
+ The main thing.
+*/
+static void* send_msgs( void* mrc, int n2send, int delay, int retry ) {
+ lc_msg_t* lcm; // pointer at the payload as a struct
+ rmr_mbuf_t* sbuf; // send buffer
+ int count = 0;
+ int rt_count = 0; // number of messages that had a retry on first send attempt
+ int good_count = 0;
+ int drops = 0;
+ int fail_count = 0; // # of failure sends after first successful send
+ int successful = 0; // set to true after we have a successful send
+ char xbuf[1024]; // build transaction string here
+ int xaction_id = 1;
+ char* tok;
+ int state = 0;
+ struct timespec start_ts;
+ struct timespec end_ts;
+ int mtype = 0;
+
+ if( mrc == NULL ) {
+ fprintf( stderr, "send_msg: bad mrc\n" );
+ }
+
+ sbuf = rmr_alloc_msg( mrc, 256 ); // alloc first send buffer; subsequent buffers allcoated on send
+
+ snprintf( xbuf, 200, "%31d", xaction_id );
+ while( count < n2send ) { // we send n messages after the first message is successful
+ lcm = (lc_msg_t *) sbuf->payload;
+
+ rmr_bytes2xact( sbuf, xbuf, 32 );
+
+ sbuf->mtype = 0;
+ sbuf->mtype = mtype++; // all go with the same type
+ if( mtype > 9 ) {
+ mtype = 0;
+ }
+
+ sbuf->len = sizeof( *lcm );
+ sbuf->state = RMR_OK;
+ lcm->out_retries = 0;
+ lcm->turn_retries = 0;
+ clock_gettime( CLOCK_REALTIME, &lcm->out_ts ); // mark time out
+ sbuf = rmr_send_msg( mrc, sbuf );
+
+ if( sbuf && sbuf->state == RMR_ERR_RETRY ) { // send not accepted
+ if( retry || count == 0 ) {
+ rt_count++; // # messages that we retried beyond rmr's retry
+ } else {
+ if( delay )
+ usleep( delay );
+ fail_count++; // send failed because we drop it
+ }
+ }
+
+ count++;
+ if( sbuf != NULL ) {
+ if( ! successful ) {
+ switch( sbuf->state ) {
+ case RMR_OK:
+ clock_gettime( CLOCK_REALTIME, &start_ts );
+ successful = 1;
+ good_count++;
+ break;
+
+ default:
+ fprintf( stderr, "<SM> send error: rmr-state=%d ernro=%d\n", sbuf->state, errno );
+ sleep( 1 );
+ break;
+ }
+ } else {
+ good_count += sbuf->state == RMR_OK;
+ }
+ } else {
+ sbuf = rmr_alloc_msg( mrc, 512 ); // must have a sedn buffer at top
+ drops++;
+ }
+
+ //if( count < n2send && (count % 100) == 0 && delay > 0 ) {
+ if( count < n2send && delay > 0 ) {
+ if( count % 500 ) {
+ usleep( delay );
+ }
+ }
+ }
+
+ clock_gettime( CLOCK_REALTIME, &end_ts );
+
+ fprintf( stderr, "<SM> sending finished attempted=%d good=%d fails=%d rt=%d elapsed=%d ms, \n", count, good_count, fail_count, rt_count, elapsed( &start_ts, &end_ts ) );
+ return NULL;
+}
+
+int main( int argc, char** argv ) {
+ void* mrc; // msg router context
+ rmr_mbuf_t* rbuf = NULL; // received on 'normal' flow
+ char* listen_port = "43086"; // largely unused here
+ long timeout = 0;
+ int delay = 100000; // usec between send attempts
+ int nmsgs = 10; // number of messages to send
+ int rmr_retries = 0; // number of retries we allow rmr to do
+
+ if( argc > 1 ) {
+ nmsgs = atoi( argv[1] );
+ }
+ if( argc > 2 ) {
+ delay = atoi( argv[2] );
+ }
+ if( argc > 4 ) {
+ listen_port = argv[4];
+ }
+ if( argc > 3 ) {
+ rmr_retries = atoi( argv[3] );
+ }
+
+ fprintf( stderr, "<LSEND> listen port: %s; sending %d messages; delay=%d\n", listen_port, nmsgs, delay );
+
+ if( (mrc = rmr_init( listen_port, 1400, RMRFL_MTCALL )) == NULL ) { // initialise with multi-threaded call enabled
+ fprintf( stderr, "<LSEND> unable to initialise RMr\n" );
+ exit( 1 );
+ }
+
+ fprintf( stderr, "\nsetting rmr retries: %d\n", rmr_retries );
+ //if( rmr_retries != 1 ) {
+ rmr_set_stimeout( mrc, rmr_retries );
+ //}
+
+ timeout = time( NULL ) + 20; // give rmr 20s to find the route table (shouldn't need that much)
+ while( ! rmr_ready( mrc ) ) { // must have a route table before we can send; wait til RMr says it has one
+ fprintf( stderr, "<LSEND> waiting for rmr to show ready\n" );
+ sleep( 1 );
+
+ if( time( NULL ) > timeout ) {
+ fprintf( stderr, "<LSEND> giving up\n" );
+ exit( 1 );
+ }
+ }
+ fprintf( stderr, "<LSEND> rmr is ready; starting sender retries=%d\n", rmr_retries );
+
+ send_msgs( mrc, nmsgs, delay, rmr_retries );
+
+ fprintf( stderr, "pausing for drain\n" );
+ sleep( 3 );
+ fprintf( stderr, "closing down\n" );
+ rmr_close( mrc );
+
+ return 0;
+}
+