Address multi-threading issues in SI95

There are potential issues when a uer application is multi-threaded
and disconnections are noticed.  This change addresses these issues.

Signed-off-by: E. Scott Daniels <daniels@research.att.com>
Change-Id: Ie586cfe6294429b299e0044b2f6bf315d78104ce
diff --git a/src/rmr/si/src/si95/sibldpoll.c b/src/rmr/si/src/si95/sibldpoll.c
index 6ad26ea..5b50fcc 100644
--- a/src/rmr/si/src/si95/sibldpoll.c
+++ b/src/rmr/si/src/si95/sibldpoll.c
@@ -52,7 +52,10 @@
 	for( tpptr = gptr->tplist; tpptr != NULL; tpptr = nextb ) {
 		nextb = tpptr->next;
 		if( tpptr->flags & TPF_DELETE ) {
-			SIterm( gptr, tpptr );
+			if( tpptr->fd >= 0 ) {						// wasn't closed for some reason
+				SIterm( gptr, tpptr );
+			}
+			SIrm_tpb( gptr, tpptr );					// safe to remove the block from the list in this thread
 		} else {
 			if( tpptr->fd >= 0 ) {                       //  if valid file descriptor 
 				if( tpptr->fd >= gptr->fdcount ) {	
diff --git a/src/rmr/si/src/si95/siclose.c b/src/rmr/si/src/si95/siclose.c
index cb5cf36..eed11ef 100644
--- a/src/rmr/si/src/si95/siclose.c
+++ b/src/rmr/si/src/si95/siclose.c
@@ -18,7 +18,7 @@
 ==================================================================================
 */
 
-/* X
+/*
 ******************************************************************************
 *
 *  Mnemonic: SIclose
@@ -35,62 +35,51 @@
 *  Date:     3 February 1995
 *  Author:   E. Scott Daniels
 *
-*  Modified: 19 Feb 1995 - To set TP blk to drain if output pending.
-*            10 May 1995 - To change SOCK_RAW to SOCK_DGRAM
-*		22 Feb 2002 - To accept TCP_LISTEN_PORT or UDP_PORT as fd
+*  Modified:i	19 Feb 1995 - To set TP blk to drain if output pending.
+*				10 May 1995 - To change SOCK_RAW to SOCK_DGRAM
+*				22 Feb 2002 - To accept TCP_LISTEN_PORT or UDP_PORT as fd
 ******************************************************************************
 */
 #include "sisetup.h"
 
-extern int SIclose( struct ginfo_blk *gptr, int fd )
-{
+extern int SIclose( struct ginfo_blk *gptr, int fd ) {
+	struct tp_blk *tpptr;      //  pointer into tp list 
+	int status = SI_ERROR;     //  status of processing 
 
- struct tp_blk *tpptr;      //  pointer into tp list 
- int status = SI_ERROR;     //  status of processing 
+	if( gptr != NULL ) {
+		if( fd >= 0 ) {						//  if caller knew the fd number 
+			if( fd < MAX_FDS ) {			// straight from map if possible
+				tpptr = gptr->tp_map[fd];
+			} else {
+				// future: need to lock the list or switch to gmax hash
+				for( tpptr = gptr->tplist; tpptr != NULL && tpptr->fd != fd; tpptr = tpptr->next );   //  find the tppblock to close
+			}
+		} else {  //  user did not know the fd - find first Listener or UDP tp blk 
+			if( fd == TCP_LISTEN_PORT ) {			//  close first tcp listen port; else first udp 
+				for( tpptr = gptr->tplist; tpptr != NULL && !(tpptr->flags&& TPF_LISTENFD); tpptr = tpptr->next );   
+			} else {
+				for( tpptr = gptr->tplist; tpptr != NULL && tpptr->type != SOCK_DGRAM; tpptr = tpptr->next );
+			}
+		}
 
- gptr->sierr = SI_ERR_HANDLE;
- if( gptr->magicnum == MAGICNUM )   //  good cookie at the gptr address? 
-  {
-   gptr->sierr = SI_ERR_SESSID;
-
-   if( fd >= 0 )     //  if caller knew the fd number 
-    {
-     for( tpptr = gptr->tplist; tpptr != NULL && tpptr->fd != fd;
-          tpptr = tpptr->next );   //  find the tppblock to close 
-    }
-   else  //  user did not know the fd - find first Listener or UDP tp blk 
-   {
-	if( fd == TCP_LISTEN_PORT )			//  close first tcp listen port; else first udp 
-     		for( tpptr = gptr->tplist; tpptr != NULL && !(tpptr->flags&& TPF_LISTENFD); tpptr = tpptr->next );   
-	else
-    		for( tpptr = gptr->tplist; tpptr != NULL && tpptr->type != SOCK_DGRAM; tpptr = tpptr->next );
-   }
-
-   if( tpptr != NULL )
-    {
-     gptr->sierr = SI_ERR_TP;
-
-     if( tpptr->squeue == NULL )   //  if nothing is queued to send... 
-      {
-       tpptr->flags |= TPF_UNBIND;   //  ensure port is unbound from tp 
-	tpptr->flags |= TPF_DELETE;
-	{
-		int x = 1;
-
-		setsockopt(tpptr->fd, SOL_SOCKET, SO_LINGER, (char *)&x, sizeof( x ) ) ;
+		if( tpptr != NULL ) {
+			if( tpptr->squeue == NULL ) {   //  if nothing is queued to send... 
+				tpptr->flags |= TPF_UNBIND;   //  ensure port is unbound from tp 
+				tpptr->flags |= TPF_DELETE;
+				{
+					int x = 1;
+					setsockopt(tpptr->fd, SOL_SOCKET, SO_LINGER, (char *)&x, sizeof( x ) ) ;
+				}
+	
+				SIterm( gptr, tpptr );		// close the fd and mark the block as deletable
+			} else {
+				tpptr->flags |= TPF_DRAIN;   //  stuff on queue, must drain before closing
+			}
+	
+			status = SI_OK;               //  give caller a good status 
+		}                              //  end if we found a tpptr 
 	}
-	close( tpptr->fd );
-	tpptr->fd = -1;
-	tpptr->type = -1;
-			//  siterm now called in build poll if tp is marked delete 
-       // SIterm( gptr, gptr, tpptr );*/        /* cleanup and remove from the list 
-      }
-     else                       	//  stuff queued to send - mark port to drain 
-      tpptr->flags |= TPF_DRAIN;   //  and we will term the port when q empty 
 
-     status = SI_OK;               //  give caller a good status 
-    }                              //  end if we found a tpptr 
-  }                                //  end if the handle was good 
-
- return( status );                 //  send the status back to the caller 
+	return status;                 //  send the status back to the caller 
 }                                  //  SIclose 
+
diff --git a/src/rmr/si/src/si95/siconnect.c b/src/rmr/si/src/si95/siconnect.c
index 842207f..114e873 100644
--- a/src/rmr/si/src/si95/siconnect.c
+++ b/src/rmr/si/src/si95/siconnect.c
@@ -62,24 +62,20 @@
 			return SI_ERROR;
 		}
 
-		gptr->sierr = SI_ERR_HANDLE;
 		if( gptr->magicnum != MAGICNUM ) {		// no cookie -- no connection
 			return SI_ERROR;
 		}
 	}
 
-	gptr->sierr = SI_ERR_TPORT;
 	tpptr = SIconn_prep( gptr, TCP_DEVICE, abuf, 0 );			// create tp struct, and socket. get peer address 0 == any family that suits the addr
 	if( tpptr != NULL ) {
 		taddr = tpptr->paddr;
-		gptr->sierr = SI_ERR_TP;
 		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 
-			gptr->sierr = 0;
 			tpptr->flags |= TPF_SESSION;    		//  indicate we have a session here 
 			tpptr->next = gptr->tplist;     		//  add block to the list 
 			if( tpptr->next != NULL ) {
diff --git a/src/rmr/si/src/si95/siestablish.c b/src/rmr/si/src/si95/siestablish.c
index bdb3f72..846faa1 100644
--- a/src/rmr/si/src/si95/siestablish.c
+++ b/src/rmr/si/src/si95/siestablish.c
@@ -109,12 +109,12 @@
 			if( status == SI_OK ) {
 				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, ">>>>> 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 ) );
+			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 
diff --git a/src/rmr/si/src/si95/siinit.c b/src/rmr/si/src/si95/siinit.c
index 9159f69..b297124 100644
--- a/src/rmr/si/src/si95/siinit.c
+++ b/src/rmr/si/src/si95/siinit.c
@@ -62,8 +62,6 @@
 		}
 		memset( gptr->tp_map, 0, sizeof( struct tp_blk *) * MAX_FDS );
 
-		gptr->sierr = SI_ERR_TPORT;
-	
 		gptr->cbtab = (struct callback_blk *) malloc(
 			(sizeof( struct callback_blk ) * MAX_CBS ) );
 		if( gptr->cbtab != NULL ) {
@@ -76,8 +74,6 @@
 			free( gptr );
 			gptr = NULL;       //  dont allow them to continue 
 		}
-
-		gptr->sierr = SI_OK;
 	}                     //  end if gen infor block allocated successfully 
 
 	
diff --git a/src/rmr/si/src/si95/silisten.c b/src/rmr/si/src/si95/silisten.c
index c7151d4..8cd484a 100644
--- a/src/rmr/si/src/si95/silisten.c
+++ b/src/rmr/si/src/si95/silisten.c
@@ -49,12 +49,10 @@
 		if( gptr == NULL ) {
 			return status;
 		}
-		gptr->sierr = SI_ERR_HANDLE;
 		if( gptr->magicnum != MAGICNUM )   			//  good cookie at the gptr address?
 			return status;
 	}
 
-	gptr->sierr = SI_ERR_TP;
 	tpptr = SIlisten_prep( gptr, type, abuf, 0 );
 
 	if( tpptr != NULL )                          //  established a fd bound to the port ok
diff --git a/src/rmr/si/src/si95/sipoll.c b/src/rmr/si/src/si95/sipoll.c
index df71eae..0ecca66 100644
--- a/src/rmr/si/src/si95/sipoll.c
+++ b/src/rmr/si/src/si95/sipoll.c
@@ -59,14 +59,10 @@
  struct timeval  delay;        //  delay to use on select call
  struct sockaddr *uaddr;       //  pointer to udp address
 
- gptr->sierr = SI_ERR_SHUTD;
-
  if( gptr->flags & GIF_SHUTDOWN )     //  cannot do if we should shutdown
   return( SI_ERROR );                    //  so just get out
 
 
- gptr->sierr = SI_ERR_HANDLE;
-
  if( gptr->magicnum != MAGICNUM )     //  if not a valid ginfo block
   return( SI_ERROR );
 
@@ -156,7 +152,7 @@
                 SIaddress( uaddr, (void **) &buf, AC_TODOT );
                 status = (*cbptr)( gptr->cbtab[SI_CB_RDATA].cbdata, gptr->rbuf, status, buf );
                 SIcbstat( gptr, status, SI_CB_RDATA );    //  handle status
-		free( buf );
+				free( buf );
                }                              //  end if call back was defined
              }                                //  end if status was ok
             free( uaddr );
@@ -190,7 +186,6 @@
 
  if( gptr->flags & GIF_SHUTDOWN )      //  we need to stop for some reason
   {
-   gptr->sierr = SI_ERR_SHUTD;        //  indicate error exit status
    status = SI_ERROR;                //  status should indicate to user to die
    SIshutdown( gptr );            //  clean things up
   }
diff --git a/src/rmr/si/src/si95/siproto.h b/src/rmr/si/src/si95/siproto.h
index bb94d2a..c59d626 100644
--- a/src/rmr/si/src/si95/siproto.h
+++ b/src/rmr/si/src/si95/siproto.h
@@ -48,6 +48,7 @@
 extern int SInewsession( struct ginfo_blk *gptr, struct tp_blk *tpptr );
 extern int SIpoll( struct ginfo_blk *gptr, int msdelay );
 extern int SIrcv( struct ginfo_blk *gptr, int sid, char *buf, int buflen, char *abuf, int delay );
+extern void SIrm_tpb( struct ginfo_blk *gptr, struct tp_blk *tpptr );
 extern void SIsend( struct ginfo_blk *gptr, struct tp_blk *tpptr );
 extern int SIsendt( struct ginfo_blk *gptr, int fd, char *ubuf, int ulen );
 extern void SIset_tflags( struct ginfo_blk* gp, int flags );
diff --git a/src/rmr/si/src/si95/sircv.c b/src/rmr/si/src/si95/sircv.c
index 2202629..d69cb61 100644
--- a/src/rmr/si/src/si95/sircv.c
+++ b/src/rmr/si/src/si95/sircv.c
@@ -58,11 +58,9 @@
 	char 	*acbuf;		//  pointer to converted address 
  int addrlen;
 
- gptr->sierr = SI_ERR_HANDLE;              //  set errno before we fail 
  if( gptr->magicnum != MAGICNUM )     //  if not a valid ginfo block 
   return SI_ERROR;
 
- gptr->sierr = SI_ERR_SESSID;             //  set errno before we fail 
  for( tpptr = gptr->tplist; tpptr != NULL && tpptr->fd != sid;
       tpptr = tpptr->next );      //  find transport block 
  if( tpptr == NULL )
@@ -71,7 +69,6 @@
  uaddr = (struct sockaddr *) malloc( sizeof( struct sockaddr ) );
  addrlen = sizeof( *uaddr );
 
- gptr->sierr = SI_ERR_SHUTD;               //  set errno before we fail 
  if( ! (gptr->flags & GIF_SHUTDOWN) )
   {                        //  if not in shutdown and no signal flags  
    FD_ZERO( &readfds );               //  clear select info 
@@ -87,22 +84,18 @@
      tptr->tv_usec = delay;
     }
 
-   gptr->sierr = SI_ERR_TP;
    if( (select( tpptr->fd + 1, &readfds, NULL, &execpfds, tptr ) < 0 ) )
     gptr->flags |= GIF_SHUTDOWN;     //  we must shut on error or signal 
    else
     {                                //  poll was successful - see if data ? 
-     gptr->sierr = SI_ERR_TIMEOUT;
      if( FD_ISSET( tpptr->fd, &execpfds ) )   //  session error? 
       {
        SIterm( gptr, tpptr );                 //  clean up our end of things 
-       gptr->sierr = SI_ERR_SESSID;               //  set errno before we fail 
       }
      else
       {
        if( (FD_ISSET( tpptr->fd, &readfds )) )
         {                                       //  process data if no signal 
-		gptr->sierr = SI_ERR_TP;
 		if( tpptr->type == SOCK_DGRAM )        //  raw data received 
 		{
 			status = RECVFROM( sid, buf, buflen, 0, uaddr, &addrlen );
diff --git a/src/rmr/si/src/si95/sisend.c b/src/rmr/si/src/si95/sisend.c
index 5a8a94e..c0233ae 100644
--- a/src/rmr/si/src/si95/sisend.c
+++ b/src/rmr/si/src/si95/sisend.c
@@ -46,7 +46,6 @@
 	struct t_unitdata *udata;      //  pointer at UDP unit data 
 	struct ioq_blk *qptr;          //  pointer at qio block for free 
 	int status;
-//static int announced = 0;	// TESTING
 
 	if( tpptr->squeue == NULL )    //  who knows why we were called 
 		return;                        //  nothing queued - just leave 
@@ -64,14 +63,6 @@
 	}
 */
 
-
-/*
-//TESTING
-if( !announced && status < tpptr->squeue->dlen ) {
-announced = 1;
-fprintf( stderr, ">>>>>>> !!!!!! SIsend: short send: %d != %d\n", status, tpptr->squeue->dlen );
-}
-*/
 	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 
@@ -82,6 +73,6 @@
 
 	if( (tpptr->flags & TPF_DRAIN) && tpptr->squeue == NULL )  //  done w/ drain? 
 	{
-		SIterm( gptr, tpptr );     //  trash the tp block 
+		SIterm( gptr, tpptr );     //  close the session and mark the block for delte
 	}
 }                      //  SIsend 
diff --git a/src/rmr/si/src/si95/sisendt.c b/src/rmr/si/src/si95/sisendt.c
index 81a3be6..8a4d5f0 100644
--- a/src/rmr/si/src/si95/sisendt.c
+++ b/src/rmr/si/src/si95/sisendt.c
@@ -56,19 +56,25 @@
 	int	sidx = 0;				// send index
 
 	errno = EINVAL;
-	gptr->sierr = SI_ERR_SESSID;
 
 	if( fd < 0 ) {
+		errno = EBADFD;
 		return SI_ERROR;					// bad form trying to use this fd
 	}
 
 	if( fd < MAX_FDS ) {					// straight from map if possible
 		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
 	}
 
 	if( tpptr != NULL ) {
+		if( (fd = tpptr->fd) < 0 ) {			// fd user given might not be real, and this might be closed already
+			errno = EBADFD;
+			return SI_ERROR;
+		}
+
 		tpptr->sent++;				// investigate: this may over count
 
 		FD_ZERO( &writefds );       //  clear for select call 
@@ -80,10 +86,9 @@
 		time.tv_usec = 1;			// small pause on check to help drain things
 
 		if( select( fd + 1, NULL, &writefds, &execpfds, &time ) > 0 ) {		//  would block if <= 0
-			gptr->sierr = SI_ERR_TP;
 			if( FD_ISSET( fd, &execpfds ) ) {   	//  error? 
 				errno = EBADFD;
-				SIterm( gptr, tpptr );   			//  clean up our portion of the session 
+				SIterm( gptr, tpptr );   			// mark block for deletion when safe
 				return SI_ERROR;					// and bail from this sinking ship
 			} else {
 				errno = 0;
@@ -112,91 +117,3 @@
 	return status;
 }
 
-/*
-	This routine will send a datagram to the TCP session partner
-	that is connected via the FD number that is passed in.
-	If the send would cause the process to block, the send is
-	queued on the tp_blk for the session and is sent later as
-	a function of the SIwait process.  If the buffer must be
-	queued, a copy of the buffer is created such that the
-	user program may free, or reuse, the buffer upon return.
-
-	Parms:i		gptr - The pointer to the global info structure (context)
-	            fd   - File descriptor (session number)
-	            ubuf - User buffer to send.
-	            ulen - Lenght of the user buffer.
-
-	Returns:  SI_OK if sent, SI_QUEUED if queued for later, SI_ERROR if error.
-*/
-#ifdef KEEP
-extern int new_SIsendt( struct ginfo_blk *gptr, int fd, char *ubuf, int ulen ) {
-	int status = SI_OK;         //  status of processing 
-	fd_set writefds;            //  local write fdset to check blockage 
-	fd_set execpfds;            //  exception fdset to check errors 
-	struct tp_blk *tpptr;       //  pointer at the tp_blk for the session 
-	struct ioq_blk *qptr;       //  pointer at i/o queue block 
-	struct timeval time;        //  delay time parameter for select call 
-
-	gptr->sierr = SI_ERR_HANDLE;
-
-	//if( gptr->magicnum == MAGICNUM ) {     //  ensure cookie is good  -- we need to be too performant for this
-	//{                                   //  mmmm oatmeal, my favorite 
-		gptr->sierr = SI_ERR_SESSID;
-
-		if( fd < MAX_FDS ) {					// straight from map if possible
-			tpptr = gptr->tp_map[fd];
-		} else {
-			for( tpptr = gptr->tplist; tpptr != NULL && tpptr->fd != fd; tpptr = tpptr->next ); //  find the block if out of map's range
-		}
-
-		if( tpptr != NULL ) {
-			tpptr->sent++;
-
-			FD_ZERO( &writefds );       //  clear for select call 
-			FD_SET( fd, &writefds );    //  set to see if this one was writable 
-			FD_ZERO( &execpfds );       //  clear and set execptions fdset 
-			FD_SET( fd, &execpfds );
-
-			time.tv_sec = 0;			//  set both to 0 if we just want a poll, else we block at max this amount
-			time.tv_usec = 1;			// small pause on check to help drain things
-
-			if( select( fd + 1, NULL, &writefds, &execpfds, &time ) > 0 ) {		//  see if it would block
-				gptr->sierr = SI_ERR_TP;
-				if( FD_ISSET( fd, &execpfds ) ) {   //  error? 
-					SIterm( gptr, tpptr );   			//  clean up our portion of the session 
-					return SI_ERROR;					// and bail from this sinking ship
-				} else {
-					if( tpptr->squeue ) {
-						SIsend( gptr, tpptr );			//  something queued; send off queue and queue this
-					} else {
-						return SEND( tpptr->fd, ubuf, (unsigned int) ulen, 0 );   //  done after send 
-					}
-				}
-			}
-
-			gptr->sierr = SI_ERR_NOMEM;
-
-			tpptr->qcount++;
-			if( (qptr = SInew( IOQ_BLK )) != NULL ) {		//  alloc a queue block 
-				if( tpptr->sqtail == NULL ) {				//  if nothing on the queue 
-					tpptr->squeue = qptr;         //  simple add to the tp blk q 
-					tpptr->sqtail = qptr;
-	 			} else  {                          		//  else - add at end of the q 
-	 				tpptr->sqtail->next = qptr;		
-					tpptr->sqtail = qptr;	
-					qptr->next = NULL;		//  new block is the last one now 
-				}    		                       //  end add block at end of queue 
-
-				qptr->dlen = ulen;           //  copy info to queue block 
-				qptr->data = (char *) malloc( ulen );  //  get buffer 
-				memcpy( qptr->data, (const char*) ubuf, ulen );
-	
-				gptr->sierr = SI_QUEUED;                //  indicate queued to caller 
-				status = SI_QUEUED;						// for return
-			}
-		}							//  end if tpptr was not found 
-	//}								//  ginfo pointer was corrupted 
-
-	return status;
-}
-#endif
diff --git a/src/rmr/si/src/si95/sishutdown.c b/src/rmr/si/src/si95/sishutdown.c
index 95b6f25..c76bc94 100644
--- a/src/rmr/si/src/si95/sishutdown.c
+++ b/src/rmr/si/src/si95/sishutdown.c
@@ -35,7 +35,6 @@
 #include "sisetup.h"                   //  get includes and defines 
 
 extern void SIshutdown( struct ginfo_blk *gptr ) {
-	gptr->sierr = SI_ERR_HANDLE;
 	if( gptr != NULL && gptr->magicnum == MAGICNUM )
 	{
  		gptr->flags |=  GIF_SHUTDOWN;    //  signal shutdown 
@@ -43,7 +42,6 @@
 		{
 			gptr->tplist->flags |= TPF_UNBIND;    //  force unbind on session 
 			SIterm( gptr, gptr->tplist );         //  and drop the session 
-		}                                      //  end while 
-		gptr->sierr = 0;
+		}
 	}
 }            
diff --git a/src/rmr/si/src/si95/siterm.c b/src/rmr/si/src/si95/siterm.c
index 0b74ba0..8b732f6 100644
--- a/src/rmr/si/src/si95/siterm.c
+++ b/src/rmr/si/src/si95/siterm.c
@@ -20,23 +20,26 @@
 
 /*
 **************************************************************************
-*  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 "sitransport.h"
 
+/*
+	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.
+*/
 extern void SIterm( struct ginfo_blk* gptr, struct tp_blk *tpptr ) {
 
 	if( tpptr != NULL ) {
@@ -47,14 +50,28 @@
 			}
 		}
 
-		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 
diff --git a/src/rmr/si/src/si95/siwait.c b/src/rmr/si/src/si95/siwait.c
index cf06838..0d1e3e5 100644
--- a/src/rmr/si/src/si95/siwait.c
+++ b/src/rmr/si/src/si95/siwait.c
@@ -71,14 +71,10 @@
 
 	ibuf = (char *) malloc( 2048 );
 
-	gptr->sierr = SI_ERR_SHUTD;
-
 	if( gptr->flags & GIF_SHUTDOWN ) {				//  cannot do if we should shutdown 
 		return SI_ERROR;							//  so just get out 
 	}
 
-	gptr->sierr = SI_ERR_HANDLE;
-
 	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;
@@ -127,7 +123,7 @@
 										status = (*cbptr)( gptr->cbtab[SI_CB_DISC].cbdata, tpptr->fd );
 										SIcbstat( gptr, status, SI_CB_DISC );	//  handle status 
 									}
-									SIterm( gptr, tpptr );
+									SIterm( gptr, tpptr );			// close FD and mark block for deletion
 								}
 							}
 						}
@@ -139,10 +135,8 @@
 
 	free( ibuf );
 	if( gptr->tplist == NULL )					//  indicate all fds closed 
-		gptr->sierr = SI_ERR_NOFDS;
 
 	if( gptr->flags & GIF_SHUTDOWN ) {			//  we need to stop for some reason 
-		gptr->sierr = SI_ERR_SHUTD;				//  indicate error exit status 
 		status = SI_ERROR;						//  status should indicate to user to die 
 		SIshutdown( gptr );						//  clean things up 
 	} else {