Add safe connect, fix possible seg fault in RTC
[ric-plt/lib/rmr.git] / src / rmr / si / src / si95 / siterm.c
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
        }
 }