Fix rmr_rpobe command line bug; add test coverage 05/4705/1
authorE. Scott Daniels <daniels@research.att.com>
Tue, 15 Sep 2020 14:27:34 +0000 (10:27 -0400)
committerE. Scott Daniels <daniels@research.att.com>
Tue, 15 Sep 2020 14:27:34 +0000 (10:27 -0400)
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 <daniels@research.att.com>
Change-Id: I5943bacf8d7434a7991781dba70b01bf5c16c67d

17 files changed:
CHANGES_CORE.txt
CMakeLists.txt
docs/rel-notes.rst
src/rmr/si/src/si95/sicbreg.c
src/rmr/si/src/si95/siestablish.c
src/rmr/si/src/si95/sigetadd.c
src/rmr/si/src/si95/sigetname.c
src/rmr/si/src/si95/sinewses.c
src/rmr/si/src/si95/sipoll.c
src/rmr/si/src/si95/siproto.h
src/rmr/si/src/si95/sisend.c
src/rmr/si/src/si95/sisendt.c
src/support/rmr_probe.c
test/logging_test.c
test/si95_test.c
test/test_support.c
test/test_transport_em.c

index 20fb7cc..c2aa178 100644 (file)
@@ -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)
index cef3e5d..94834ba 100644 (file)
@@ -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" )
index b38175f..a8d76f9 100644 (file)
@@ -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
 ----------------------------
 
index 9c7bba7..6428b1d 100644 (file)
@@ -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 ? 
index 49e484d..53c8db5 100644 (file)
 * 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, "<ERR> 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, "<ERR> 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, "<ERR> 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
                }
        }
index 06e6e31..cf2feea 100644 (file)
@@ -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 )
        {
index 04494eb..89cbdf7 100644 (file)
@@ -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;
index 6e439de..02a5e6d 100644 (file)
@@ -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
index 8c28977..c6a5cd5 100644 (file)
@@ -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
index dfe9447..93bdd7b 100644 (file)
@@ -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  );
index c0233ae..2652737 100644 (file)
 *  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 
+}
index 8a4d5f0..7935251 100644 (file)
@@ -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;
index f3d5858..6173299 100644 (file)
@@ -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;
 
index 4ef975e..be375a9 100644 (file)
 
 
 /*
-       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
 */
index fd6dd56..a33e334 100644 (file)
 
 #include <si95/siaddress.c>
 //#include <si95/sialloc.c>
-//#include <si95/sibldpoll.c>
-//#include <si95/sicbreg.c>
-//#include <si95/sicbstat.c>
-//#include <si95/siclose.c>
+#include <si95/sibldpoll.c>
+#include <si95/sicbreg.c>
+#include <si95/sicbstat.c>
+#include <si95/siclose.c>
 #include <si95/siconnect.c>
 #include <si95/siestablish.c>
-//#include <si95/sigetadd.c>
-//#include <si95/sigetname.c>
+#include <si95/sigetadd.c>
+#include <si95/sigetname.c>
 #include <si95/siinit.c>
 #include <si95/silisten.c>
 #include <si95/sinew.c>
-//#include <si95/sinewses.c>
+#include <si95/sinewses.c>
 //#include <si95/sipoll.c>
 //#include <si95/sircv.c>
 //#include <si95/sisend.c>
-//#include <si95/sisendt.c>
+#include <si95/sisendt.c>
 #include <si95/sishutdown.c>
 #include <si95/siterm.c>
 #include <si95/sitrash.c>
@@ -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, "<INFO> 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, "<INFO> cleanup has no context to use\n" );
                return 0;
        }
 
+       fprintf( stderr, "<INFO> 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, "<INFO> 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, "<INFO> 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, "<INFO> get address returns (%s)\n", buf );
+
+       fprintf( stderr, "<INFO> 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, "<INFO> 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, "<INFO> testing finished\n" );
+       fprintf( stderr, "<INFO> si95 tests finished (%d)\n", errors );
        if( errors == 0 ) {
                fprintf( stderr, "<PASS> all tests were OK\n\n" );
        } else {
index d14678b..a8309d9 100644 (file)
@@ -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, "<TESTING> %s %d\n", what, a==b );
        if( a == b ) {
                fprintf( stderr, "<FAIL> %s values were equal a=%d b=%d\n", what, a, b );
        }
index 92a6b93..afdebc3 100644 (file)
@@ -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, "<SYSTEM> 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, "<SYSTEM> 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