From: E. Scott Daniels Date: Thu, 6 Jun 2019 16:21:24 +0000 (+0000) Subject: enhance(rtc): Tolerate missing newline in rtable X-Git-Tag: 1.0.31~3 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=dc30c39e83785bf75cd1e6cc89f7860cedf7b486;p=ric-plt%2Flib%2Frmr.git enhance(rtc): Tolerate missing newline in rtable If the final record in a static route table does not have a final newline (\n) this will be tolerated and the table will be parsed as if the newline was present. On some systems it is not possible for the user to control when a final newline is added (or not). Signed-off-by: E. Scott Daniels Change-Id: I5627bd2a0b59a628a20757428df7960149c8229b --- diff --git a/src/rmr/common/src/rt_generic_static.c b/src/rmr/common/src/rt_generic_static.c index 253e7ab..9b01100 100644 --- a/src/rmr/common/src/rt_generic_static.c +++ b/src/rmr/common/src/rt_generic_static.c @@ -153,6 +153,38 @@ static char* clip( char* buf ) { return buf; } +/* + This accepts a pointer to a nil terminated string, and ensures that there is a + newline as the last character. If there is not, a new buffer is allocated and + the newline is added. If a new buffer is allocated, the buffer passed in is + freed. The function returns a pointer which the caller should use, and must + free. In the event of an error, a nil pointer is returned. +*/ +static char* ensure_nlterm( char* buf ) { + char* nb = NULL; + int len = 1; + + + nb = buf; + if( buf == NULL || (len = strlen( buf )) < 2 ) { + if( (nb = (char *) malloc( sizeof( char ) * 2 )) != NULL ) { + *nb = '\n'; + *(nb+1) = 0; + } + } else { + if( buf[len-1] != '\n' ) { + fprintf( stderr, "[WARN] rmr buf_check: input buffer was not newline terminated (file missing final \\n?)\n" ); + if( (nb = (char *) malloc( sizeof( char ) * (len + 2) )) != NULL ) { + memcpy( nb, buf, len ); + *(nb+len) = '\n'; // insert \n and nil into the two extra bytes we allocated + *(nb+len+1) = 0; + free( buf ); + } + } + } + + return nb; +} /* Given a message type create a route table entry and add to the hash keyed on the @@ -489,7 +521,7 @@ static void read_static_rt( uta_ctx_t* ctx, int vlevel ) { return; } - if( (fbuf = uta_fib( fname ) ) == NULL ) { // read file into a single buffer (nil terminated string) + if( (fbuf = ensure_nlterm( uta_fib( fname ) ) ) == NULL ) { // read file into a single buffer (nil terminated string) fprintf( stderr, "[WRN] rmr read_static: seed route table could not be opened: %s: %s\n", fname, strerror( errno ) ); return; } @@ -507,7 +539,7 @@ static void read_static_rt( uta_ctx_t* ctx, int vlevel ) { *eor = 0; } else { fprintf( stderr, "[WARN] rmr read_static: seed route table had malformed records (missing newline): %s\n", fname ); - fprintf( stderr, "[WARN] rmr read_static: seed route table not used%s\n", fname ); + fprintf( stderr, "[WARN] rmr read_static: seed route table not used: %s\n", fname ); free( fbuf ); return; } diff --git a/test/sr_nano_static_test.c b/test/sr_nano_static_test.c index ef6e496..efeba23 100644 --- a/test/sr_nano_static_test.c +++ b/test/sr_nano_static_test.c @@ -82,6 +82,75 @@ static void gen_rt( uta_ctx_t* ctx ) { unlink( "utesting.rt" ); } +/* + Generates a legitimate table but with a missing newline on the last record. +*/ +static void gen_mlnl_rt( uta_ctx_t* ctx ) { + int fd; + char* rt_stuff; // strings for the route table + + rt_stuff = + "newrt|start\n" + "rte|0|localhost:4560,localhost:4562\n" // these are legitimate entries for our testing + "rte|1|localhost:4562;localhost:4561,localhost:4569\n" + "rte|2|localhost:4562| 10\n" // new subid at end + "mse|4|10|localhost:4561\n" // new msg/subid specifier rec + "mse|4|localhost:4561\n" // new mse entry with less than needed fields + " rte| 5 |localhost:4563 #garbage comment\n" // tests white space cleanup + "rte|6|localhost:4562\n" + "newrt|end"; // should not affect the loader + + fd = open( "utesting.rt", O_WRONLY | O_CREAT, 0600 ); + if( fd < 0 ) { + fprintf( stderr, " unable to open file for testing route table gen\n" ); + return; + } + + setenv( "RMR_SEED_RT", "utesting.rt", 1 ); + write( fd, rt_stuff, strlen( rt_stuff ) ); + close( fd ); + read_static_rt( ctx, 0 ); + unlink( "utesting.rt" ); +} + +/* + Generate an empty route table to test edge case. +*/ +static void gen_empty_rt( uta_ctx_t* ctx ) { + int fd; + + fd = open( "utesting.rt", O_WRONLY | O_CREAT | O_TRUNC, 0600 ); + if( fd < 0 ) { + fprintf( stderr, " unable to open file for testing route table gen\n" ); + return; + } + + setenv( "RMR_SEED_RT", "utesting.rt", 1 ); + //write( fd, "", 0 ); + close( fd ); + read_static_rt( ctx, 0 ); + unlink( "utesting.rt" ); +} + +/* + Generate an single byte route table to drive an edge handling case. +*/ +static void gen_sb_rt( uta_ctx_t* ctx ) { + int fd; + + fd = open( "utesting.rt", O_WRONLY | O_CREAT | O_TRUNC, 0600 ); + if( fd < 0 ) { + fprintf( stderr, " unable to open file for testing route table gen\n" ); + return; + } + + setenv( "RMR_SEED_RT", "utesting.rt", 1 ); + write( fd, " ", 1 ); + close( fd ); + read_static_rt( ctx, 0 ); + unlink( "utesting.rt" ); +} + /* Drive the send and receive functions. We also drive as much of the route @@ -118,8 +187,23 @@ static int sr_nano_test() { ctx->my_ip = strdup( "30.4.19.86:1111" ); uta_lookup_rtg( ctx ); + ctx->rtable = NULL; + gen_sb_rt( ctx ); // generate and read a file with a sinle byte to test edge case + errors += fail_not_nil( ctx->rtable, "read single byte route table produced a table" ); + + ctx->rtable = NULL; + gen_empty_rt( ctx ); // generate and read an empty rt file to test edge case + errors += fail_not_nil( ctx->rtable, "read empty route table file produced a table" ); + + ctx->rtable = NULL; + gen_mlnl_rt( ctx ); // ensure that a file with missing last new line does not trip us up + errors += fail_if_nil( ctx->rtable, "read route table file with missing last newline did not produce a table" ); + + ctx->rtable = NULL; gen_rt( ctx ); // forces a static load with some known info since we don't start the rtc() + errors += fail_if_nil( ctx->rtable, "read multi test route table file did not produce a table" ); gen_rt( ctx ); // force a second load to test cloning + errors += fail_if_nil( ctx->rtable, "read multi test route table file to test clone did not produce a table" ); p = rt_ensure_ep( NULL, "foo" ); // drive for coverage errors += fail_not_nil( p, "rt_ensure_ep did not return nil when given nil route table" );