WORKDIR /playpen
# Install RMr (runtime and dev) from debian package cached on packagecloud.io
-ARG RMR_VER=3.1.2
+ARG RMR_VER=3.5.1
RUN wget -nv --content-disposition https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr_${RMR_VER}_amd64.deb/download.deb
RUN wget -nv --content-disposition https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr-dev_${RMR_VER}_amd64.deb/download.deb
#------------------------------------------------------------------------------------
# Mnemonic: build_images.sh
# Abstract: This script will create both the mc_listener runtime and development
-# images.
+# images when "all" is given on the command line, otherwise it builds
+# just a runtime environment.
# Date: 22 August 2-19
# Author: E. Scott Daniels
# -----------------------------------------------------------------------------------
fi
-ver=${1:-1.2}
-patch=${2:-1}
+ver=${1:-1.3}
+patch=${2:-0}
if (( skip_dev == 0 ))
then
docker build -f mcl_dev.df -t mcl_dev:$ver.$patch .
fi
+# use the main dockerfile for the runtime image
echo "building runtime image mc_listener:$ver"
-if docker build -f mcl_runtime.df -t mc_listener:$ver.$patch .
+if docker build -f Dockerfile -t mc_listener:$ver.$patch .
then
echo "build finished"
echo ""
#include <rmr/rmr.h>
#include <rmr/rmr_symtab.h>
+#include <rmr/RIC_message_types.h>
#include "mcl.h"
dest is nil. The header is of the form:
<delim><len><timestamp>
+ Field lengths (bytes) are:
+ delim 4
+ len 8 (7 digits + 0)
+ timestamp 16 (15 digits + 0)
+
+
Timestamp is a single unsigned long long in ASCII; ms since epoch.
If the current time is 2019/10/03 10:39:51.103 which is 1570113591.103
- the timestamp generated will be 1570113591103.
+ the timestamp generated will be 1570113591103.
+
+ The lenght and timestamp fields in the header are zero terminated so
+ they can be parsed as a string (atoi etc).
*/
static char* build_hdr( int len, char* dest, int dest_len ) {
struct timespec ts; // time just before call executed
if( dest == NULL ) {
- dest_len = 48;
+ dest_len = MCL_EXHDR_SIZE + 2; // more than enough room
dest = (char *) malloc( sizeof( char ) * dest_len );
} else {
- if( dest_len < 28 ) { // shouldn't happen, but take no chances
+ if( dest_len < MCL_EXHDR_SIZE ) { // shouldn't happen, but take no chances
memset( dest, 0, dest_len );
return NULL;
}
memset( dest, 0, dest_len );
clock_gettime( CLOCK_REALTIME, &ts );
- sprintf( dest, "%s%07d", MCL_DELIM, len );
- sprintf( dest+12, "%ld%03ld", ts.tv_sec, ts.tv_nsec/1000000 );
+ snprintf( dest, dest_len, "%s%07d", MCL_DELIM, len );
+ snprintf( dest+12, dest_len-13, "%ld%03ld", ts.tv_sec, ts.tv_nsec/1000000 );
return dest;
}
read_header( fd, wbuf );
msg_len = need = atoi( wbuf + MCL_LEN_OFF ); // read the length
if( timestamp ) {
- strcpy( timestamp, wbuf + MCL_TSTAMP_OFF+1 );
+ strncpy( timestamp, wbuf + MCL_TSTAMP_OFF+1, MCL_TSTAMP_SIZE );
}
} else {
if( timestamp != NULL ) { // won't be there, but ensure it's not garbage
If long_hdr is true, then we geneate an extended header with a delimiter and
timestamp.
+
+ The one message which is NOT pushed into a FIFO is the RIC_HEALTH_CHECK_REQ
+ message. When the health check message is received it is responded to
+ with the current state of processing (ok or err).
*/
-extern void mcl_fifo_fanout( void* vctx, int report, int long_hdr ) {
+extern void mcl_fifo_fanout( void* vctx, int report, int long_hdr ) {
mcl_ctx_t* ctx; // our context; mostly for the rmr context reference and symtable
fifo_t* fifo; // fifo to chalk counts on
rmr_mbuf_t* mbuf = NULL; // received message buffer; recycled on each call
do {
mbuf = mcl_get_msg( ctx, mbuf, report ); // wait up to report sec for msg (0 == block until message)
- if( mbuf != NULL && mbuf->state == RMR_OK && mbuf->len > 0 ) {
- fd = suss_fifo( ctx, mbuf->mtype, WRITER, &fifo ); // map the message type to an open fd
- if( fd >= 0 ) {
- if( long_hdr ) {
- build_hdr( mbuf->len, header, sizeof( header ) );
- hwlen = MCL_EXHDR_SIZE;
- } else {
- snprintf( header, sizeof( header ), "%07d", mbuf->len ); // size of payload CAUTION: 7d is MCL_LEN_SIZE-1
- hwlen = MCL_LEN_SIZE;
- }
+ if( mbuf != NULL && mbuf->state == RMR_OK ) {
+ if( mbuf->mtype == RIC_HEALTH_CHECK_REQ ) {
+ mbuf->mtype = RIC_HEALTH_CHECK_RESP; // if we're here we are running and all is ok
+ mbuf->sub_id = -1;
+ mbuf = rmr_realloc_payload( mbuf, 128, FALSE, FALSE ); // ensure payload is large enough
+ strncpy( mbuf->payload, "OK\n", rmr_payload_size( mbuf) );
+ rmr_rts_msg( ctx->mrc, mbuf );
+ continue;
+ }
+
+ if( mbuf->len > 0 ) {
+ fd = suss_fifo( ctx, mbuf->mtype, WRITER, &fifo ); // map the message type to an open fd
+ if( fd >= 0 ) {
+ if( long_hdr ) {
+ build_hdr( mbuf->len, header, sizeof( header ) );
+ hwlen = MCL_EXHDR_SIZE;
+ } else {
+ snprintf( header, sizeof( header ), "%07d", mbuf->len ); // size of payload CAUTION: 7d is MCL_LEN_SIZE-1
+ hwlen = MCL_LEN_SIZE;
+ }
- if( (state = write( fd, header, hwlen )) != hwlen ) { // write exactly MCL_LEN_SIZE bytes from the buffer
- drops++;
- total_drops++;
- chalk_error( fifo );
- } else {
- if( write( fd, mbuf->payload, mbuf->len ) < mbuf->len ) { // followed by the payload
- errors++;
+ if( (state = write( fd, header, hwlen )) != hwlen ) { // write exactly MCL_LEN_SIZE bytes from the buffer
+ drops++;
+ total_drops++;
chalk_error( fifo );
} else {
- chalk_ok( fifo );
- count++;
- total++;
+ if( write( fd, mbuf->payload, mbuf->len ) < mbuf->len ) { // followed by the payload
+ errors++;
+ chalk_error( fifo );
+ } else {
+ chalk_ok( fifo );
+ count++;
+ total++;
+ }
}
}
- }
- if( rdc_ctx != NULL ) {
- rdc_buf = rdc_init_buf( mbuf->mtype, header, hwlen, rdc_buf ); // set up for write
- rdc_write( rdc_ctx, rdc_buf, mbuf->payload, mbuf->len ); // write the raw data
+ if( rdc_ctx != NULL ) {
+ rdc_buf = rdc_init_buf( mbuf->mtype, header, hwlen, rdc_buf ); // set up for write
+ rdc_write( rdc_ctx, rdc_buf, mbuf->payload, mbuf->len ); // write the raw data
+ }
}
}
# Author: E. Scott Daniels
# -------------------------------------------------------------------------
+function abort_after {
+ touch /tmp/running
+ sleep ${1:-60}
+ if [[ -e /tmp/running ]]
+ then
+ echo "abort: unit test running too long"
+ kill -9 ${2:-bad-pid}
+ fi
+}
+
function setup_dirs {
mkdir -p /tmp/fifos
mkdir -p /tmp/mc_listener_test/final
exit
fi
+abort_after 60
if ! unit_test >/tmp/PID$$.utlog 2>&1
then
+ rm /tmp/running
cat /tmp/PID$$.utlog
rm -f /tmp/PID$$.*
purge_dirs
exit 1
fi
+rm /tmp/running
echo "[PASS] base unit tests all pass"
echo "[INFO] file/directory verification begins...."
*/
#include <rmr/rmr.h>
+#include <rmr/RIC_message_types.h>
-#define rmr_torcv_msg RMR_torcv_msg
+/*
+ The first call will generate a timeout for testing. All others will
+ succeed with a message.
+*/
extern rmr_mbuf_t* RMR_torcv_msg( void* ctx, rmr_mbuf_t* old_msg, int ms_to ) {
static int timeout = 0;
+ static int hcheck = 0;
if( old_msg == NULL ) {
old_msg = rmr_alloc_msg( ctx, 256 );
return old_msg;
}
+ if( !hcheck ) { // send one health check message
+ old_msg->mtype = RIC_HEALTH_CHECK_REQ;
+ old_msg->state = 0;
+ hcheck = 1;
+ return old_msg;
+ }
+
- snprintf( old_msg->payload, 100, "DUMMY MESSAGE" );
- old_msg->mtype = 100;
+ snprintf( old_msg->payload, rmr_payload_size( old_msg ), "DUMMY MESSAGE" );
+ old_msg->mtype = TEST_MTYPE;
old_msg->len = strlen( old_msg->payload );
old_msg->sub_id = -1;
old_msg->state = 0;
return old_msg;
}
+
+/*
+ Always successful if a message was passed in.
+*/
+extern rmr_mbuf_t* RMR_rts_msg( void* ctx, rmr_mbuf_t* msg ) {
+ if( msg != NULL ) {
+ msg->state = 0;
+ }
+
+ return msg;
+}
+
+/*
+ Generates "short" reads 9 out of 10 times so that we can
+ drive the buffer construction code that otherwise wouldn't
+ be driven since long reads are usually the case.
+*/
+extern int Read( int fd, char* dest, int max ) {
+ static int count = -1;
+
+ count++;
+
+ if( count % 10 ) {
+ return read( fd, dest, max ); // return long read
+ }
+
+ return read( fd, dest, 3 ); // short read
+}
+
+// ----------- defines that point included code here --------------------
+#define rmr_torcv_msg RMR_torcv_msg
+#define rmr_rts_msg RMR_rts_msg
+#define read Read
#include <sys/stat.h>
#include <sys/types.h>
+#define TEST_MTYPE 1000 // message type for testing
#include "test_rmr_em.c" // emulated rmr functions (for receives)
// this/these are what we are testing; include them directly (must be after forever def)
mcl_set_sigh(); // prevent colobber from broken pipe
- open_fifo( ctx, 100, WRITER ); // open dummy to prevent blocking reader
- rfd = open_fifo( ctx, 100, READER ); // open a reader to check fanout output
+ open_fifo( ctx, TEST_MTYPE, WRITER ); // open dummy to prevent blocking reader
+ rfd = open_fifo( ctx, TEST_MTYPE, READER ); // open a reader to check fanout output
if( rfd < 0 ) {
fprintf( stderr, "[FAIL] unable to open a pipe reader for type == 100\n" );
errors++;
}
- fd = suss_fifo( ctx, 100, 1, &fref ); // should open the file for writing and return the fdes
+ fd = suss_fifo( ctx, TEST_MTYPE, WRITER, &fref ); // should open the file for writing and return the fdes
if( fd < 0 ) {
fprintf( stderr, "[FAIL] suss_fifo did not return a valid fd\n" );
errors++;
chalk_error( fref );
}
- fd2= suss_fifo( ctx, 100, 0, NULL ); // should open the file file for reading and return a different fd
+ fd2= suss_fifo( ctx, TEST_MTYPE, 0, NULL ); // should open the file file for reading and return a different fd
if( fd < 0 ) {
fprintf( stderr, "[FAIL] suss_fifo did not return a valid fd\n" );
errors++;
mcl_start_listening( ctx, port, 0 ); // start the listener
- // under test, the forever keeps fanout from blocking; drive for each of two cases:
+ // under test, the FOREVER = 0 keeps fanout from blocking; drive several times to cover all cases
mcl_fifo_fanout( ctx, 5, 1 ); // first rmr receive call will simulate a timeout
- mcl_fifo_fanout( ctx, 5, 1 ); // second receive call simualtes a message arriving
- mcl_fifo_fanout( ctx, 5, 1 ); // another round so there are two to read
+ mcl_fifo_fanout( ctx, 5, 1 ); // second receive simulates a health check
+ mcl_fifo_fanout( ctx, 5, 1 ); // 3-n return alternating timeout messages; drive so that
+ mcl_fifo_fanout( ctx, 5, 1 ); // we will have several land in the FIFO
+ mcl_fifo_fanout( ctx, 5, 1 );
+ mcl_fifo_fanout( ctx, 5, 1 );
mcl_fifo_fanout( ctx, 5, 1 );
*timestamp = 0;
- state = mcl_fifo_read1( ctx, 100, payload, sizeof( payload ), TRUE );
+ state = mcl_fifo_read1( ctx, TEST_MTYPE, payload, sizeof( payload ), TRUE );
if( state < 1 ) {
fprintf( stderr, "[FAIL] fifo_read return positive value when expected to\n" );
errors++;
}
- state = mcl_fifo_tsread1( ctx, 100, payload, sizeof( payload ), TRUE, timestamp );
+ state = mcl_fifo_tsread1( ctx, TEST_MTYPE, payload, sizeof( payload ), TRUE, timestamp );
if( state < 1 ) {
fprintf( stderr, "[FAIL] fifo_read with timestamp return positive value when expected to\n" );
errors++;
}
- state = fifo_read1( NULL, 100, payload, sizeof( payload ), 1, timestamp ); // coverage error check
+ state = fifo_read1( NULL, TEST_MTYPE, payload, sizeof( payload ), 1, timestamp ); // coverage error check
if( state != 0 ) {
fprintf( stderr, "[FAIL] fifo_read didn't return 0 when given a nil context to\n" );
errors++;
}
fref = NULL;
- fd = suss_fifo( bad_ctx, 100, 1, &fref ); // should fail to open the file for writing beacuse directory is bad
+ fd = suss_fifo( bad_ctx, TEST_MTYPE, 1, &fref ); // should fail to open the file for writing beacuse directory is bad
if( fd >= 0 ) {
fprintf( stderr, "[FAIL] suss_fifo returned a valid fd when given a context with a bad directory path\n" );
errors++;
errors++;
}
- fd = suss_fifo( NULL, 100, 1, &fref ); // coverage nil pointer check
+ fd = suss_fifo( NULL, TEST_MTYPE, 1, &fref ); // coverage nil pointer check
if( fd >= 0 ) {
fprintf( stderr, "[FAIL] suss_fifo returned a valid fd when given a nil context a bad directory path\n" );
errors++;
build_hdr( 1024, wbuf, sizeof( wbuf ) );
bp = NULL;
- bp = rdc_init_buf( 100, wbuf, 10, bp ); // set up for write
+ bp = rdc_init_buf( TEST_MTYPE, wbuf, 10, bp ); // set up for write
rdc_write( ctx, bp, payload, sizeof( payload ) ); // write the raw data
fprintf( stderr, "[INFO] pausing to test rdc file rolling\n" );
sleep( 15 );
build_hdr( 1024, wbuf, sizeof( wbuf ) );
bp = NULL;
- bp = rdc_init_buf( 100, wbuf, 10, bp );
+ bp = rdc_init_buf( TEST_MTYPE, wbuf, 10, bp );
rdc_write( ctx, bp, payload, sizeof( payload ) );