From: E. Scott Daniels Date: Tue, 15 Sep 2020 14:27:34 +0000 (-0400) Subject: Fix rmr_rpobe command line bug; add test coverage X-Git-Tag: 4.2.3~1 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=cc314e0c526a0ed0ce9295e490b3f2bb29c3332c;p=ric-plt%2Flib%2Frmr.git Fix rmr_rpobe command line bug; add test coverage This change corrects a deficency in the command line parsing of the rmr_probe support utility. It also adds unit test code to cover a significant portion of the SI95 code which was previously not covered. Commented out code in SI95 was also removed to reduce the sonar grumblings. Issue-ID: RIC-645 Signed-off-by: E. Scott Daniels Change-Id: I5943bacf8d7434a7991781dba70b01bf5c16c67d --- diff --git a/CHANGES_CORE.txt b/CHANGES_CORE.txt index 20fb7cc..c2aa178 100644 --- a/CHANGES_CORE.txt +++ b/CHANGES_CORE.txt @@ -5,6 +5,9 @@ # API and build change and fix summaries. Doc correctsions # and/or changes are not mentioned here; see the commit messages. +2020 September 15; Version 4.2.3 + Correct arg processing bug in rmr_rpobe (RIC-645) + 2020 August 4; Version 4.2.2 Correct bug in the rmr_probe support utility when -r option is used on the command line (RIC-644) diff --git a/CMakeLists.txt b/CMakeLists.txt index cef3e5d..94834ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,7 @@ cmake_minimum_required( VERSION 3.5 ) set( major_version "4" ) # should be automatically populated from git tag later, but until CI process sets a tag we use this set( minor_version "2" ) -set( patch_level "2" ) +set( patch_level "3" ) set( install_root "${CMAKE_INSTALL_PREFIX}" ) set( install_inc "include/rmr" ) diff --git a/docs/rel-notes.rst b/docs/rel-notes.rst index b38175f..a8d76f9 100644 --- a/docs/rel-notes.rst +++ b/docs/rel-notes.rst @@ -22,6 +22,13 @@ the need to leap frog versions ceased, and beginning with version 4.0.0, the RMR versions should no longer skip. +2020 September 15; Version 4.2.3 +-------------------------------- + +Correct arg processing bug in rmr_rpobe (RIC-645) + + + 2020 August 4; Version 4.2.2 ---------------------------- diff --git a/src/rmr/si/src/si95/sicbreg.c b/src/rmr/si/src/si95/sicbreg.c index 9c7bba7..6428b1d 100644 --- a/src/rmr/si/src/si95/sicbreg.c +++ b/src/rmr/si/src/si95/sicbreg.c @@ -40,7 +40,7 @@ extern void SIcbreg( struct ginfo_blk *gptr, int type, int ((*fptr)()), void * d if( gptr == NULL ) { rmr_vlog( RMR_VL_ERR, "SIcbreg -- gptr was nil\n" ); - exit( 1 ); + return; } if( gptr->magicnum == MAGICNUM ) { // valid block from user ? diff --git a/src/rmr/si/src/si95/siestablish.c b/src/rmr/si/src/si95/siestablish.c index 49e484d..53c8db5 100644 --- a/src/rmr/si/src/si95/siestablish.c +++ b/src/rmr/si/src/si95/siestablish.c @@ -25,10 +25,10 @@ * Mnemonic: SIestablish * Abstract:i Prep functions that set up a socket for listening or making a * connection. -* Date: 26 March 1995 -* Author: E. Scott Daniels +* Date: 26 March 1995 +* Author: E. Scott Daniels * -* Modified: 19 Apr 1995 - To keep returned address of the port. +* Modified: 19 Apr 1995 - To keep returned address of the port. * 08 Mar 2007 - conversion for ipv6. * 12 Oct 2020 - split into connect prep and listen prep * functions. @@ -66,8 +66,8 @@ */ extern struct tp_blk *SIlisten_prep( struct ginfo_blk *gptr, int type, char* abuf, int family ) { struct tp_blk *tptr; // pointer at new tp block - int status = SI_OK; // processing status - struct sockaddr *addr; // IP address we are requesting + int status = SI_OK; // processing status + struct sockaddr *addr; // IP address we are requesting int protocol; // protocol for socket call char buf[256]; // buffer to build request address in int optval = 0; @@ -107,21 +107,21 @@ extern struct tp_blk *SIlisten_prep( struct ginfo_blk *gptr, int type, char* abu status = BIND( tptr->fd, (struct sockaddr *) addr, alen ); if( status == SI_OK ) { - tptr->addr = addr; // save address + tptr->addr = addr; // save address } else { - fprintf( stderr, ">>>>> siestablish: bind failed: fam=%d type=%d pro=%d %s\n", tptr->family, tptr->type, protocol, strerror( errno ) ); + fprintf( stderr, " siestablish: bind failed: fam=%d type=%d pro=%d %s\n", tptr->family, tptr->type, protocol, strerror( errno ) ); close( tptr->fd ); } } else { - status = ! SI_OK; // force bad return later - fprintf( stderr, ">>>>> siestablish: socket not esablished: fam=%d type=%d pro=%d %s\n", tptr->family, tptr->type, protocol, strerror( errno ) ); + status = ! SI_OK; // force bad return later + fprintf( stderr, " siestablish: socket not esablished: fam=%d type=%d pro=%d %s\n", tptr->family, tptr->type, protocol, strerror( errno ) ); } - if( status != SI_OK ) { // socket or bind call failed - clean up stuff - fprintf( stderr, ">>>>> siestablish: bad state -- returning nil pointer\n" ); + if( status != SI_OK ) { // socket or bind call failed - clean up stuff + fprintf( stderr, " siestablish: bad state -- returning nil pointer\n" ); free( addr ); SItrash( TP_BLK, tptr ); // free the trasnsport block - tptr = NULL; // set to return nothing + tptr = NULL; // set to return nothing } } @@ -163,7 +163,7 @@ static int need_smartc( char* abuf ) { */ extern struct tp_blk *SIconn_prep( struct ginfo_blk *gptr, int type, char *abuf, int family ) { struct tp_blk *tptr; // pointer at new tp block - struct sockaddr *addr; // IP address we are requesting + struct sockaddr *addr; // IP address we are requesting int protocol; // protocol for socket call char buf[256]; // buffer to build request address in int optval = 0; @@ -189,10 +189,7 @@ extern struct tp_blk *SIconn_prep( struct ginfo_blk *gptr, int type, char *abuf, } alen = SIgenaddr( abuf, protocol, family, tptr->type, &addr ); // family == 0 for type that suits the address passed in - if( alen <= 0 ) - { - //fprintf( stderr, ">>>>> siconn_prep: error generating an address struct for %s(abuf) %d(proto) %d(type): %s\n", - // abuf, protocol, tptr->type, strerror( errno ) ); + if( alen <= 0 ) { return NULL; } @@ -222,7 +219,7 @@ extern struct tp_blk *SIconn_prep( struct ginfo_blk *gptr, int type, char *abuf, } } else { free( addr ); - SItrash( TP_BLK, tptr ); // free the trasnsport block + SItrash( TP_BLK, tptr ); // free the trasnsport block tptr = NULL; // we'll return nil } } diff --git a/src/rmr/si/src/si95/sigetadd.c b/src/rmr/si/src/si95/sigetadd.c index 06e6e31..cf2feea 100644 --- a/src/rmr/si/src/si95/sigetadd.c +++ b/src/rmr/si/src/si95/sigetadd.c @@ -41,8 +41,7 @@ extern int SIgetaddr( struct ginfo_blk *gptr, char *buf ) { int status = SI_ERROR; // return status char *ibuf; // SIaddr now points us at a string, rather than filling ours - for( tpptr = gptr->tplist; tpptr != NULL && !(tpptr->flags & TPF_LISTENFD); - tpptr = tpptr->next ); + for( tpptr = gptr->tplist; tpptr != NULL && !(tpptr->flags & TPF_LISTENFD); tpptr = tpptr->next ); if( tpptr != NULL ) { diff --git a/src/rmr/si/src/si95/sigetname.c b/src/rmr/si/src/si95/sigetname.c index 04494eb..89cbdf7 100644 --- a/src/rmr/si/src/si95/sigetname.c +++ b/src/rmr/si/src/si95/sigetname.c @@ -29,7 +29,7 @@ */ #include "sisetup.h" -extern char *sigetname( int sid ) { +extern char *SIgetname( int sid ) { struct sockaddr oaddr; // pointer to address in TCP binary format char *buf; int len; diff --git a/src/rmr/si/src/si95/sinewses.c b/src/rmr/si/src/si95/sinewses.c index 6e439de..02a5e6d 100644 --- a/src/rmr/si/src/si95/sinewses.c +++ b/src/rmr/si/src/si95/sinewses.c @@ -71,33 +71,28 @@ extern int SInewsession( struct ginfo_blk *gptr, struct tp_blk *tpptr ) { newtp->next->prev = newtp; // back chain to us } gptr->tplist = newtp; - newtp->paddr = (struct sockaddr *) addr; // partner address + newtp->paddr = (struct sockaddr *) addr; // partner address newtp->fd = status; // save the fd from accept - //fprintf( stderr, ">>>>> newsession: accepted session on fd %d\n", status ); - if( gptr->tcp_flags & SI_TF_NODELAY ) { + if( gptr->tcp_flags & SI_TF_NODELAY ) { // set on/off for no delay configuration optval = 1; } else { optval = 0; } - //fprintf( stderr, ">>>>> newsession: setting no delay = %d\n", optval ); - SETSOCKOPT( tpptr->fd, SOL_TCP, TCP_NODELAY, (void *)&optval, sizeof( optval) ) ; + SETSOCKOPT( tpptr->fd, SOL_TCP, TCP_NODELAY, (void *)&optval, sizeof( optval) ); - - if( gptr->tcp_flags & SI_TF_FASTACK ) { + if( gptr->tcp_flags & SI_TF_FASTACK ) { // set on/off for fast ack config optval = 1; } else { optval = 0; } - //fprintf( stderr, ">>>>> conn_prep: setting quick ack = %d\n", optval ); SETSOCKOPT( tpptr->fd, SOL_TCP, TCP_QUICKACK, (void *)&optval, sizeof( optval) ) ; SIaddress( addr, (void **) &buf, AC_TODOT ); // get addr of remote side if( (cbptr = gptr->cbtab[SI_CB_SECURITY].cbrtn) != NULL ) { // invoke the security callback function if there status = (*cbptr)( gptr->cbtab[SI_CB_SECURITY].cbdata, buf ); if( status == SI_RET_ERROR ) { // session to be rejected - SIterm( gptr, newtp ); // terminate new tp block - SItrash( TP_BLK, newtp ); + SIterm( gptr, newtp ); // terminate new tp block (do NOT call trash) free( addr ); free( buf ); return SI_ERROR; @@ -108,7 +103,6 @@ extern int SInewsession( struct ginfo_blk *gptr, struct tp_blk *tpptr ) { newtp->flags |= TPF_SESSION; // indicate a session here - //fprintf( stderr, ">>>> pending connection callback for: %s\n", buf ); if( (cbptr = gptr->cbtab[SI_CB_CONN].cbrtn) != NULL ) { // drive connection callback status=(*cbptr)( gptr->cbtab[SI_CB_CONN].cbdata, newtp->fd, buf ); SIcbstat( gptr, status, SI_CB_CONN ); // handle status diff --git a/src/rmr/si/src/si95/sipoll.c b/src/rmr/si/src/si95/sipoll.c index 8c28977..c6a5cd5 100644 --- a/src/rmr/si/src/si95/sipoll.c +++ b/src/rmr/si/src/si95/sipoll.c @@ -81,32 +81,8 @@ extern int SIpoll( struct ginfo_blk *gptr, int msdelay ) { // poll fail or termination signal rcvd gptr->fdcount = 0; // prevent trying to look at a session gptr->flags |= GIF_SHUTDOWN; // cause cleanup and exit at end - //deaths = 0; // dont need to issue waits on dead child - //sigflags = 0; // who cares about signals now too } -/* - while( deaths > 0 ) // there have been death(s) - keep the dead - { // from being zombies - send them to heaven - wait( NULL ); // issue wait on child - deaths--; - } // end while dead children to send to heaven -*/ - -/* - if( sigflags && // if signal received and processing them - (cbptr = gptr->cbtab[SI_CB_SIGNAL].cbrtn) != NULL ) - { - while( sigflags != 0 ) - { - i = sigflags; // hold for call - sigflags = 0; // incase we are interrupted while away - status = (*cbptr)( gptr->cbtab[SI_CB_SIGNAL].cbdata, i ); - SIcbstat( gptr, status, SI_CB_SIGNAL ); // handle status - } // end while - } -*/ - if( pstat > 0 && (! (gptr->flags & GIF_SHUTDOWN)) ) { if( FD_ISSET( 0, &gptr->readfds ) ) // check for keybd input @@ -119,7 +95,6 @@ extern int SIpoll( struct ginfo_blk *gptr, int msdelay ) } // end if call back was defined } - // for( tpptr = gptr->tplist; tpptr != NULL; tpptr = tpptr->next ) tpptr = gptr->tplist; while( tpptr != NULL ) { nextone = tpptr->next; // allow for a delete in loop diff --git a/src/rmr/si/src/si95/siproto.h b/src/rmr/si/src/si95/siproto.h index dfe9447..93bdd7b 100644 --- a/src/rmr/si/src/si95/siproto.h +++ b/src/rmr/si/src/si95/siproto.h @@ -35,7 +35,7 @@ extern void siabort_conn( int fd ); // use by applications discouraged extern void *SInew( int type ); -extern char *sigetname( int sid ); +extern char *SIgetname( int sid ); extern void SIabort( struct ginfo_blk *gptr ); extern int SIaddress( void *src, void **dest, int type ); extern void SIbldpoll( struct ginfo_blk* gptr ); diff --git a/src/rmr/si/src/si95/sisend.c b/src/rmr/si/src/si95/sisend.c index c0233ae..2652737 100644 --- a/src/rmr/si/src/si95/sisend.c +++ b/src/rmr/si/src/si95/sisend.c @@ -35,44 +35,34 @@ * Returns: Nothing. * Date: 27 March 1995 * Author: E. Scott Daniels -* Mod: 22 Feb 2002 - To support sendqueue tail +* Mod: 22 Feb 2002 - To support sendqueue tail * ****************************************************************************** */ -#include "sisetup.h" // get include files etc +#include "sisetup.h" // get include files etc #include "sitransport.h" extern void SIsend( struct ginfo_blk *gptr, struct tp_blk *tpptr ) { - struct t_unitdata *udata; // pointer at UDP unit data - struct ioq_blk *qptr; // pointer at qio block for free + struct t_unitdata *udata; // pointer at UDP unit data + struct ioq_blk *qptr; // pointer at qio block for free int status; - if( tpptr->squeue == NULL ) // who knows why we were called - return; // nothing queued - just leave - -/* - if( tpptr->type == SOCK_DGRAM ) { // udp send? - sendto( tpptr->fd, tpptr->squeue->data, tpptr->squeue->dlen, 0, tpptr->squeue->addr, sizeof( struct sockaddr ) ); - if( tpptr->squeue->addr != NULL ) - free( tpptr->squeue->data ); - tpptr->squeue->addr = NULL; - } else { -*/ - status= SEND( tpptr->fd, tpptr->squeue->data, tpptr->squeue->dlen, 0 ); -/* + if( tpptr->squeue == NULL ) { // who knows why we were called + return; // nothing queued - just leave } -*/ - free( tpptr->squeue->data ); // trash buffer or the udp block - qptr = tpptr->squeue; // hold pointer for free - tpptr->squeue = tpptr->squeue->next; // next in queue becommes head - if( !tpptr->squeue ) - tpptr->sqtail = NULL; // no tail left either + status= SEND( tpptr->fd, tpptr->squeue->data, tpptr->squeue->dlen, 0 ); + + free( tpptr->squeue->data ); // trash buffer or the udp block + qptr = tpptr->squeue; // hold pointer for free + tpptr->squeue = tpptr->squeue->next; // next in queue becommes head + if( !tpptr->squeue ) { + tpptr->sqtail = NULL; // no tail left either + } free( qptr ); - if( (tpptr->flags & TPF_DRAIN) && tpptr->squeue == NULL ) // done w/ drain? - { + if( (tpptr->flags & TPF_DRAIN) && tpptr->squeue == NULL ) { // done w/ drain? SIterm( gptr, tpptr ); // close the session and mark the block for delte } -} // SIsend +} diff --git a/src/rmr/si/src/si95/sisendt.c b/src/rmr/si/src/si95/sisendt.c index 8a4d5f0..7935251 100644 --- a/src/rmr/si/src/si95/sisendt.c +++ b/src/rmr/si/src/si95/sisendt.c @@ -66,9 +66,8 @@ extern int SIsendt( struct ginfo_blk *gptr, int fd, char *ubuf, int ulen ) { tpptr = gptr->tp_map[fd]; } else { // list should be locked before traversing - for( tpptr = gptr->tplist; tpptr != NULL && tpptr->fd != fd; tpptr = tpptr->next ); // find the block if out of map's range + for( tpptr = gptr->tplist; tpptr != NULL && tpptr->fd != fd; tpptr = tpptr->next ) ; // find the block if out of map's range } - if( tpptr != NULL ) { if( (fd = tpptr->fd) < 0 ) { // fd user given might not be real, and this might be closed already errno = EBADFD; diff --git a/src/support/rmr_probe.c b/src/support/rmr_probe.c index f3d5858..6173299 100644 --- a/src/support/rmr_probe.c +++ b/src/support/rmr_probe.c @@ -124,6 +124,20 @@ static void usage( char* arg0 ) { "\t-v enables some amount of extra verbose output to stderr\n", arg0 ); } +/* + This validates the arg index is in range (< argc). If it is not + valid, the a message is issued and we abort. +*/ +static void vet_ai( int ai, int argc, char* arg0 ) { + if( ai < argc && ai > 0 ) { + return; + } + + fprintf( stderr, "abort: command line parameter(s) missing\n" ); + usage( arg0 ); + exit( 1 ); +} + int main( int argc, char** argv ) { int ai = 1; // arg index int i; @@ -155,16 +169,19 @@ int main( int argc, char** argv ) { switch( argv[ai][1] ) { case 'h': // host:port ai++; + vet_ai( ai, argc, argv[0] ); target = strdup( argv[ai] ); break; case 'n': // num to send ai++; + vet_ai( ai, argc, argv[0] ); num2send = atoi( argv[ai] ); break; case 'p': // num to send ai++; + vet_ai( ai, argc, argv[0] ); listen_port = strdup( argv[ai] ); break; @@ -174,6 +191,7 @@ int main( int argc, char** argv ) { case 't': // timeout ai++; + vet_ai( ai, argc, argv[0] ); max_timeout = atoi( argv[ai] ); break; diff --git a/test/logging_test.c b/test/logging_test.c index 4ef975e..be375a9 100644 --- a/test/logging_test.c +++ b/test/logging_test.c @@ -20,10 +20,8 @@ /* - Mnemonic: symtab_test.c - Abstract: This is the unit test module that will drive tests against - the symbol table portion of RMr. Run with: - ksh unit_test.ksh symtab_test.c + Mnemonic: logging_test.c + Abstract: This test drives logging related tests. Date: 1 April 2019 Author: E. Scott Daniels */ diff --git a/test/si95_test.c b/test/si95_test.c index fd6dd56..a33e334 100644 --- a/test/si95_test.c +++ b/test/si95_test.c @@ -76,22 +76,22 @@ #include //#include -//#include -//#include -//#include -//#include +#include +#include +#include +#include #include #include -//#include -//#include +#include +#include #include #include #include -//#include +#include //#include //#include //#include -//#include +#include #include #include #include @@ -103,6 +103,20 @@ void* si_ctx = NULL; // a global context might be useful // --------------------------------------------------------------------- +/* + Fake callback to register. +*/ +static int test_cb( void* data ) { + return 0; +} + +/* + Returns error for coverage testing of CB calls +*/ +static int test_cb_err( void* data ) { + return -1; +} + /* Memory allocation/free related tests */ @@ -132,11 +146,10 @@ static int memory( ) { errors += fail_if_nil( ptr, "memory: sinew returned nil when given giblk request" ); SItrash( GI_BLK, ptr ); // GI block cannot be trashed, ensure this (valgind will complain about a leak) - + fprintf( stderr, " memory module finished with %d errors\n", errors ); return errors; } - /* Test initialisation related things */ @@ -157,9 +170,14 @@ static int cleanup() { int errors = 0; if( ! si_ctx ) { + fprintf( stderr, " cleanup has no context to use\n" ); return 0; } + fprintf( stderr, " cleanup running\n" ); + SIcbstat( si_ctx, SI_RET_UNREG, SI_CB_SECURITY ); + SIcbstat( si_ctx, SI_RET_QUIT, SI_CB_SECURITY ); + SItp_stats( si_ctx ); // drive for coverage only SItp_stats( NULL ); @@ -208,7 +226,6 @@ static int addr() { fprintf( stderr, " addr module finished with %d errors\n", errors ); return errors; - } @@ -218,6 +235,8 @@ static int addr() { static int conn( ) { int errors = 0; int state; + int cfd = 3; // fd for close + char* buf; state = SIconnect( si_ctx, "localhost:4567" ); // driver regular connect errors += fail_if_true( state < 0, "connect to low port failed" ); @@ -225,16 +244,16 @@ static int conn( ) { state = SIconnect( si_ctx, "localhost:43086" ); // drive save connect with good return code errors += fail_if_true( state < 0, "connect to high port failed" ); - tpem_set_addr_dup_state( 1 ); // force get sockket name emulation to return a duplicate address + tpem_set_addr_dup_state( 1 ); // force get sockket name emulation to return a duplicate address state = SIconnect( si_ctx, "localhost:43086" ); // drive save connect with good return code errors += fail_if_true( state >= 0, "forced dup connect did not return error" ); - tpem_set_addr_dup_state( 0 ); // force get sockket name emulation to return a duplicate address + tpem_set_addr_dup_state( 0 ); // back to normal tpem_set_conn_state( 1 ); state = SIconnect( si_ctx, "localhost:4567" ); // driver regular connect errors += fail_if_true( state >= 0, "connect to low port successful when failure expected" ); - tpem_set_sock_state( 1 ); // make scoket calls fail + tpem_set_sock_state( 1 ); // make scoket calls fail state = SIconnect( si_ctx, "localhost:4567" ); // driver regular connect errors += fail_if_true( state >= 0, "connect to low port successful when socket based failure expected" ); @@ -248,11 +267,123 @@ static int conn( ) { errors += fail_if_true( state >= 0, "listen successful when bind error set" ); tpem_set_bind_state( 0 ); + SIbldpoll( si_ctx ); // for coverage. no return value and nothing we can check + + state = SIclose( NULL, 0 ); //coverage + errors += fail_if_true( state != SI_ERROR, "close given nil context returned success" ); + + state = SIclose( si_ctx, cfd ); + errors += fail_if_true( state == SI_ERROR, "close given good context and good fd returned error" ); + + state = SIclose( si_ctx, 5000 ); // out of range fd + errors += fail_if_true( state != SI_ERROR, "close given good context and bad fd returned success" ); + + state = SIclose( si_ctx, TCP_LISTEN_PORT ); // close listener + errors += fail_if_true( state == SI_ERROR, "close given good context and listener fd returned error" ); + + state = SIclose( si_ctx, UDP_PORT ); // close first open udp port (should not be there) + errors += fail_if_true( state != SI_ERROR, "close given good context and udp generic fd returned error" ); + + buf = SIgetname( 3 ); + if( fail_if_true( buf == NULL, "get name failed to return a buffer" ) ) { + errors++; + } else { + errors += fail_if_true( buf[0] == 0, "get name returned buf with emtpy string" ); + } fprintf( stderr, " conn module finished with %d errors\n", errors ); return errors; } +/* + Misc tests that just don't fit in another bucket. +*/ +static int misc( ) { + int errors = 0; + char buf[1024]; + + SIcbreg( NULL, SI_CB_SECURITY, test_cb, NULL ); // coverage only, no return value no verification + SIcbreg( si_ctx, SI_CB_SECURITY, test_cb, NULL ); + + buf[0] = 0; + SIgetaddr( si_ctx, buf ); + errors += fail_if_true( buf[0] == 0, "get address failed" ); + fprintf( stderr, " get address returns (%s)\n", buf ); + + fprintf( stderr, " misc module finished with %d errors\n", errors ); + return errors; +} + + +/* + New session (accept) testing. +*/ +static int new_sess( ) { + int errors = 0; + char buf[1024]; + struct tp_blk *tpptr; + int status; + + tpptr = SInew( TP_BLK ); + tpptr->fd = 3; + tpptr->flags |= TPF_LISTENFD; + + tpem_set_accept_fd( -1 ); // accept will "fail" for coverage + status = SInewsession( si_ctx, tpptr ); + errors += fail_if_true( status != SI_ERROR, "newsession did not fail when accept fails" ); + + tpem_set_accept_fd( 5 ); // accept will return a good fd + SIcbreg( si_ctx, SI_CB_SECURITY, test_cb_err, NULL ); // register error and drive new session for error coverage + status = SInewsession( si_ctx, tpptr ); + errors += fail_if_true( status >= 0, "newsession did failed when accept was good" ); + + tpem_set_accept_fd( 6 ); // accept will return a good fd + SIset_tflags( si_ctx, SI_TF_NODELAY | SI_TF_FASTACK ); // flip options for coverage in new sess + SIcbreg( si_ctx, SI_CB_CONN, test_cb, NULL ); // drive connection for coverage + SIcbreg( si_ctx, SI_CB_SECURITY, test_cb, NULL ); + status = SInewsession( si_ctx, tpptr ); + errors += fail_if_true( status < 0, "newsession did failed when accept was good" ); + + fprintf( stderr, " new_sess module finished with %d errors\n", errors ); + return errors; +} + +/* + Send tests +*/ +static int send_tests( ) { + int errors = 0; + char buf[1024]; + int len; + int state; + + len = snprintf( buf, 100, "Heaven knows I'm miserable now!" ); + + state = SIsendt( si_ctx, 9999, buf, len ); + errors += fail_if_true( state >= 0, "send given fd out of range did not fail" ); + + state = SIsendt( si_ctx, -1, buf, len ); + errors += fail_if_true( state >= 0, "send given neg fd did not fail" ); + + SIsendt( si_ctx, 6, buf, len ); + + tpem_set_send_err( 99 ); + SIsendt( si_ctx, 6, buf, len ); + + tpem_set_send_err( 0 ); + tpem_set_sel_blk( 1 ); + SIsendt( si_ctx, 6, buf, len ); + + tpem_set_sel_blk( 0 ); + tpem_set_selef_fd( 6 ); // will cause send to fail and fd6 to close + SIsendt( si_ctx, 6, buf, len ); + + return errors; +} + + +// ---------------------------------------------------------------------------------------- + /* Drive tests... */ @@ -267,9 +398,14 @@ int main() { errors += memory(); errors += addr(); errors += conn(); + errors += misc(); + + errors += new_sess(); // should leave a "connected" session at fd == 6 + errors += send_tests(); + errors += cleanup(); - fprintf( stderr, " testing finished\n" ); + fprintf( stderr, " si95 tests finished (%d)\n", errors ); if( errors == 0 ) { fprintf( stderr, " all tests were OK\n\n" ); } else { diff --git a/test/test_support.c b/test/test_support.c index d14678b..a8309d9 100644 --- a/test/test_support.c +++ b/test/test_support.c @@ -159,6 +159,7 @@ static int fail_not_equal( int a, int b, char* what ) { } static int fail_if_equal( int a, int b, char* what ) { + fprintf( stderr, " %s %d\n", what, a==b ); if( a == b ) { fprintf( stderr, " %s values were equal a=%d b=%d\n", what, a, b ); } diff --git a/test/test_transport_em.c b/test/test_transport_em.c index 92a6b93..afdebc3 100644 --- a/test/test_transport_em.c +++ b/test/test_transport_em.c @@ -39,11 +39,15 @@ int tpem_conn_state = 0; // states returned by emulated functions allowing fail int tpem_sock_state = 0; int tpem_listen_state = 0; int tpem_bind_state = 0; +int tpem_accept_fd = 5; // file desc returned by accept +int tpem_sel_ef = -1; // select sets this fd's error if >= 0 +int tpem_sel_block = 0; // set if select call inidcates would block +int tpem_send_err = 0; // set to cause send to return error // ------------ emulation control ------------------------------------------- /* - All test prog to set various things + Allow test prog to set various things */ static void tpem_set_conn_state( int s ) { tpem_conn_state = s; @@ -61,6 +65,22 @@ static void tpem_set_bind_state( int s ) { tpem_bind_state = s; } +static void tpem_set_accept_fd( int s ) { + tpem_accept_fd = s; +} + +static void tpem_set_selef_fd( int s ) { + tpem_sel_ef = s; +} + +static void tpem_set_sel_blk( int s ) { + tpem_sel_block = s; +} + +static void tpem_set_send_err( int s ) { + tpem_send_err = s; +} + // ---- emulated functions --------------------------------------------------- static int tpem_bind( int socket, struct sockaddr* addr, socklen_t alen ) { @@ -114,6 +134,43 @@ static int tpem_socket( int domain, int type, int protocol ) { return -1; } +static int tpem_accept( int socket, struct sockaddr *restrict address, socklen_t *restrict address_len) { + return tpem_accept_fd; +} + +/* + Emulate a select. If tpem_sel_ef is set, then the error fd set for the fd is set to true. + If sel_woudl_block is set, then the select returns blocking +*/ +static int tpem_select( int fd_count, fd_set* rf, fd_set* wf, fd_set* ef, void* time ) { + fprintf( stderr, " select returns %d (1==no-block)\n", tpem_sel_block ? -1 : 1 ); + + if( tpem_sel_block ) { + return -1; + } + + if( tpem_sel_ef >= 0 ) { + FD_SET( tpem_sel_ef, ef ); + } else { + FD_ZERO( ef ); + } + + return 1; +} + +/* + If tpem_send_err is set, we return less than count; +*/ +static int tpem_send( int fd, void* buf, int count, int flags ) { + errno = tpem_send_err; + + fprintf( stderr, " send on fd=%d for %d bytes ret=%d\n", fd, count, tpem_send_err ? -1 : count ); + return tpem_send_err ? -1 : count; +} + + +// --------------------------------------------------------------------------------------- + /* redefine all system calls to reference functions here. There are two defs SI functions should use the capitalised verision so that sliding ff under @@ -129,19 +186,22 @@ static int tpem_socket( int domain, int type, int protocol ) { #define socket tpem_socket #define LISTEN tpem_listen #define listen tpem_listen +#define accept tpem_accept +#define ACCEPT tpem_accept +#define SEND tpem_send +#define SELECT tpem_select +#define select tpem_select /* these are defined in SI so that we can use the system stack or FFstack they must exist and reference system calls if not defined above. */ -#define ACCEPT accept #define CLOSE close #define SHUTDOWN shutdown #define GETSOCKOPT getscokopt #define SETSOCKOPT setsockopt #define READ read #define WRITE write -#define SEND send #define SENDTO sendto #define RECV recv #define RECVFROM recvfrom