Add safe connect, fix possible seg fault in RTC 13/3313/2 3.8.0
authorE. Scott Daniels <daniels@research.att.com>
Fri, 17 Apr 2020 17:00:28 +0000 (13:00 -0400)
committerE. Scott Daniels <daniels@research.att.com>
Fri, 17 Apr 2020 17:23:54 +0000 (13:23 -0400)
This change adds "safe connect" to the SI95 code which avoids
the connect to even port bug in Linux which could potentially
result in a successful connection when the remote process is
not running or listening on the attempted port.
Issue-ID: RIC-332

This change also includes a change to the level 2 debugging
in the route table collector (RTC) code which could have
resulted in a segment fault.
Issue-ID: RIC-335

Several of the man pages are updated with typo corrections.

Signed-off-by: E. Scott Daniels <daniels@research.att.com>
Change-Id: Ib6045f36850bd2a4b07a19bf11839ce3e9824b6a

31 files changed:
CHANGES_CORE.txt
CMakeLists.txt
docs/overview.rst
docs/rel-notes.rst
docs/rmr_call.3.rst
docs/rmr_get_src.3.rst
docs/rmr_get_srcip.3.rst
docs/rmr_init.3.rst
docs/rmr_init_trace.3.rst
docs/rmr_mt_call.3.rst
docs/rmr_mt_rcv.3.rst
docs/rmr_rts_msg.3.rst
docs/rmr_send_msg.3.rst
docs/rmr_set_stimeout.3.rst
docs/rmr_wh_call.3.rst
docs/rmr_wh_open.3.rst
docs/rmr_wh_send_msg.3.rst
docs/user-guide.rst
src/rmr/common/src/logging.c
src/rmr/common/src/rtc_static.c
src/rmr/si/src/si95/siconnect.c
src/rmr/si/src/si95/siconst.h
src/rmr/si/src/si95/siestablish.c
src/rmr/si/src/si95/sinewses.c
src/rmr/si/src/si95/siproto.h
src/rmr/si/src/si95/sishutdown.c
src/rmr/si/src/si95/siterm.c
src/rmr/si/src/si95/socket_if.h
test/app_test/run_all.sh
test/si95_test.c
test/test_transport_em.c [new file with mode: 0644]

index 80f7e61..997dd77 100644 (file)
@@ -5,6 +5,12 @@
 # API and build change  and fix summaries. Doc correctsions
 # and/or changes are not mentioned here; see the commit messages.
 
+2020 April 17; version 3.8.0
+       Add safe connect to avoid potential connect bug on Linux (RIC-332)
+
+       Change debugging in route table collector to avoid possible
+       segment fault when in level 2 debug (RIC-335)
+
 2020 April 15; version 3.7.4
        Add missing message type to header file (RIC-334)
 
index 8df2a92..93b73e3 100644 (file)
@@ -39,8 +39,8 @@ project( rmr LANGUAGES C )
 cmake_minimum_required( VERSION 3.5 )
 
 set( major_version "3" )               # should be automatically populated from git tag later, but until CI process sets a tag we use this
-set( minor_version "7" )
-set( patch_level "4" )
+set( minor_version "8" )
+set( patch_level "0" )
 
 set( install_root "${CMAKE_INSTALL_PREFIX}" )
 set( install_inc "include/rmr" )
index 91f7376..2433e3e 100644 (file)
@@ -12,24 +12,24 @@ RMR Overview
 ============================================================================================ 
  
  
-RMr Library 
+RMR Library 
 ============================================================================================ 
  
  
 NAME 
 -------------------------------------------------------------------------------------------- 
  
-RMr -- Ric Message Router Library 
+RMR -- Ric Message Router Library 
  
 DESCRIPTION 
 -------------------------------------------------------------------------------------------- 
  
-RMr is a library which provides a user application with the 
-ability to send and receive messages to/from other RMr based 
+RMR is a library which provides a user application with the 
+ability to send and receive messages to/from other RMR based 
 applications without having to understand the underlying 
 messaging transport environment (e.g., SI95) and without 
 needing to know which other endpoint applications are 
