# API and build change and fix summaries. Doc corrections
# and/or changes are not mentioned here; see the commit messages.
+2022 January 7; version 4.8.1
+ Re-enables RMR libary's module tests (RIC-861).
+ Creates a new unit test for the debugging rmr rx queue API.
+ Fixes some bugs and possible memory likeage in SI95 code.
+
2021 December 2; version 4.8.0
Fixing memory leak in python support function (RIC-858).
New API added for debugging rmr rx queue (RIC-838).
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 "8" )
-set( patch_level "0" )
+set( patch_level "1" )
set( install_root "${CMAKE_INSTALL_PREFIX}" )
set( install_inc "include/rmr" )
version 4.0.0, the RMR versions should no longer skip.
+2022 January 7; version 4.8.1
+------------------------------
+
+Re-enables RMR libary's module tests (RIC-861).
+Creates a new unit test for the debugging rmr rx queue API.
+Fixes some bugs and possible memory likeage in SI95 code.
+
+
+
2021 December 2; version 4.8.0
------------------------------
*/
extern int rmr_get_rx_debug_info(void *vctx, rmr_rx_debug_t *rx_debug) {
uta_ctx_t *ctx;
- if ((ctx = (uta_ctx_t *)vctx) == NULL) {
+ if ((ctx = (uta_ctx_t *)vctx) == NULL || rx_debug == NULL ) {
errno = EINVAL;
return EINVAL;
}
* hostent structure. It claims that h_addr_list is a pointer
* to character pointers, but it is really a pointer to a list
* of pointers to integers!!!
-*
+*
***************************************************************************
*/
#include "sisetup.h" // get necessary defs and other stuff
(int) ntohs( addr6->sin6_port ) );
} else {
num = (char *) &addr->sin_addr.s_addr; // point at the long
- snprintf( wbuf, sizeof( wbuf ), "%u.%u.%u.%u;%d", *(num+0), *(num+1), *(num+2), *(num+3), (int) ntohs(addr->sin_port) );
+ snprintf( wbuf, sizeof( wbuf ), "%u.%u.%u.%u:%d", *(num+0), *(num+1), *(num+2), *(num+3), (int) ntohs(addr->sin_port) );
}
*dest = (void *) strdup( wbuf );
if( addr != NULL ) {
free( addr ); // not needed, but scanners complain if we don't overtly do this
}
+ free( tptr );
return NULL;
}
if( addr != NULL ) { // not needed, but scanners complain if we don't overtly do this
free( addr );
}
+ free( tptr );
return NULL;
}
**************************************************************************
* Mnemonic: SIinitialise
* Abstract: Initialisation and other context management functions.
-*
+*
* Date: 26 March 1995
* Author: E. Scott Daniels
*
-* Mod: 17 FEB 2002 - To convert to a globally managed gpointer
-* 09 Mar 2007 - To allow for ipv6 (added SIinitialise() to
+* Mod: 17 FEB 2002 - To convert to a globally managed gpointer
+* 09 Mar 2007 - To allow for ipv6 (added SIinitialise() to
* replace SIinit())
**************************************************************************
*/
-#include "sisetup.h" // get the setup stuff
+#include "sisetup.h" // get the setup stuff
/*
Initialise the SI environment. Specifically:
*/
extern struct ginfo_blk* SIinitialise( int opts )
{
- struct ginfo_blk *gptr = NULL; // pointer at gen info blk
- int status = SI_OK; // status of internal processing
- struct tp_blk *tpptr; // pointer at tp stuff
- struct sigaction sact; // signal action block
- int i; // loop index
- int signals = SI_DEF_SIGS; // signals to be set in SIsetsig
+ struct ginfo_blk *gptr = NULL; // pointer at gen info blk
+ int status = SI_OK; // status of internal processing
+ struct tp_blk *tpptr; // pointer at tp stuff
+ struct sigaction sact; // signal action block
+ int i; // loop index
+ int signals = SI_DEF_SIGS; // signals to be set in SIsetsig
errno = ENOMEM;
gptr->cbtab = (struct callback_blk *) malloc(
(sizeof( struct callback_blk ) * MAX_CBS ) );
if( gptr->cbtab != NULL ) {
- for( i = 0; i < MAX_CBS; i++ ) { // initialize callback table
- gptr->cbtab[i].cbdata = NULL; // no data and no functions
+ for( i = 0; i < MAX_CBS; i++ ) { // initialize callback table
+ gptr->cbtab[i].cbdata = NULL; // no data and no functions
gptr->cbtab[i].cbrtn = NULL;
}
- } else { // if call back table allocation failed - error off
- SIshutdown( gptr ); // clean up any open fds
+ } else { // if call back table allocation failed - error off
+ SIshutdown( gptr ); // clean up any open fds
+ free( gptr->tp_map );
free( gptr );
- gptr = NULL; // dont allow them to continue
+ gptr = NULL; // dont allow them to continue
}
- } // end if gen infor block allocated successfully
+ } // end if gen infor block allocated successfully
+
-
memset( &sact, 0, sizeof( sact ) );
sact.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &sact, NULL ); // ignore pipe signals as for some bloody reason linux sets this off if write to closed socket
- return gptr; // all's well that ends well
-}
+ return gptr; // all's well that ends well
+}
/*
This will set all of the tcp oriented flags in mask (SI_TF_* constants).
addr = (struct sockaddr *) malloc( sizeof( struct sockaddr ) );
addrlen = sizeof( struct sockaddr );
+ memset( addr, 0, sizeof( struct sockaddr ) );
status = accept( tpptr->fd, addr, &addrlen ); // accept and assign new fd (status)
if( status < 0 ) {
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 (do NOT call trash)
- free( addr );
+ // free( addr ); // not required, will be eventually freed by SItrash
free( buf );
return SI_ERROR;
} else {
/*
***************************************************************************
-*
+*
* Mnemonic: sitrash
* Abstract: Delete all things referenced by a struct and then free the memory.
-*
+*
* Returns: Nothing
* Date: 08 March 2007
-* Author: E. Scott Daniels
+* Author: E. Scott Daniels
*
-******************************************************************************
+******************************************************************************
*/
#include "sisetup.h"
#include "sitransport.h"
-
+
extern void SItrash( int type, void *bp )
{
struct tp_blk *tp = NULL;
free( iptr->addr );
free( iptr );
break;
-
- case TP_BLK: // we assume its off the list
+
+ case TP_BLK: // we assume its off the list
tp = (struct tp_blk *) bp;
- iptr = tp->squeue;
+ iptr = tp->squeue;
while( iptr != NULL ) {
inext = iptr->next;
- free( iptr->data ); // we could recurse, but that seems silly
+ free( iptr->data ); // we could recurse, but that seems silly
free( iptr->addr );
free( iptr );
if( tp->fd >= 0 ) {
CLOSE( tp->fd );
}
-
- free( tp->addr ); // release the address bufers
- free( tp->paddr );
- free( tp ); // and release the block
+
+ free( tp->addr ); // release the address bufers
+ free( tp->paddr );
+ free( tp ); // and release the block
break;
}
}
struct tp_blk *nextone= NULL; // point at next block to process in loop
int pstat = 0; // poll status
struct timeval timeout; // delay to use on select call
- char *buf = NULL;
- char *ibuf = NULL;
if( gptr->magicnum != MAGICNUM ) { // if not a valid ginfo block
rmr_vlog( RMR_VL_CRIT, "SI95: wait: bad global info struct magic number is wrong\n" );
return SI_ERROR; // so just get out
}
- if( ( ibuf = (char *) malloc( 2048 ) ) == NULL ) {
- rmr_vlog( RMR_VL_WARN, "ibuf malloc fail\n" );
- return SI_ERROR;
- }
-
do { // spin until a callback says to stop (likely never)
timeout.tv_sec = 0; // must be reset on every call!
timeout.tv_usec = SI_SELECT_TIMEOUT;
}
} while( gptr->tplist != NULL && !(gptr->flags & GIF_SHUTDOWN) );
- free( ibuf );
if( gptr->tplist == NULL ) // indicate all fds closed
if( gptr->flags & GIF_SHUTDOWN ) { // we need to stop for some reason
--- /dev/null
+// vim: ts=4 sw=4 noet
+/*
+==================================================================================
+ Copyright (c) 2021 Alexandre Huff (UTFPR).
+
+ 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: rmr_debug_si_test.c
+ Abstract: This is the main driver to test the si95 debug functions
+
+ Date: 24 December 2021
+ Author: Alexandre Huff
+*/
+#include <netdb.h>
+#include <errno.h>
+
+#define DEBUG 1
+#undef NNG_UNDER_TEST // NNG is NOT under test so undefine if set
+#define NO_EMULATION 1 // no emulation of transport functions
+
+#include "rmr.h"
+#include "rmr_agnostic.h"
+
+#include "si95/socket_if.h"
+#undef uta_ctx_t
+#include "rmr_si_private.h"
+
+#include "test_support.c" // things like fail_if()
+
+#include "rmr_debug_si.c" // api under test
+
+
+
+
+// ------------- dummy functions to force edge cases when we can ---------------------------------------
+
+#define SYSTEM_UNDER_TEST 1 // for conditional code
+
+
+// ----------------------------------------------------------------------------------------
+
+static int get_debug_info_test( uta_ctx_t *ctx ) {
+ int errors = 0;
+ int ret;
+ rmr_rx_debug_t info;
+
+ ctx->acc_dcount = 5; // dummy info
+ ctx->acc_ecount = 10;
+
+ // argument related things
+ ret = rmr_get_rx_debug_info( NULL, &info );
+ errors += fail_not_equal( EINVAL, errno, "get_debug_info_test: rmr_get_rx_debug_info did not set errno to EINVAL on nil global context" );
+ errors += fail_if_equal( 0, ret, "get_debug_info_test: rmr_get_rx_debug_info returned 0 on error" );
+
+ errno = 0;
+ ret = rmr_get_rx_debug_info( ctx, NULL );
+ errors += fail_not_equal( EINVAL, errno, "get_debug_info_test: rmr_get_rx_debug_info did not set errno to EINVAL on nil info struct" );
+ errors += fail_if_equal( 0, ret, "get_debug_info_test: rmr_get_rx_debug_info returned 0 on error" );
+
+ // test rx debug struct values
+ ret = rmr_get_rx_debug_info( ctx, &info );
+ errors += fail_not_equal( 0, ret, "get_debug_info_test: rmr_get_rx_debug_info did not return 0 on success" );
+ errors += fail_not_equal( 5, ctx->acc_dcount, "get_debug_info_test: rmr_get_rx_debug_info unexpected acc_dcount value in info struct" );
+ errors += fail_not_equal( 10, ctx->acc_ecount, "get_debug_info_test: rmr_get_rx_debug_info unexpected acc_ecount value in info struct" );
+
+ fprintf( stderr, "<INFO> get_debug_info_test finished with %d errors\n", errors );
+
+ return errors;
+}
+
+static int reset_debug_test(uta_ctx_t *ctx) {
+ int errors = 0;
+ int ret;
+
+ ctx->acc_dcount = 5; // dummy info
+ ctx->acc_ecount = 10;
+
+ ret = rmr_reset_rx_debug_count( NULL ); // expect to fail
+ errors += fail_not_equal( EINVAL, errno, "reset_debug_test: rmr_reset_rx_debug_count did not set errno to EINVAL on error" );
+ errors += fail_if_equal( 0, ret, "reset_debug_test: rmr_reset_rx_debug_count returned 0 on error" );
+
+ ret = rmr_reset_rx_debug_count( ctx ); // expect to return successfully
+ errors += fail_not_equal( 0, ret, "reset_debug_test: reset_debug_rx_count did not return 0 on success" );
+ errors += fail_not_equal( 0, ctx->acc_dcount, "reset_debug_test: rmr_reset_rx_debug_count did not reset acc_dcount to 0" );
+ errors += fail_not_equal( 0, ctx->acc_ecount, "reset_debug_test: rmr_reset_rx_debug_count did not reset acc_ecount to 0" );
+
+ fprintf( stderr, "<INFO> reset_debug_test finished with %d errors\n", errors );
+
+ return errors;
+}
+
+// ----------------------------------------------------------------------------------------
+
+/*
+ Drive tests...
+*/
+int main() {
+ uta_ctx_t si_ctx;
+ int errors = 0;
+
+ fprintf( stderr, "\n<INFO> starting SI95 debug api tests\n" );
+
+ errors += get_debug_info_test( &si_ctx );
+ errors += reset_debug_test( &si_ctx );
+
+ test_summary( errors, "SI95 debug api tests" );
+ if( errors == 0 ) {
+ fprintf( stderr, "<PASS> all tests were OK\n\n" );
+ } else {
+ fprintf( stderr, "<FAIL> %d errors in SI95 debug api code\n\n", errors );
+ }
+
+ return !!errors;
+}
#include <netdb.h>
#include <errno.h>
#include <string.h>
-#include <errno.h>
#include <pthread.h>
#include <ctype.h>
#include <unistd.h>
static void* test_malloc( size_t n ) {
-fprintf( stderr, ">>>> test malloc: %d %d\n", good_mallocs, bad_mallocs );
+ fprintf( stderr, ">>>> test malloc: %d %d\n", good_mallocs, bad_mallocs );
if( good_mallocs ) {
good_mallocs--;
return malloc( n );
ptr = SInew( GI_BLK );
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)
+ free( ptr ); // we can free GI block only in tests
fprintf( stderr, "<INFO> memory module finished with %d errors\n", errors );
return errors;
SIshutdown( NULL );
SIabort( si_ctx );
+ // cleaning up the remaining global resources
+ struct ginfo_blk *gptr = (struct ginfo_blk*)si_ctx;
+ SItrash( TP_BLK, gptr->tplist );
+ free( gptr->tp_map );
+ free( gptr->rbuf );
+ free( gptr->cbtab );
+ free( si_ctx );
fprintf( stderr, "<INFO> cleanup module finished with %d errors\n", errors );
return errors;
static int addr() {
int errors = 0;
int l;
- struct sockaddr* addr;
char buf1[4096]; // space to build buffers for xlation
char* hr_addr; // human readable address returned
void* net_addr; // a network address block of some type
- addr = (struct sockaddr *) malloc( sizeof( struct sockaddr ) );
/*
+ struct sockaddr* addr;
+ addr = (struct sockaddr *) malloc( sizeof( struct sockaddr ) );
+
l = SIgenaddr( " [ff02::4]:4567", PF_INET6, IPPROTO_TCP, SOCK_STREAM, &addr );
SIgenaddr( " [ff02::4]:4567", PF_INET6, IPPROTO_TCP, SOCK_STREAM, &addr );
errors += fail_if_true( l < 1, "v6 to dot conversion failed" );
errors += fail_if_nil( hr_addr, "v6 to dot conversion yields a nil pointer" );
free( net_addr );
+ free( hr_addr );
}
snprintf( buf1, sizeof( buf1 ), "localhost:43086" );
errors += fail_if_true( l < 1, "to dot convdersion failed" );
errors += fail_if_nil( hr_addr, "v4 to dot conversion yields a nil pointer" );
free( net_addr );
+ free( hr_addr );
fprintf( stderr, "<INFO> addr module finished with %d errors\n", errors );
return errors;
thing = SIlisten_prep( UDP_DEVICE, "localhost:1234", AF_INET );
errors += fail_if_nil( thing, "listen prep udp returned nil block" );
+ SItrash( TP_BLK, thing );
thing = SIlisten_prep( UDP_DEVICE, "localhost:1234", 84306 ); // this should fail
errors += fail_not_nil( thing, "listen prep udp returned valid block ptr for bogus family" );
dummy->flags |= GIF_SHUTDOWN; // shutdown edge condition
SIpoll( dummy, 1 );
+ free( dummy->tp_map );
+ free( dummy->rbuf );
+ free( dummy->cbtab );
+
memset( dummy, 0, sizeof( *dummy ) ); // force bad cookie check code to drive
SIpoll( dummy, 1 );
+ free (dummy );
+
status = SIpoll( si_ctx, 1 );
errors += fail_if_true( status != 0, "poll failed" );
status = SInewsession( si_ctx, tpptr );
errors += fail_if_true( status < 0, "newsession did failed when accept was good" );
+ free( tpptr );
+
fprintf( stderr, "<INFO> new_sess module finished with %d errors\n", errors );
return errors;
}
dummy->flags |= GIF_SHUTDOWN;
SIwait( dummy );
+ free( dummy->tp_map );
+ free( dummy->rbuf );
+ free( dummy->cbtab );
+
memset( dummy, 0, sizeof( *dummy ) ); // force bad cookie check code to drive
SIwait( dummy );
+ free( dummy );
+
+
SIwait( si_ctx ); // should drive once through the loop
return errors;