/*
**************************************************************************
-* Mnemonic: SIterm
-* Abstract: This routine will terminate a session based on the tp_blk
-* that is passed into the routine. The transport session block
-* is released and removed from the ginfo list. The session is
-* terminated by issuing a t_unbind call (if the unbind flag is
-* on in the tpptr block), and then issuing a t_close.
-* Parms: gptr - Pointer to the global information block
-* tpptr - Pointer to tp block that defines the open fd.
-* Returns: Nothing.
-* Date: 18 January 1995
-* Author: E. Scott Daniels
+* 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
+* thread. When safe, the SIrm_tpb() function can be called to
+* do the rest of the work that was originally done by SIterm.
+*
+* Date: 18 January 1995
+* Author: E. Scott Daniels
*
**************************************************************************
*/
-#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. 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
}
}
- 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
- }
+ tpptr->fd = -1; // prevent future sends etc.
+ tpptr->flags |= TPF_DELETE; // signal block deletion needed when safe
+ }
+}
- if( tpptr->next != NULL ) {
- tpptr->next->prev = tpptr->prev; // point next one back behind this one
+/*
+ It is safe to remove the block from the list; if it was in the list
+ 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
+ } else {
+ 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
+ }
}
- 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
}
}