-currently available and accepting messages. To do this, RMr 
+currently available and accepting messages. To do this, RMR 
 depends on a routing table generated by an external source. 
 This table is used to determine the destination endpoint of 
 each message sent by mapping the message type T (supplied by 
@@ -39,7 +39,7 @@ application is unaware of which endpoint actually receives
 the message, and in some cases whether that message was sent 
 to multiple applications. 
  
-RMr functions do provide for the ability to respond to the 
+RMR functions do provide for the ability to respond to the 
 specific source instance of a message allowing for either a 
 request response, or call response relationship when needed. 
  
@@ -56,7 +56,7 @@ worker1 and worker2, while group B consists only of logger1.
 It is the responsibility of the route table generator to know 
 which endpoints belong to which groups, and which groups 
 accept which message types. Once understood, the route table 
-generator publishes a table that is ingested by RMr and used 
+generator publishes a table that is ingested by RMR and used 
 for mapping messages to end points. 
  
 The following is a simple route table which causes message 
@@ -176,10 +176,10 @@ Environment
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
  
 To enable configuration of the library behaviour outside of 
-direct user application control, RMr supports a number of 
+direct user application control, RMR supports a number of 
 environment variables which provide information to the 
 library. The following is a list of the various environment 
-variables, what they control and the defaults which RMr uses 
+variables, what they control and the defaults which RMR uses 
 if undefined. 
  
  
index 5c1b47c..78452ce 100644 (file)
@@ -30,6 +30,28 @@ Core RMR Changes
 -------------------------------------------------------------------------------------------- 
  
  
+2020 April 17; version 3.8.0 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+Add safe connect to avoid potential connect bug on Linux 
+(RIC-332) 
+Change debugging in route table collector to avoid possible 
+segment fault when in level 2 debug (RIC-335) 
+2020 April 15; version 3.7.4 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+Add missing message type to header file (RIC-334) 
+2020 April 14; version 3.7.3 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+Fix bug in rmr_call() when using SI95 (RIC-333) 
 2020 April 10; version 3.7.2 
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
  
index a9861c3..3ddac8b 100644 (file)
@@ -95,7 +95,7 @@ A retry loop consists of approximately 1000 send attempts
 **without** any intervening calls to *sleep()* or *usleep().* 
 The number of retry loops defaults to 1, thus a maximum of 
 1000 send attempts is performed before returning to the user 
-application. This value can be set at any point after RMr 
+application. This value can be set at any point after RMR 
 initialisation using the *rmr_set_stimeout()* function 
 allowing the user application to completely disable retires 
 (set to 0), or to increase the number of retry loops. 
index 5202fc0..d76e5a0 100644 (file)
@@ -36,14 +36,14 @@ DESCRIPTION
  
 The rmr_get_src function will copy the *source* information 
 from the message to a buffer (dest) supplied by the user. In 
-an RMr message, the source is the sender's information that 
+an RMR message, the source is the sender's information that 
 is used for return to sender function calls, and is generally 
 the hostname and port in the form *name*. The source might be 
 an IP address port combination; the data is populated by the 
 sending process and the only requirement is that it be 
 capable of being used to start a TCP session with the sender. 
  
-The maximum size allowed by RMr is 64 bytes (including the 
+The maximum size allowed by RMR is 64 bytes (including the 
 nil string terminator), so the user must ensure that the 
 destination buffer given is at least 64 bytes. 
  
index a8cf434..f4bb20a 100644 (file)
@@ -36,19 +36,19 @@ DESCRIPTION
  
 The rmr_get_srcip function will copy the *source IP address* 
 from the message to a buffer (dest) supplied by the user. In 
-an RMr message, the source IP address is the sender's 
+an RMR message, the source IP address is the sender's 
 information that is used for return to sender function calls; 
 this function makes it available to the user application. The 
 address is maintained as IP:port where *IP* could be either 
 an IPv6 or IPv4 address depending on what was provided by the 
 sending application. 
  
-The maximum size allowed by RMr is 64 bytes (including the 
+The maximum size allowed by RMR is 64 bytes (including the 
 nil string terminator), so the user must ensure that the 
 destination buffer given is at least 64 bytes. The user 
-application should use the RMr constant RMR_MAX_SRC to ensure 
+application should use the RMR constant RMR_MAX_SRC to ensure 
 that the buffer supplied is large enough, and to protect 
-against future RMr enhancements which might increase the 
+against future RMR enhancements which might increase the 
 address buffer size requirement. 
  
 RETURN VALUE 
index 2dfdcc8..02efbe7 100644 (file)
@@ -66,9 +66,9 @@ Similarly, the only penality to the application for over
 specifying the normal buffer size might be a larger memory 
 footprint. 
  
-*Flags* allows for selection of some RMr options at the time 
+*Flags* allows for selection of some RMR options at the time 
 of initialisation. These are set by ORing RMRFL constants 
-from the RMr header file. Currently the following flags are 
+from the RMR header file. Currently the following flags are 
 supported: 
  
  
@@ -82,7 +82,7 @@ RMRFL_NOTHREAD
    
   The route table collector thread is not to be started. 
   This should only be used by the route table generator 
-  application if it is based on RMr
+  application if it is based on RMR
    
  
 RMRFL_MTCALL 
@@ -117,11 +117,11 @@ additional support is implemented with the *rmr_mt_call()*
 and *rmr_mt_rcv()* function calls. 
  
 Multi-threaded call support requires the user application to 
-specifically enable it when RMr is initialised. This is 
+specifically enable it when RMR is initialised. This is 
 necessary because a second, dedicated, receiver thread must 
 be started, and requires all messages to be examined and 
 queued by this thread. The additional overhead is minimal, 
-queuing information is all in the RMr message header, but as 
+queuing information is all in the RMR message header, but as 
 an additional process is necessary the user application must 
 "opt in" to this approach. 
  
index 8dc4f4a..a6ddd33 100644 (file)
@@ -58,7 +58,7 @@ RETURN VALUE
 -------------------------------------------------------------------------------------------- 
  
 A value of 1 is returned on success, and 0 on failure. A 
-failure indicates that the RMr context (a void pointer passed 
+failure indicates that the RMR context (a void pointer passed 
 to this function was not valid. 
  
 SEE ALSO 
index b37fe76..b090e04 100644 (file)
@@ -103,7 +103,7 @@ A retry loop consists of approximately 1000 send attempts
 **without** any intervening calls to *sleep()* or *usleep().* 
 The number of retry loops defaults to 1, thus a maximum of 
 1000 send attempts is performed before returning to the user 
-application. This value can be set at any point after RMr 
+application. This value can be set at any point after RMR 
 initialisation using the *rmr_set_stimeout()* function 
 allowing the user application to completely disable retires 
 (set to 0), or to increase the number of retry loops. 
index c73a3c4..86352ff 100644 (file)
@@ -36,7 +36,7 @@ DESCRIPTION
  
 The rmr_mt_rcv function blocks until a message is received, 
 or the timeout period (milliseconds) has passed. The result 
-is an RMr message buffer which references a received message. 
+is an RMR message buffer which references a received message. 
 In the case of a timeout the state will be reflected in an 
 "empty buffer" (if old_msg was not nil, or simply with the 
 return of a nil pointer. If a timeout value of zero (0) is 
@@ -75,7 +75,7 @@ RETURN VALUE
 -------------------------------------------------------------------------------------------- 
  
 When a message is received before the timeout period expires, 
-a pointer to the RMr message buffer which describes the 
+a pointer to the RMR message buffer which describes the 
 message is returned. This will, with a high probability, be a 
 different message buffer than *old_msg;* the user application 
 should not continue to use *old_msg* after it is passed to 
@@ -113,7 +113,7 @@ RMR_ERR_EMPTY
  
 RMR_ERR_NOTSUPP 
    
-  The multi-threaded option was not enabled when RMr was 
+  The multi-threaded option was not enabled when RMR was 
   initialised. See the man page for *rmr_init()* for 
   details. 
    
index a5f428d..e656388 100644 (file)
@@ -67,7 +67,7 @@ A retry loop consists of approximately 1000 send attempts
 **without** any intervening calls to *sleep()* or *usleep().* 
 The number of retry loops defaults to 1, thus a maximum of 
 1000 send attempts is performed before returning to the user 
-application. This value can be set at any point after RMr 
+application. This value can be set at any point after RMR 
 initialisation using the *rmr_set_stimeout()* function 
 allowing the user application to completely disable retires 
 (set to 0), or to increase the number of retry loops. 
index e347189..5f30eeb 100644 (file)
@@ -74,7 +74,7 @@ A retry loop consists of approximately 1000 send attempts
 **without** any intervening calls to *sleep()* or *usleep().* 
 The number of retry loops defaults to 1, thus a maximum of 
 1000 send attempts is performed before returning to the user 
-application. This value can be set at any point after RMr 
+application. This value can be set at any point after RMR 
 initialisation using the *rmr_set_stimeout()* function 
 allowing the user application to completely disable retires 
 (set to 0), or to increase the number of retry loops. 
index 31b9c80..fa1ba2e 100644 (file)
@@ -35,14 +35,14 @@ DESCRIPTION
 -------------------------------------------------------------------------------------------- 
  
 The rmr_set_stimeout function sets the configuration for how 
-RMr will retry message send operations which complete with 
+RMR will retry message send operations which complete with 
 either a *timeout* or *again* completion value. (Send 
 operations include all of the possible message send 
 functions: *rmr_send_msg(), rmr_call(), rmr_rts_msg()* and 
 *rmr_wh_send_msg().* The *rloops* parameter sets the maximum 
 number of retry loops that will be attempted before giving up 
 and returning the unsuccessful state to the user application. 
-Each retry loop is approximately 1000 attempts, and RMr does 
+Each retry loop is approximately 1000 attempts, and RMR does 
 **not** invoke any sleep function between retries in the 
 loop; a small, 1 mu-sec, sleep is executed between loop sets 
 if the *rloops* value is greater than 1. 
@@ -58,7 +58,7 @@ user application does not want to have send operations retry
 when the underlying transport mechanism indicates *timeout* 
 or *again,* the application should invoke this function and 
 pass a value of 0 (zero) for *rloops.* With this setting, all 
-RMr send operations will attempt a send operation only 
+RMR send operations will attempt a send operation only 
 **once,** returning immediately to the caller with the state 
 of that single attempt. 
  
index 3d6ac31..0c9f753 100644 (file)
@@ -84,7 +84,7 @@ A retry loop consists of approximately 1000 send attempts
 **without** any intervening calls to *sleep()* or *usleep().* 
 The number of retry loops defaults to 1, thus a maximum of 
 1000 send attempts is performed before returning to the user 
-application. This value can be set at any point after RMr 
+application. This value can be set at any point after RMR 
 initialisation using the *rmr_set_stimeout()* function 
 allowing the user application to completely disable retires 
 (set to 0), or to increase the number of retry loops. 
index 5a958e3..fb5a457 100644 (file)
@@ -35,7 +35,7 @@ DESCRIPTION
 -------------------------------------------------------------------------------------------- 
  
 The rmr_wh_open function creates a direct link for sending, a 
-wormhole, to another RMr based process. Sending messages 
+wormhole, to another RMR based process. Sending messages 
 through a wormhole requires that the connection be 
 established overtly by the user application (via this 
 function), and that the ID returned by rmr_wh_open be passed 
@@ -43,7 +43,7 @@ to the rmr_wh_send_msg function.
  
 *Target* is the *name* or *IP-address* combination of the 
 processess that the wormhole should be connected to. *Vctx* 
-is the RMr void context pointer that was returned by the 
+is the RMR void context pointer that was returned by the 
 rmr_init function. 
  
 When invoked, this function immediatly attempts to connect to 
index 8854e78..c644967 100644 (file)
@@ -76,7 +76,7 @@ A retry loop consists of approximately 1000 send attempts
 **without** any intervening calls to *sleep()* or *usleep().* 
 The number of retry loops defaults to 1, thus a maximum of 
 1000 send attempts is performed before returning to the user 
-application. This value can be set at any point after RMr 
+application. This value can be set at any point after RMR 
 initialisation using the *rmr_set_stimeout()* function 
 allowing the user application to completely disable retires 
 (set to 0), or to increase the number of retry loops. 
index 8a15725..c201dcb 100644 (file)
@@ -465,7 +465,7 @@ A retry loop consists of approximately 1000 send attempts
 **without** any intervening calls to *sleep()* or *usleep().* 
 The number of retry loops defaults to 1, thus a maximum of 
 1000 send attempts is performed before returning to the user 
-application. This value can be set at any point after RMr 
+application. This value can be set at any point after RMR 
 initialisation using the *rmr_set_stimeout()* function 
 allowing the user application to completely disable retires 
 (set to 0), or to increase the number of retry loops. 
@@ -925,14 +925,14 @@ DESCRIPTION
  
 The rmr_get_src function will copy the *source* information 
 from the message to a buffer (dest) supplied by the user. In 
-an RMr message, the source is the sender's information that 
+an RMR message, the source is the sender's information that 
 is used for return to sender function calls, and is generally 
 the hostname and port in the form *name*. The source might be 
 an IP address port combination; the data is populated by the 
 sending process and the only requirement is that it be 
 capable of being used to start a TCP session with the sender. 
  
-The maximum size allowed by RMr is 64 bytes (including the 
+The maximum size allowed by RMR is 64 bytes (including the 
 nil string terminator), so the user must ensure that the 
 destination buffer given is at least 64 bytes. 
  
@@ -991,19 +991,19 @@ DESCRIPTION
  
 The rmr_get_srcip function will copy the *source IP address* 
 from the message to a buffer (dest) supplied by the user. In 
-an RMr message, the source IP address is the sender's 
+an RMR message, the source IP address is the sender's 
 information that is used for return to sender function calls; 
 this function makes it available to the user application. The 
 address is maintained as IP:port where *IP* could be either 
 an IPv6 or IPv4 address depending on what was provided by the 
 sending application. 
  
-The maximum size allowed by RMr is 64 bytes (including the 
+The maximum size allowed by RMR is 64 bytes (including the 
 nil string terminator), so the user must ensure that the 
 destination buffer given is at least 64 bytes. The user 
-application should use the RMr constant RMR_MAX_SRC to ensure 
+application should use the RMR constant RMR_MAX_SRC to ensure 
 that the buffer supplied is large enough, and to protect 
-against future RMr enhancements which might increase the 
+against future RMR enhancements which might increase the 
 address buffer size requirement. 
  
 RETURN VALUE 
@@ -1256,9 +1256,9 @@ Similarly, the only penality to the application for over
 specifying the normal buffer size might be a larger memory 
 footprint. 
  
-*Flags* allows for selection of some RMr options at the time 
+*Flags* allows for selection of some RMR options at the time 
 of initialisation. These are set by ORing RMRFL constants 
-from the RMr header file. Currently the following flags are 
+from the RMR header file. Currently the following flags are 
 supported: 
  
  
@@ -1272,7 +1272,7 @@ RMRFL_NOTHREAD
    
   The route table collector thread is not to be started. 
   This should only be used by the route table generator 
-  application if it is based on RMr
+  application if it is based on RMR
    
  
 RMRFL_MTCALL 
@@ -1307,11 +1307,11 @@ additional support is implemented with the *rmr_mt_call()*
 and *rmr_mt_rcv()* function calls. 
  
 Multi-threaded call support requires the user application to 
-specifically enable it when RMr is initialised. This is 
+specifically enable it when RMR is initialised. This is 
 necessary because a second, dedicated, receiver thread must 
 be started, and requires all messages to be examined and 
 queued by this thread. The additional overhead is minimal, 
-queuing information is all in the RMr message header, but as 
+queuing information is all in the RMR message header, but as 
 an additional process is necessary the user application must 
 "opt in" to this approach. 
  
@@ -1603,7 +1603,7 @@ RETURN VALUE
 -------------------------------------------------------------------------------------------- 
  
 A value of 1 is returned on success, and 0 on failure. A 
-failure indicates that the RMr context (a void pointer passed 
+failure indicates that the RMR context (a void pointer passed 
 to this function was not valid. 
  
 SEE ALSO 
@@ -1705,7 +1705,7 @@ A retry loop consists of approximately 1000 send attempts
 **without** any intervening calls to *sleep()* or *usleep().* 
 The number of retry loops defaults to 1, thus a maximum of 
 1000 send attempts is performed before returning to the user 
-application. This value can be set at any point after RMr 
+application. This value can be set at any point after RMR 
 initialisation using the *rmr_set_stimeout()* function 
 allowing the user application to completely disable retires 
 (set to 0), or to increase the number of retry loops. 
@@ -1883,7 +1883,7 @@ DESCRIPTION
  
 The rmr_mt_rcv function blocks until a message is received, 
 or the timeout period (milliseconds) has passed. The result 
-is an RMr message buffer which references a received message. 
+is an RMR message buffer which references a received message. 
 In the case of a timeout the state will be reflected in an 
 "empty buffer" (if old_msg was not nil, or simply with the 
 return of a nil pointer. If a timeout value of zero (0) is 
@@ -1922,7 +1922,7 @@ RETURN VALUE
 -------------------------------------------------------------------------------------------- 
  
 When a message is received before the timeout period expires, 
-a pointer to the RMr message buffer which describes the 
+a pointer to the RMR message buffer which describes the 
 message is returned. This will, with a high probability, be a 
 different message buffer than *old_msg;* the user application 
 should not continue to use *old_msg* after it is passed to 
@@ -1960,7 +1960,7 @@ RMR_ERR_EMPTY
  
 RMR_ERR_NOTSUPP 
    
-  The multi-threaded option was not enabled when RMr was 
+  The multi-threaded option was not enabled when RMR was 
   initialised. See the man page for *rmr_init()* for 
   details. 
    
@@ -2457,7 +2457,7 @@ A retry loop consists of approximately 1000 send attempts
 **without** any intervening calls to *sleep()* or *usleep().* 
 The number of retry loops defaults to 1, thus a maximum of 
 1000 send attempts is performed before returning to the user 
-application. This value can be set at any point after RMr 
+application. This value can be set at any point after RMR 
 initialisation using the *rmr_set_stimeout()* function 
 allowing the user application to completely disable retires 
 (set to 0), or to increase the number of retry loops. 
@@ -2694,7 +2694,7 @@ A retry loop consists of approximately 1000 send attempts
 **without** any intervening calls to *sleep()* or *usleep().* 
 The number of retry loops defaults to 1, thus a maximum of 
 1000 send attempts is performed before returning to the user 
-application. This value can be set at any point after RMr 
+application. This value can be set at any point after RMR 
 initialisation using the *rmr_set_stimeout()* function 
 allowing the user application to completely disable retires 
 (set to 0), or to increase the number of retry loops. 
@@ -2962,14 +2962,14 @@ DESCRIPTION
 -------------------------------------------------------------------------------------------- 
  
 The rmr_set_stimeout function sets the configuration for how 
-RMr will retry message send operations which complete with 
+RMR will retry message send operations which complete with 
 either a *timeout* or *again* completion value. (Send 
 operations include all of the possible message send 
 functions: *rmr_send_msg(), rmr_call(), rmr_rts_msg()* and 
 *rmr_wh_send_msg().* The *rloops* parameter sets the maximum 
 number of retry loops that will be attempted before giving up 
 and returning the unsuccessful state to the user application. 
-Each retry loop is approximately 1000 attempts, and RMr does 
+Each retry loop is approximately 1000 attempts, and RMR does 
 **not** invoke any sleep function between retries in the 
 loop; a small, 1 mu-sec, sleep is executed between loop sets 
 if the *rloops* value is greater than 1. 
@@ -2985,7 +2985,7 @@ user application does not want to have send operations retry
 when the underlying transport mechanism indicates *timeout* 
 or *again,* the application should invoke this function and 
 pass a value of 0 (zero) for *rloops.* With this setting, all 
-RMr send operations will attempt a send operation only 
+RMR send operations will attempt a send operation only 
 **once,** returning immediately to the caller with the state 
 of that single attempt. 
  
@@ -3822,7 +3822,7 @@ A retry loop consists of approximately 1000 send attempts
 **without** any intervening calls to *sleep()* or *usleep().* 
 The number of retry loops defaults to 1, thus a maximum of 
 1000 send attempts is performed before returning to the user 
-application. This value can be set at any point after RMr 
+application. This value can be set at any point after RMR 
 initialisation using the *rmr_set_stimeout()* function 
 allowing the user application to completely disable retires 
 (set to 0), or to increase the number of retry loops. 
@@ -4012,7 +4012,7 @@ DESCRIPTION
 -------------------------------------------------------------------------------------------- 
  
 The rmr_wh_open function creates a direct link for sending, a 
-wormhole, to another RMr based process. Sending messages 
+wormhole, to another RMR based process. Sending messages 
 through a wormhole requires that the connection be 
 established overtly by the user application (via this 
 function), and that the ID returned by rmr_wh_open be passed 
@@ -4020,7 +4020,7 @@ to the rmr_wh_send_msg function.
  
 *Target* is the *name* or *IP-address* combination of the 
 processess that the wormhole should be connected to. *Vctx* 
-is the RMr void context pointer that was returned by the 
+is the RMR void context pointer that was returned by the 
 rmr_init function. 
  
 When invoked, this function immediatly attempts to connect to 
@@ -4155,7 +4155,7 @@ A retry loop consists of approximately 1000 send attempts
 **without** any intervening calls to *sleep()* or *usleep().* 
 The number of retry loops defaults to 1, thus a maximum of 
 1000 send attempts is performed before returning to the user 
-application. This value can be set at any point after RMr 
+application. This value can be set at any point after RMR 
 initialisation using the *rmr_set_stimeout()* function 
 allowing the user application to completely disable retires 
 (set to 0), or to increase the number of retry loops. 
index ce6c246..e38d7b0 100644 (file)
@@ -145,6 +145,7 @@ extern void rmr_vlog( int write_level, char* fmt, ... ) {
                write_level = RMR_VL_DEBUG;
        }
 
+       memset( msg, 0, sizeof( msg ) );                                                                // logging is slow; this ensures 0 term if msg is too large
        hlen = snprintf( msg, sizeof( msg ), "%ld %d/RMR [%s] ", (long) time( NULL ), log_pid, log_situations[write_level] );
        body = msg + hlen;
 
@@ -171,7 +172,7 @@ extern void rmr_vlog_force( int write_level, char* fmt, ... ) {
                rmr_vlog_init();
        }
 
-       if( log_vlevel <= 0 ) {                 // cant force if off completely to allow for total silience
+       if( log_vlevel <= 0 ) {                 // can force if off completely to allow for total silience
                return;
        }
 
index aa829ef..5fdf064 100644 (file)
@@ -285,12 +285,8 @@ static void* rtc( void* vctx ) {
                if( msg != NULL && msg->len > 0 ) {
                        payload = msg->payload;
                        mlen = msg->len;                                        // usable bytes in the payload
-                       if( vlevel > 1 ) {
-                               rmr_vlog_force( RMR_VL_DEBUG, "rmr_rtc: received rt message type=%d len=%d bytes (%s)\n", msg->mtype, (int) mlen, msg->payload );
-                       } else {
-                               if( DEBUG > 1 || (vlevel > 0) ) rmr_vlog( RMR_VL_DEBUG, "rmr_rtc: received rt message type=%d len=%d\n", msg->mtype, (int) mlen );
-                       }
 
+                       if( DEBUG > 1 || (vlevel > 0) ) rmr_vlog( RMR_VL_DEBUG, "rmr_rtc: received rt message type=%d len=%d\n", msg->mtype, (int) mlen );
                        switch( msg->mtype ) {
                                case RMRRM_TABLE_DATA:
                                        if( (flags & RTCFL_HAVE_UPDATE) == 0 ) {
@@ -311,6 +307,9 @@ static void* rtc( void* vctx ) {
                                        }
                                        memcpy( pbuf, payload, mlen );
                                        pbuf[mlen] = 0;                                                                         // don't depend on sender making this a legit string
+                                       if( vlevel > 1 ) {
+                                               rmr_vlog_force( RMR_VL_DEBUG, "rmr_rtc: rt message: (%s)\n", pbuf );
+                                       }
 
                                        curr = pbuf;
                                        while( curr ) {                                                         // loop over each record in the buffer
index a48cb43..77dce63 100644 (file)
 ***************************************************************************
 *
 *  Mnemonic:   SIconnect
-*  Abstract:   Start a TCP/IP session with another process.
-*  Parms:    
-*              addr - Pointer to a string containing the process' address
-*                              The address is either ipv4 or ipv6 formmat with the
-*                              port number separated with a semicolon (::1;4444,
-*                              localhost;4444 climber;4444 129.168.0.4;4444).
-*  Returns:    The session number if all goes well, SI_ERROR if not.
+*  Abstract:   This module contains functions to make the connection using
+*                              a transport block which has been given a transport (tcp) family
+*                              address structure.
 *
 *  Date:               March 1995
 *  Author:             E. Scott Daniels
 *
-*  Mod:                08 Mar 2007 - conversion of sorts to support ipv6
+*  Mod:                        08 Mar 2007 - conversion of sorts to support ipv6
+*                              17 Apr 2020 - Add safe connect capabilities
 ******************************************************************************
 */
 #include "sisetup.h"
 #include "sitransport.h"
 
+// ---------------- internal functions ----------------------------------------------
+
+/*
+       Attempts a connection to addr, and ensures that the linux even port
+       connect bug does not establish the connection back to our process.
+       If we detect this, then we abort the connection and return -1. 0
+       returned on a good connection.
+
+       If we are hit with the even port connection bug we have no choice but
+       to abort the connection which will CLOSE the caller's FD. This may
+       not be expected in some situations, and when we do the errno is set to
+       EBADFD to indicate this. We ensure that this state is returned ONLY
+       if the failure results in a closed fd which the caller will need to reopen.
+*/
+int safe_connect( int fd, struct sockaddr* addr, int alen ) {
+       int state = 0;
+       char    caddr[255];                     // work buffer for get sock name (v6 addr ~28 bytes, so this is plenty)
+       int             calen;                          // len of the connect generated address
+
+       if( (state = CONNECT( fd, addr, alen )) != 0 ) {
+               if( errno == EBADFD ) {                 // ensure we return bad fd ONLY if we abort later
+                       errno = ECONNABORTED;
+               }
+               return state;
+       }
+
+       if( PARANOID_CHECKS ) {
+               if( alen > sizeof( caddr ) ) {          // shouldn't happen, but be safe
+                       fprintf( stderr, "safe_connect: address buffer for connect exceeds work space %d > %lu\n", alen, sizeof( caddr ) );
+                       errno = E2BIG;
+                       return -1;
+               }
+       }
+
+       calen = alen;                   // we assume a bound address will have the same type, and thus len, as the connect to addr
+       if( getsockname( fd, (struct sockaddr *) &caddr, &calen ) == 0 ) {
+               if( calen != alen || memcmp( addr, &caddr, calen ) != 0 ) {                     // addresses differ, so it's good
+                       errno = 0;
+                       return 0;
+               }
+       }
+
+       siabort_conn( fd );
+       errno = EBADFD;
+       return -1;
+}
+
 /*
        Accept a file descriptor and add it to the map.
 */
@@ -50,12 +94,26 @@ extern void SImap_fd( struct ginfo_blk *gptr, int fd, struct tp_blk* tpptr ) {
        }
 }
 
+/*
+       Creates a connection to the target endpoint using the address in the
+       buffer provided.  The address may be one of three forms:
+               hostname:port
+               IPv4-address:port
+               [IPv6-address]:port
+
+       On success the open file descriptor is returned; else -1 is returned. Errno
+       will be left set by the underlying connect() call.
+
+       To avoid the even port connect bug in the linux connect() systeem call,
+       we will use safe_connect() if indicated during the connection prep
+       process.
+*/
 extern int SIconnect( struct ginfo_blk *gptr, char *abuf ) {
        int status;
-       struct tp_blk *tpptr;           //  pointer to new block 
+       struct tp_blk *tpptr;           //  pointer to new block
        struct sockaddr *taddr;         // convenience pointer to addr of target
-       int alen = 0;                                   //  len of address struct 
-       int fd = SI_ERROR;              //  file descriptor to return to caller 
+       int alen = 0;                                   //  len of address struct
+       int fd = SI_ERROR;              //  file descriptor to return to caller
 
        if( PARANOID_CHECKS ) {
                if( gptr == NULL ) {
@@ -71,22 +129,31 @@ extern int SIconnect( struct ginfo_blk *gptr, char *abuf ) {
        if( tpptr != NULL ) {
                taddr = tpptr->paddr;
                errno = 0;
-               if( connect( tpptr->fd, taddr, tpptr->palen ) != 0 ) {
-                       close( tpptr->fd );                             //  clean up fd and tp_block 
-                       SItrash( TP_BLK, tpptr );               //  free the trasnsport block 
-                       fd = SI_ERROR;                                  //  send bad session id num back 
-               } else  {                                       //  connect ok 
-                       tpptr->flags |= TPF_SESSION;                    //  indicate we have a session here 
-                       tpptr->next = gptr->tplist;                     //  add block to the list 
+               if( tpptr->flags & TPF_SAFEC ) {
+                       if( safe_connect( tpptr->fd, taddr, tpptr->palen ) != 0 ) {             // fd closed on failure
+                               SItrash( TP_BLK, tpptr );
+                               tpptr->fd = -1;
+                       }
+               } else {
+                       if( CONNECT( tpptr->fd, taddr, tpptr->palen ) != 0 ) {
+                               CLOSE( tpptr->fd );                             // clean up fd and tp_block
+                               tpptr->fd = -1;
+                               SItrash( TP_BLK, tpptr );               // free the trasnsport block
+                       }
+               }
+
+               if( tpptr->fd >= 0 ) {                                                          // connect ok
+                       tpptr->flags |= TPF_SESSION;                    //  indicate we have a session here
+                       tpptr->next = gptr->tplist;                     //  add block to the list
                        if( tpptr->next != NULL ) {
-                               tpptr->next->prev = tpptr;              //  if there - point back at new 
+                               tpptr->next->prev = tpptr;              //  if there - point back at new
                        }
 
-                       gptr->tplist = tpptr;                           //  point at new head 
-                       fd = tpptr->fd;                                 //  save for return value 
+                       gptr->tplist = tpptr;                           //  point at new head
+                       fd = tpptr->fd;                                 //  save for return value
                        SImap_fd( gptr, fd, tpptr );
                }
        }
 
-       return fd;                    
-}                                 
+       return fd;
+}
index e5ec5c0..f43e41a 100644 (file)
@@ -38,6 +38,9 @@
 #define DEBUG 0
 #endif 
 
+#ifndef PARANOID_CHECKS
+#      define PARANOID_CHECKS 0
+#endif
 
 //#define EOS   '\000'          //  end of string marker 
 
@@ -51,6 +54,8 @@
 #define TPF_UNBIND             0x04   //  SIterm should unbind the fd 
 #define TPF_DRAIN              0x08   //  session is being drained 
 #define TPF_DELETE             0x10    //  block is ready for deletion -- when safe 
+#define TPF_SAFEC              0x20    // use safe connect when connecting
+#define TPF_ABORT              0x40    // connection should be aborted at termination
 
 #define MAX_CBS                        8        //  number of supported callbacks in table 
 #define MAX_RBUF               8192   //  max size of receive buffer 
index 846faa1..49e484d 100644 (file)
@@ -36,7 +36,7 @@
 */
 
 
-#include "sisetup.h"       //  include the necessary setup stuff 
+#include "sisetup.h"       //  include the necessary setup stuff
 #include "sitransport.h"
 #include <errno.h>
 #include <netinet/tcp.h>
        Returns a transport struct which is the main context for the listener.
 */
 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 protocol;                //  protocol for socket call 
-       char buf[256];               //  buffer to build request address in 
+       struct tp_blk *tptr;         //  pointer at new tp block
+       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;
        int alen = 0;
 
-       tptr = (struct tp_blk *) SInew( TP_BLK );     //  new transport info block 
+       tptr = (struct tp_blk *) SInew( TP_BLK );     //  new transport info block
 
        if( tptr != NULL )
        {
                addr = NULL;
 
-               switch( type )                  //  things specifc to tcp or udp 
+               switch( type )                  //  things specifc to tcp or udp
                {
                        case UDP_DEVICE:
                                tptr->type = SOCK_DGRAM;
@@ -92,7 +92,7 @@ extern struct tp_blk *SIlisten_prep( struct ginfo_blk *gptr, int type, char* abu
                                protocol = IPPROTO_TCP;
                }
 
-               alen = SIgenaddr( abuf, protocol, family, tptr->type, &addr );  //  family == 0 for type that suits the address passed in 
+               alen = SIgenaddr( abuf, protocol, family, tptr->type, &addr );  //  family == 0 for type that suits the address passed in
                if( alen <= 0 ) {
                        return NULL;
                }
@@ -107,27 +107,50 @@ 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 ) );
                                close( tptr->fd );
                        }
                } else {
-                       status = ! SI_OK;                       //  force bad return later 
+                       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 
+               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 
+                       SItrash( TP_BLK, tptr );        //  free the trasnsport block
+                       tptr = NULL;                    //  set to return nothing
                }
        }
 
        return tptr;
 }
 
+/*
+       Look at the address and determine if the connect attempt to this address must
+       use safe_connect() rather than the system connect() call. On linux, a smart
+       connect is needed if the target port is >32K and is even. This makes the assumption
+       that the local port rage floor is 32K; we could read something in /proc, but
+       at this point won't bother.  Returns true if we determine that it is best to
+       use safe_connect().
+*/
+static int need_smartc( char* abuf ) {
+       char*   tok;
+       int             state = 1;
+       int             v;
+
+       if( (tok = strchr( abuf, ':')) != NULL ) {
+               v = atoi( tok+1 );
+               if( v < 32767  || v % 2 != 0 ) {
+                       state = 0;
+               }
+       }
+
+       return state;
+}
+
 /*
        Prep a socket to use to connect to a listener.
        Establish a transport block and target address in prep to connect.
@@ -139,20 +162,20 @@ extern struct tp_blk *SIlisten_prep( struct ginfo_blk *gptr, int type, char* abu
        family of 0 (AF_ANY) is usually the best choice.
 */
 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 
-       int protocol;                //  protocol for socket call 
-       char buf[256];               //  buffer to build request address in 
+       struct tp_blk *tptr;         //  pointer at new tp block
+       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;
        int alen = 0;
 
-       tptr = (struct tp_blk *) SInew( TP_BLK );     //  new transport info block 
+       tptr = (struct tp_blk *) SInew( TP_BLK );     //  new transport info block
 
        if( tptr != NULL )
        {
                addr = NULL;
 
-               switch( type )                  //  things specifc to tcp or udp 
+               switch( type )                  //  things specifc to tcp or udp
                {
                        case UDP_DEVICE:
                                tptr->type = SOCK_DGRAM;
@@ -165,7 +188,7 @@ extern struct tp_blk *SIconn_prep( struct ginfo_blk *gptr, int type, char *abuf,
                                protocol = IPPROTO_TCP;
                }
 
-               alen = SIgenaddr( abuf, protocol, family, tptr->type, &addr );  //  family == 0 for type that suits the address passed in 
+               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",
@@ -179,16 +202,11 @@ extern struct tp_blk *SIconn_prep( struct ginfo_blk *gptr, int type, char *abuf,
                if( (tptr->fd = SOCKET( tptr->family, tptr->type, protocol )) >= SI_OK ) {
                        optval = 1;
 
-                       if( SO_REUSEPORT ) {
-                               SETSOCKOPT( tptr->fd, SOL_SOCKET, SO_REUSEPORT, (char *)&optval, sizeof( optval) );
-                       }
-
                        if( gptr->tcp_flags & SI_TF_NODELAY ) {
                                optval = 1;
                        } else {
                                optval = 0;
                        }
-                       //fprintf( stderr, ">>>>> conn_prep: setting no delay = %d\n", optval );
                        SETSOCKOPT( tptr->fd, SOL_TCP, TCP_NODELAY, (void *)&optval, sizeof( optval) ) ;
 
                        if( gptr->tcp_flags & SI_TF_FASTACK ) {
@@ -196,14 +214,15 @@ extern struct tp_blk *SIconn_prep( struct ginfo_blk *gptr, int type, char *abuf,
                        } else {
                                optval = 0;
                        }
-                       //fprintf( stderr, ">>>>> conn_prep: setting quick ack = %d\n", optval );
                        SETSOCKOPT( tptr->fd, SOL_TCP, TCP_QUICKACK, (void *)&optval, sizeof( optval) ) ;
 
                        tptr->paddr = addr;                             // tuck the remote peer address away
+                       if( need_smartc( abuf ) ) {
+                               tptr->flags |= TPF_SAFEC;
+                       }
                } else {
-                       //fprintf( stderr, ">>>>> conn_prep: bad socket create: %s\n", strerror( errno ) );
                        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 182fa6a..6e439de 100644 (file)
@@ -61,7 +61,7 @@ extern int SInewsession( struct ginfo_blk *gptr, struct tp_blk *tpptr ) {
 
        newtp = SInew( TP_BLK );                              //  get a new tp block for the session
        if( newtp == NULL ) {
-               close( status );                                                // must disconnect the other side
+               CLOSE( status );                                                // must disconnect the other side
                free( addr );
                return SI_ERROR;
        }
index e8d9ba5..dfe9447 100644 (file)
 #ifndef _si_proto_h
 #define _si_proto_h
 
+extern void siabort_conn( int fd );            // use by applications discouraged
+
 extern void *SInew( int type );
 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  );
 extern struct tp_blk *SIconn_prep( struct ginfo_blk *gptr, int type, char *abuf, int family );
index c76bc94..4ff1e8f 100644 (file)
 ******************************************************************************
 *
 *  Mnemonic: SIshutdown
-*  Abstract: This routine will ensure that all tp blocks have been closed
-*            with the transport provider and removed from the list. The
-*            shutdown flag is set in addition.
-*  Parms:    gptr - pointer to the ginfo structure (SIHANDLE)
-*  Retrns:   Nothing.
+*  Abstract: Shutdown and abort functions.
+*
 *  Date:     23 March 1995
 *  Author:   E. Scott Daniels
 *
 *****************************************************************************
 */
-#include "sisetup.h"                   //  get includes and defines 
+#include "sisetup.h"                   //  get includes and defines
+
+/*
+*/
+static void sishutdown( struct ginfo_blk *gptr, int flags ) {
+       struct tp_blk*  tpb;
 
-extern void SIshutdown( struct ginfo_blk *gptr ) {
        if( gptr != NULL && gptr->magicnum == MAGICNUM )
        {
-               gptr->flags |=  GIF_SHUTDOWN;    //  signal shutdown 
-               while( gptr->tplist != NULL )
+               gptr->flags |=  GIF_SHUTDOWN;    //  signal shutdown
+               for( tpb = gptr->tplist; tpb != NULL; tpb = tpb->next )
                {
-                       gptr->tplist->flags |= TPF_UNBIND;    //  force unbind on session 
-                       SIterm( gptr, gptr->tplist );         //  and drop the session 
+                       tpb->flags |= (TPF_UNBIND | flags);    //  force unbind on session  and set caller flags
+                       SIterm( gptr, tpb );                                    // term marks ok to delete but does NOT remove it
                }
        }
-}            
+}
+
+/*
+       Run the list of known transport sessions and close them gracefully. This
+       will result in time-waits which might prevent the application from
+       restarting immediately as the listen port(s) might not be usable.
+*/
+extern void SIshutdown( struct ginfo_blk *gptr ) {
+       sishutdown( gptr, 0 );
+}
+
+/*
+       Run the list of known transport sessions and close them by aborting
+       (resetting the connection). This can result in buffered, but untransmitted,
+       data from being lost; the risk should be known by the caller.
+*/
+extern void SIabort( struct ginfo_blk *gptr ) {
+       sishutdown( gptr, TPF_ABORT );
+}
index 8b732f6..ce48748 100644 (file)
@@ -23,7 +23,7 @@
 *  Mnemonic:   SIterm
 *  Abstract:   Manage the transport provider block information relating to
 *                              the need to terminate the session. The block is left in the
-*                              list; it is unsafe to clean the lsit up outside of the SIwait 
+*                              list; it is unsafe to clean the lsit up outside of the SIwait
 *                              thread.  When safe, the SIrm_tpb() function can be called to
 *                              do the rest of the work that was originally done by SIterm.
 *
 *
 **************************************************************************
 */
-#include "sisetup.h"     //  get the setup stuff 
+#include "sisetup.h"     //  get the setup stuff
 #include "sitransport.h"
 
+
+/*
+       Abort the connection in such a way that there is no resulting time-wait state.
+       This should be used cautiously but is needed for situations like when the Linux
+       connect() system call manages to connect us to ourselves through the even number
+       port bug.
+
+       This needs a real file desc as there may not yet be a transport block when
+       the connection may need to be aborted. For this reason, the function name is
+       lower case indicating that user programmes are discouraged from using this
+       function directly.
+*/
+extern void siabort_conn( int fd ) {
+       struct linger   opt_val;                // value passed as option to set call
+
+       opt_val.l_onoff = 1;                    // MUST set linger on with a zero len timeout
+       opt_val.l_linger = 0;
+
+       setsockopt( fd, SOL_SOCKET, SO_LINGER, &opt_val, sizeof( opt_val ) );           // disable linger to prevent time-wait
+       CLOSE( fd );                    // close will now abort and not result in time-wait (do NOT use shutdown() first!)
+}
+
 /*
        Close the FD and mark the transport block as unusable/closed.
        Removal of the block from the list is safe only from the siwait
-       thread.
+       thread.  If the abort flag is set in the transport block, then the
+       connection is aborted (reset).
 */
 extern void SIterm( struct ginfo_blk* gptr, struct tp_blk *tpptr ) {
 
        if( tpptr != NULL ) {
                if( tpptr->fd >= 0 ) {
-                       CLOSE( tpptr->fd );    
+                       if( tpptr->flags & TPF_ABORT ) {
+                               siabort_conn( tpptr->fd );
+                       } else {
+                               CLOSE( tpptr->fd );
+                       }
+
                        if( tpptr->fd < MAX_FDS ) {
                                gptr->tp_map[tpptr->fd] = NULL;         // drop reference
                        }
@@ -57,25 +85,25 @@ extern void SIterm( struct ginfo_blk* gptr, struct tp_blk *tpptr ) {
 
 /*
        It is safe to remove the block from the list; if it was in the list
-       in the first place. 
+       in the first place.
 */
 extern void SIrm_tpb( struct ginfo_blk *gptr, struct tp_blk *tpptr ) {
 
        if( tpptr != NULL ) {
                if( tpptr->prev != NULL || tpptr->next != NULL ) {      // in the list
-                       if( tpptr->prev != NULL ) {            //  remove from the list 
-                               tpptr->prev->next = tpptr->next;    //  point previous at the next 
+                       if( tpptr->prev != NULL ) {            //  remove from the list
+                               tpptr->prev->next = tpptr->next;    //  point previous at the next
                        } else {
-                               gptr->tplist = tpptr->next;        //  this was head, make next new head 
+                               gptr->tplist = tpptr->next;        //  this was head, make next new head
                        }
-       
+
                        if( tpptr->next != NULL ) {
-                               tpptr->next->prev = tpptr->prev;  //  point next one back behind this one 
+                               tpptr->next->prev = tpptr->prev;  //  point next one back behind this one
                        }
                }
 
-               free( tpptr->addr );             //  release the address bufers 
+               free( tpptr->addr );             //  release the address bufers
                free( tpptr->paddr );
-               free( tpptr );                   //  and release the block 
+               free( tpptr );                   //  and release the block
        }
 }
index f7311fc..eb4e69b 100644 (file)
 #ifndef _SOCKET_IF_H
 #define _SOCKET_IF_H
 
-#ifndef PARANOID_CHECKS
-#      define PARANOID_CHECKS 0
-#endif
-
 #define TCP_DEVICE     0       //  device type of socket
 #define UDP_DEVICE     1
 
index 4fef41d..f276205 100644 (file)
@@ -58,7 +58,7 @@ function run_test {
 
 build=""
 errors=0
-si_flag=""                             # eventually we'll default to -S to run SI tests over NNG tests
+si_flag="-S"                           # default to -S to prefer to run SI tests over NNG tests
 
 src_root="../.."
 if [[ -z $BUILD_PATH ]]                                                # if not explicitly set, assume one of our standard spots
index 26b1b21..c77f389 100644 (file)
@@ -62,8 +62,9 @@
 #define NO_EMULATION 1                                         // no emulation of transport functions
 #define NO_PRIVATE_HEADERS 1                           // no rmr_si or rmr_nng headers
 #define NO_DUMMY_RMR 1                                         // no msg things
-#include "test_support.c"                                      // things like fail_if()
 
+#include "test_support.c"                                      // things like fail_if()
+#include "test_transport_em.c"                         // system/transport emulation (open, close, connect, etc)
 
 /*
 #include "rmr.h"                                       // things the users see
@@ -84,7 +85,7 @@
 //#include <si95/sigetadd.c>
 //#include <si95/sigetname.c>
 #include <si95/siinit.c>
-//#include <si95/silisten.c>
+#include <si95/silisten.c>
 #include <si95/sinew.c>
 //#include <si95/sinewses.c>
 //#include <si95/sipoll.c>
@@ -148,6 +149,7 @@ static int init() {
        SIclr_tflags( si_ctx, 0x00 );           // drive for coverage; no return value from these
        SIset_tflags( si_ctx, 0x03 );
 
+       fprintf( stderr, "<INFO> init  module finished with %d errors\n", errors );
        return errors;
 }
 
@@ -158,9 +160,14 @@ static int cleanup() {
                return 0;
        }
 
+       SItp_stats( si_ctx );           // drive for coverage only
+       SItp_stats( NULL );
+
        SIconnect( si_ctx, "localhost:43086" );         // ensure context has a tp block to free on shutdown
        SIshutdown( si_ctx );
 
+
+       fprintf( stderr, "<INFO> cleanup  module finished with %d errors\n", errors );
        return errors;
 }
 
@@ -184,11 +191,11 @@ static int addr() {
 
        dest = NULL;
        snprintf( buf1, sizeof( buf1 ), "   [ff02::5:4001" );           // invalid address, drive leading space eater too
-       l = SIaddress( buf1, &dest, AC_TOADDR6 );
+       l = SIaddress( buf1, (void **)  &dest, AC_TOADDR6 );
        errors += fail_if_true( l > 0, "to addr6 with bad addr convdersion returned valid len" );
 
        snprintf( buf1, sizeof( buf1 ), "[ff02::5]:4002" );             // v6 might not be supported so failure is OK here
-       l=SIaddress( buf1, &dest, AC_TOADDR6 );
+       l=SIaddress( buf1, (void **) &dest, AC_TOADDR6 );
        errors += fail_if_true( l < 1, "to addr convdersion failed" );
 
        snprintf( buf1, sizeof( buf1 ), "localhost:43086" );
@@ -196,13 +203,56 @@ static int addr() {
        errors += fail_if_true( l < 1, "to addr convdersion failed" );
 
        snprintf( buf1, sizeof( buf1 ), "localhost:4004" );
-       l = SIaddress( buf1, &dest, AC_TODOT );
+       l = SIaddress( buf1, (void **) &dest, AC_TODOT );
        errors += fail_if_true( l < 1, "to dot convdersion failed" );
 
+       fprintf( stderr, "<INFO> addr module finished with %d errors\n", errors );
        return errors;
 
 }
 
+
+/*
+       Connection oriented tests.
+*/
+static int conn( ) {
+       int errors = 0;
+       int state;
+
+       state = SIconnect( si_ctx, "localhost:4567" );          // driver regular connect
+       errors += fail_if_true( state < 0, "connect to low port failed" );
+
+       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
+       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_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
+       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" );
+
+       tpem_set_sock_state( 0 );
+
+       state = SIlistener( si_ctx, TCP_DEVICE, "0.0.0.0:4567" );
+       errors += fail_if_true( state < 0, "listen failed" );
+
+       tpem_set_bind_state( 1 );
+       state = SIlistener( si_ctx, TCP_DEVICE, "0.0.0.0:4567" );
+       errors += fail_if_true( state >= 0, "listen successful when bind error set" );
+       tpem_set_bind_state( 0 );
+
+
+       fprintf( stderr, "<INFO> conn module finished with %d errors\n", errors );
+       return errors;
+}
+
 /*
        Drive tests...
 */
@@ -216,7 +266,7 @@ int main() {
        errors += init();
        errors += memory();
        errors += addr();
-fprintf( stderr, ">>> cleaning\n" );
+       errors += conn();
        errors += cleanup();
 
        fprintf( stderr, "<INFO> testing finished\n" );
diff --git a/test/test_transport_em.c b/test/test_transport_em.c
new file mode 100644 (file)
index 0000000..92a6b93
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+==================================================================================
+       Copyright (c) 2020 Nokia
+       Copyright (c) 2020 AT&T Intellectual Property.
+
+   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:       test_transport.c
+       Abstract:       This supplies a bunch of dummy system functions which emulate
+                               things like connect() bind() etc.
+
+                               This module must be directly included to be used.
+       Date:           17 April 2020
+       Author:         E. Scott Daniels
+*/
+
+#ifndef _test_transport_c
+#define _sitransport_h                 // prevent the transport defs when including SI95
+
+
+char   tpem_last_addr[1024];           // last address to simulate connection to ourself
+int            tpem_last_len = 0;
+
+int tpem_addr_dup = 0;                 // getsockname duplicates last addr if true
+int tpem_conn_state = 0;               // states returned by emulated functions allowing failures to be driven
+int tpem_sock_state = 0;
+int tpem_listen_state = 0;
+int tpem_bind_state = 0;
+
+// ------------ emulation control -------------------------------------------
+
+/*
+       All test prog to set various things
+*/
+static void tpem_set_conn_state( int s ) {
+       tpem_conn_state = s;
+}
+
+static void tpem_set_addr_dup_state( int s ) {
+       tpem_addr_dup = s;
+}
+
+static void tpem_set_sock_state( int s ) {
+       tpem_sock_state = s;
+}
+
+static void tpem_set_bind_state( int s ) {
+       tpem_bind_state = s;
+}
+
+// ---- emulated functions ---------------------------------------------------
+
+static int tpem_bind( int socket, struct sockaddr* addr, socklen_t alen ) {
+       return tpem_bind_state;
+}
+
+static int tpem_connect( int socket, struct sockaddr* addr, socklen_t alen ) {
+       memcpy( tpem_last_addr, addr, alen );
+       tpem_last_len = alen;
+       fprintf( stderr, "<SYSEM> connection simulated rc=%d\n", tpem_conn_state );
+       return tpem_conn_state;
+}
+
+/*
+       This gets the last address connected to if dup is true; else returns 0s
+       which should be enough to test that connection didn't loop back to us.
+*/
+static int tpem_getsockname( int socket, struct sockaddr* address, socklen_t* alen ) {
+       int clen;               // copy len
+
+       if( tpem_last_len > 0 ) {
+               clen = tpem_last_len > *alen ? *alen : tpem_last_len;
+               if( tpem_addr_dup ) {
+                       memcpy( address, tpem_last_addr, clen );
+               } else {
+                       memset( address, 0, clen );
+               }
+               *alen = clen;
+       } else {
+               memset( address, 0, *alen );
+       }
+
+       return 0;
+}
+
+static int tpem_listen( int socket, int backlog ) {
+       return tpem_listen_state;
+}
+
+static int tpem_socket( int domain, int type, int protocol ) {
+       static int fd = 1;
+
+       if( tpem_sock_state == 0 ) {
+               if( ++fd > 10 ) {
+                       fd = 1;
+               }
+
+               return fd;
+       }
+
+       return -1;
+}
+
+/*
+       redefine all system calls to reference functions here. There are two defs
+       SI functions should use the capitalised verision so that sliding ff under
+       it is possible. There might be instances wehre the actual system call is
+       needed, so we also define the lowercase value.
+*/
+#define BIND tpem_bind
+#define bind tpem_bind
+#define CONNECT tpem_connect
+#define connect tpem_connect
+#define getsockname tpem_getsockname
+#define SOCKET tpem_socket
+#define socket tpem_socket
+#define LISTEN tpem_listen
+#define listen tpem_listen
+
+/*
+       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
+#define RECVMSG                recvmsg
+
+
+
+#endif
+