/*!
  @file           ven75.c
  @author         JoergM
  @brief          Kernel Runtime: Communication Functions for Kernel
  @see            

\if EMIT_LICENCE

    ========== licence begin  GPL
    Copyright (c) 2001-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end



\endif
*/

#define MOD__  "ven75.c:"
/* exported functions */

#include "gen00.h"
#include "heo00.h"
#include "gen500.h"
#include "vsp001c.h"
#include "gen003.h"
#include "hen40.h"

/* imported functions */

#include "geo50_0.h"
#include "gen32.h"
#include "gen41.h"
#include "gen46.h"
#if defined(AIX) || defined(HP9)
#include "gen49.h" /* nocheck */
#endif /* AIX || HP9 */
#include "gen71.h"
#include "gen73.h"
#include "gen74.h"
#include "gen75.h"
#include "gen88.h"
#include "geo67.h"
#include "hsp77.h"

/*
 * =====================================================================
 */

int	e75_wake_peer ( connection_info *cip )
{
#undef  MF__
#define MF__ MOD__"e75_wake_peer"
    int				rc ;
    int				index ;
    int				fd ;
    int             ret ;

    DBGIN;

	ret = SP1CE_OK;

    while ( ret == SP1CE_OK )
	{
		DBG1 (( MF__,"semop semid %d \n", cip->ci_peer_semid ));
		rc = semop ( cip->ci_peer_semid , &semsnd , 1 );
		if ( rc == UNDEF )
		{
			if ( errno == EINTR )
			{
				MSGD (( WRN_DISTRIB_WAKE_SEMOP_ERR ))
				continue;
			}

			/*
			 *  Ignore a semaphore value overrun.
			 */
			if ( errno != ERANGE )
			{
				MSGD (( ERR_DISTRIB_WAKE_SEMOP, sqlerrs() ));
				sql41_stat_sem ( cip->ci_peer_semid );
				ret = SP1CE_NOTOK;
			}
		}
		else
		{
			break;
		}
	}

    DBG1 (( MF__,"Returning %d \n", ret ));

	DBGOUT;
    return ( ret );
}

/*
 *  =======================================================================
 */

void	e75_release_all_ukp_tasks ( )
{
#undef  MF__
#define MF__ MOD__"e75_release_all_ukp_tasks"

ten50_UKT_Control               * this_ukt = THIS_UKT_CTRL;
    struct TASK_TYPE		*tcb ;

	DBGIN;
    /*
     *  This function is intended to be called from dispatcher,
     *  where the value of this_ukt->curr_task is changed anyway.
     *  If someone later tries to call it from elsewhere,
     *  it is safer to save the original value of this_ukt->curr_task.
     *  We need to set this_ukt->curr_task for usage within e75_release_connection.
     */
    tcb = this_ukt->curr_task ;

    for ( this_ukt->curr_task = this_ukt->pFirstTaskCtrl ;
		  this_ukt->curr_task ;
		  this_ukt->curr_task = this_ukt->curr_task->next_task )
    {
		DBG1 (( MF__,"Shutdown test T%d \n", this_ukt->curr_task->index ));
		if ( (this_ukt->curr_task->type == TT_US || this_ukt->curr_task->type == TT_EV) 
	      && e75_is_connected(this_ukt->curr_task) )
		{
		    e75_release_connection ( SP1CE_SHUTDOWN, FALSE ); /* no wait */
		}
    }

    this_ukt->curr_task = tcb ;

	DBGOUT;
}

/* ======================================================================= */

/* PTS 1113008 */
void en75FinalReleaseConnections( int kernelExitCode )
{
	struct TASK_TYPE *tcb;
	int taskIndex;
	int reason = ( kernelExitCode == 0 ? SP1CE_SHUTDOWN : SP1CE_CRASH );

    for ( taskIndex = 0; taskIndex < KGS->ulNumOfTasks; taskIndex++ )
    {
        tcb = KGS->pFirstTaskCtrl + taskIndex;
        if ( (tcb->type == TT_US || tcb->type == TT_EV || tcb->type == TT_UT) 
		  && e75_is_connected(tcb) )
        {
            comseg_header *comseg;
            connection_info *cip = tcb->connection;
            /* Shared memory id of big commsect is found in ukt->connection info only */
            char *addr = (char *)sql41_attach_shm ( tcb->ukt->connection->ci_shmid,
                                                    (char *) 0 );
            if ( ((char *)0) == addr )
            {
                MSGD(( ERR_INITCOM_ATT_ADDR_BIGCOM,  (long) addr ))
                continue;
            }

            /* Setting the cs_server_state is all that is needed, to inform the peer
               about SHUTDOWN or CRASH state */
            comseg = (comseg_header *)(addr + cip->ci_big_offset);
            comseg->cs_server_state = reason;
            if ( reason != SP1CE_SHUTDOWN )
            {
    			MSGD (( WRN_RELEASE_TSK_BY_REASON, tcb->index , "kernel abort" ));
            }
            else
            {
    		    MSGD (( INFO_RELEASING_TSK, tcb->index ));
            }

            /* PTS 1113359 */
#if defined(_IBMR2) || defined(PA11) || defined(PA20W) || defined(NMP)
            e49_unlock_int4_4fold ( &comseg->cs_exclusive , 1 ) ;
#else
            CLEARLOCK ( &comseg->cs_exclusive );
#endif
            /* We do not inform the task about release state here !!!
               It will get informed by removing semaphore later on */
            sql41_detach_shm ( &addr );
#ifdef SDB_WITH_PROFILER
            /* If profiling is used, the semaphore is not removed, so we inform client now */
            (void)semop ( cip->ci_peer_semid , &semsnd , 1 );
#endif /* SDB_WITH_PROFILER */
        }
    }
}

/*
 *  =======================================================================
 */

void e75_release_connection ( int reason ,
                              int waitflag )
{
#undef  MF__
#define MF__ MOD__"e75_release_connection"

	ten50_UKT_Control *this_ukt = THIS_UKT_CTRL;
    struct TASK_TYPE  *tcb = this_ukt->curr_task;
    int				idx ;
    int				oldstate ;
    int				tskstate ;
    long			off ;
    rte_header      *header ;
    comseg_header   *comseg ;
    connection_info *cip ;
    char            *errmsg ;
    tsp00_ErrTextc   errtext ;
    int wait_for_client = waitflag;

	DBGIN;
    cip = tcb->connection;
#ifdef DEBUG_RTE
    DBG1 (( MF__,"Releasing  T%d  reason %d wait %d",
		tcb->index , reason , waitflag ));
#endif
    if ( cip->ci_connect_time )
    {
		if ( reason != SP1CE_OK )
		{
			switch ( reason )
			{
				case SP1CE_TIMEOUT :
					errmsg = "command timeout" ;
					break ;
				case SP1CE_CRASH :
					errmsg = "connection aborted" ;
					break ;
				case SP1CE_SHUTDOWN :
					errmsg = "database shutdown" ;
					break ;
				case SP1CE_RELEASED :
					errmsg = "without reply" ;
					break ;
				default :
					(void) sp77sprintf ( errtext , sizeof(errtext), "reason: %d" , (int) reason );
					errmsg = errtext ;
					break ;
			}
			MSGD (( WRN_RELEASE_TSK_BY_REASON, tcb->index , errmsg ));
		}
		else
		    MSGD (( INFO_RELEASING_TSK, tcb->index ));
    }

    /* FH
     *  Set stat_receive to SP1CE_CRASH to indicate to the REQUESTOR
     *  (e84_test_application), that this task will be released at
     *  this time. In this case the function e84_test_application 
     *  should NOT test the application.
     *  It is possible that we have a time-problem, and the requestor
     *  will kill the task for the application, which made this release,
     *  so the application thinks: kernel broke connection!
     *  (The UKP has not made the vrelease completely,
     *  a new connect has been received by the requestor.)
     */
    tskstate = tcb->state ;
    tcb->state = TSK_VRELEASE ;
    oldstate = cip->ci_state ;

	if ( cip->ci_state != CON_UNUSED )
    {
        if ( tcb->type == TT_EV )
        {
            eo67ReleaseEventTask(tcb->index);
        }
        else
        {
            /* PTS 1004575 */
            eo67InsertSessionEvent(false, tcb->index);
        }
    }

    cip->ci_state = CON_UNUSED ;
    /*
     *  Only if still attached
     */
    comseg = cip->ci_comseg;
    DBG1 (( MF__,"comseg 0x%08lx", (long) comseg ));
    if ( comseg )
    {
		DBG1 (( MF__,"cli,srv %d,%d",
		    comseg->cs_client_flag , comseg->cs_server_flag ));
		if ( reason != SP1CE_OK )
		{
			DBG1 (( MF__,"clearing comseg values" ));
			sql32_lock_comseg ( cip , "e75_release: 0x%08lx \n" );
			idx = comseg->cs_current_packet ;
			if ( (idx < 0) || (idx > cip->ci_packet_cnt) ) idx = 0 ;
			comseg->cs_current_packet = idx ;
			header = cip->ci_packet[idx];
			off = (long) header->rh_max_send_len & 7L ;
			header = (rte_header*) ((char*) header + header->rh_max_send_len);
			if ( off )
			{
				header = (rte_header*) ((char*) header + 8L - off);
			}
			FILL ( header , 0 , RTE_HEADER_SIZE );
			header->rh_act_send_len    = RTE_HEADER_SIZE_EO003 ;
			header->rh_max_send_len    = RTE_HEADER_SIZE_EO003 ;
			header->rh_mess_class      = RSQL_USER_RELEASE_REQUEST_EO003 ;
			header->rh_rte_return_code = reason ;
			comseg->cs_server_state = reason ;
			comseg->cs_server_pid   = 0 ;
			comseg->cs_server_ref   = 0 ;
			comseg->cs_server_semid = 0 ;
			comseg->cs_server_flag  = 1 ;
            if ( SP1CE_RELEASED == comseg->cs_client_state )
            {
                wait_for_client = false;
            }
			sql32_unlock_comseg ( cip );

            if ( oldstate != CON_REPLIED && wait_for_client )
			{
                int rc = e75_wake_peer ( cip );
                if ( rc != SP1CE_OK )
                {
                    int logLength ;
                    char logbuf[512];
    				struct tm timeBuffer;
	    			struct tm *pTime = localtime_r( &cip->ci_connect_time, &timeBuffer );
                    if ( pTime )
                    {
                        (void) sp77sprintf ( logbuf , sizeof(logbuf), "Client died to early? (e75_release_connection) Connected to T%d since %02d:%02d:%02d",
                            tcb->index, pTime->tm_hour, pTime->tm_min, pTime->tm_sec );
                    }
                    else
                    {
                        (void) sp77sprintf ( logbuf , sizeof(logbuf), "Client died to early? Connected to T%d since ?%ld?",
                            tcb->index, (long)cip->ci_connect_time );
                    }
                    logLength = strlen ( logbuf );
                    if ( cip->ci_peer_node[0] )
		                (void) sp77sprintf ( logbuf + logLength , sizeof(logbuf) - logLength, " remote %s" , cip->ci_peer_node );
                    else
		                (void) sp77sprintf ( logbuf + logLength , sizeof(logbuf) - logLength, " local" );
                    logLength = strlen ( logbuf );
                    if ( cip->ci_remote_pid[0] )
		                (void) sp77sprintf ( logbuf + logLength , sizeof(logbuf) - logLength, " remote_pid %s" , cip->ci_remote_pid );
                    logLength = strlen ( logbuf );
		            (void) sp77sprintf ( logbuf + logLength , sizeof(logbuf) - logLength, " peer_pid %ld" , (long) cip->ci_peer_pid );
    				MSGD (( ERR_DISTRIB_WAKE_SEMOP, logbuf ));
                }
			}
		}

		if ( wait_for_client )
		{
			tcb->task_timeout = LOCL_PKT_TMO + KGS->current_time + MAXSLEEPTIME ;
			/*
			 *  insert task into COM queue, where it waits for a packet
			 */
			e71_com ( tcb );

			DBG1 (( MF__,"goto_disp  T%d", tcb->index ));
            GOTO_DISP (&this_ukt);
			DBG1 (( MF__,"from disp  T%d", tcb->index ));
		}

		/*
		 *  Might be that the application did not yet see the server flag
		 *  due to UNIX scheduling. Nevertheless, we must not release the
		 *  comseg with the server flag set, it could be misunderstood at
		 *  the next connect.
		 */
		comseg->cs_server_state = (reason == SP1CE_OK) ?
						SP1CE_RELEASED : reason ;
		comseg->cs_server_pid   = 0 ;
		comseg->cs_server_ref   = 0 ;
		comseg->cs_server_semid = 0 ;
		comseg->cs_server_flag  = 0 ;

		e74_release_comseg ( cip, tcb );
		cip->ci_comseg = 0 ;
    }  

    if ( cip->ci_peer_semid > 0 )
    {
		DBG1 (( MF__,"removing client semaphore" ));
		(void) sql41_remove_sem ( &cip->ci_peer_semid , "us" , (char *)KGS->serverdb );
    }

    cip->ci_peer_pid   = 0 ;
    FILL ( cip->ci_remote_pid , 0 , sizeof(cip->ci_remote_pid) );

    if ( cip->ci_connect_time )
    {
        WAIT_UNTIL_ALONE ( tcb->ukt->exclusive );
        if ( cip->ci_connect_time )
        {
            cip->ci_connect_time = 0 ;

            /* cip->ci_state = CON_UNUSED ; already done above */
            KGS->connectedUserTasks -= this_ukt->curr_task->type == TT_US ? 1 : 0;
        }
        CLEARLOCK ( tcb->ukt->exclusive );
    }

    tcb->state = tskstate ;

    DBGOUT;
}

/*
 * ===========================================================================
 */

int    e75_has_com ( struct TASK_TYPE *tcb )
{
#undef  MF__
#define MF__ MOD__"e75_has_com"
    connection_info *cip ;
    comseg_header   *comseg ;
    time_t           clock_time ;

	DBGIN;

	cip = tcb->connection;

    if ( !cip )
    {
        DBG1 (( MF__,"no connection" ));
		DBGOUT;
        return false;
    }

    /* check for died application */
    if ( cip->ci_state == CON_ABORTED )
	{
        DBG1 (( MF__,"connection aborted" ));
		DBGOUT;
		return true;
	}

    /*
     *  A user task got a packet if cs_client_flag == 1.
     */
    comseg = cip->ci_comseg ;
    if ( comseg && (comseg->cs_client_flag == 1) )
    {
		DBG1 (( MF__,"COM      T%d cli,srv %d,%d",
			tcb->index ,
			comseg->cs_client_flag , comseg->cs_server_flag ));
		comseg->cs_client_flag = 2 ;
		comseg->cs_server_flag = 0 ;
		DBGOUT;
		return true;
    }

    /* dont use actual time (to expensive to get... 
      KGS->curr_time may be not up to date, but it
      is good enough for checking task timeout */
    if ( MAXTIMEVALUE != tcb->task_timeout
      && tcb->type != TT_UT )
    {
        clock_time = KGS->current_time;

        /*
         *  Check for timeout.
         *  IST 1994-09-07: hanging shutdown:
         *  using <= istead of < for disabled command timeout.
         */
        if ( tcb->task_timeout <= clock_time )
        {
		    /*
		     * timeout found
		     */
		    DBG1 (( MF__,"timeout T%d since %d seconds", 
                tcb->index , (long) (clock_time - tcb->task_timeout) ));
		    tcb->connection->ci_state = CON_TIMEDOUT ;
		    DBGOUT;
		    return true;
        }
    }

    DBG1 (( MF__,"no packet" ));
	DBGOUT;
    return false;
}

/*
 * ===========================================================================
 */

int     e75_is_connected ( struct TASK_TYPE	*tcb )
{
#undef  MF__
#define MF__ MOD__"e75_is_connected"
	DBGIN;
	if ( tcb->connection
	  && tcb->connection->ci_connect_time )
	{
		DBG1 (( MF__,"connected" ));
		DBGOUT;
		return ( TRUE );
	}
	DBG1 (( MF__,"not connected" ));
	DBGOUT;
    return ( FALSE ) ;
}

/*
 * ===========================================================================
 */

int e75_connect_request ( struct TASK_TYPE  * tcb,
                          connection_info   * cip )
{
#undef  MF__
#define MF__ MOD__"e75_connect_request"
    ten50_UKT_Control * this_ukt = THIS_UKT_CTRL;
    int				    rc ;
    int				    stack_avail = TRUE ;
    tsp1_comm_error		result ;
    comseg_header		*comseg ;
    char			logbuf [ 256 ];

	DBGIN;

    DBG1 (( MF__,"connecting T%d", tcb->index ));

    result = SP1CE_OK ;

    DBG1 (( MF__,"T%d my_ref %d peer_ref %d",
	    tcb->index,
	    cip->ci_my_ref , cip->ci_peer_ref ));

    /*
     *  Cleanup
     */
    if ( cip->ci_comseg )
    {
		MSGD (( WRN_CONNECT_LAST_COMSEG, (long) cip->ci_comseg ));
		e74_release_comseg ( cip, tcb );
		cip->ci_comseg = 0 ;
    }
    /*
     *  If, some day, multiple packets are required,
     *  we have to set up the big comseg and comseg within it
     *  to support the requested number of packets: cip->ci_packet_cnt.
     */

    /*
     *  Map task to shared memory segment
     */
    rc = sql32_attach_comseg ( cip );
    if ( rc != SP1CE_OK )
    {
		MSGD (( WRN_CONNECT_CLIENT_LOST ));
		/*
		 *  the action is: re-init task and wait for next connect !
		 */
		cip->ci_connect_time = 0 ; /* mark as not connected anymore */
		rc = tcb->state ;
		if ( rc != TSK_INACTIVE ) rc = TSK_CONNECTWAIT ;
		e75_release_connection ( SP1CE_NOTOK , FALSE ); /* no wait */
		tcb->state = rc ;
		return ( -1 );
    }

    KGS->connectedUserTasks += this_ukt->curr_task->type == TT_US ? 1 : 0;

    comseg = cip->ci_comseg ;
    sql32_unlock_comseg ( cip );

	if ( (tcb->state != TSK_CONNECTWAIT) &&
		 (tcb->state != TSK_INACTIVE)         )
	{
		/*
		 *  The task could be already connected:
		 *  - On a late remote request, after the connect reservation
		 *    has just been cancelled.
		 *  - On an expropriation of TT_UT for local re-use.
		 */
#define WRN_TASK_ALREADY_CONNECTED  11845,WRN_TYPE,"COMMUNIC","Connect reject for Task T%d already connected (%d)"
		MSGD (( WRN_TASK_ALREADY_CONNECTED, tcb->index, tcb->state ));
		result = SP1CE_NOTOK ;
	}
	else
	{
		/*
		 *  Create the user task's stack.
		 */
		if (    (tcb->state == TSK_INACTIVE)
			 && (tcb->type  == TT_US) )
		{
			stack_avail = en88_InitDynPthreadTasks(tcb);
			if ( ! stack_avail )
			{
				MSGD (( WRN_CONNECT_NO_STACK_MEM, tcb->index ));
				result = SP1CE_TASKLIMIT ;
			}
		}
    }


    if ( cip->ci_state == CON_ABORTED ) /* PTS 1113931 */
    {
		MSGD (( WRN_RELEASE_TSK_BY_REASON, tcb->index, "connection timeout" ));
        result = SP1CE_TIMEOUT;
    }
    /* if state is set to CON_ABORTED now before set to CON_ESTABLISHED below it is silently ignored */

    sql32_lock_comseg ( cip , "e75_connect: 0x%08lx \n" );
    DBG1 (( MF__,"OLDcli pid %ld ref %d flg %d",
		(long) comseg->cs_client_pid , comseg->cs_client_ref ,
		comseg->cs_client_flag ));
    DBG1 (( MF__,"OLDsrv pid %ld ref %d flg %d sem %d",
		(long) comseg->cs_server_pid , comseg->cs_server_ref ,
		comseg->cs_server_flag , comseg->cs_server_semid ));
    FILL ( cip->ci_request , 0 , cip->ci_max_data_size );
    comseg->cs_client_pid   = cip->ci_peer_pid ;
    comseg->cs_client_ref   = cip->ci_peer_ref ;
    comseg->cs_server_pid   = tcb->ukt->tid ;
    comseg->cs_server_ref   = cip->ci_my_ref ;
    comseg->cs_server_state = result ;
    comseg->cs_server_semid = tcb->ukt->semid ;
    comseg->cs_client_flag  = 2 ;
    comseg->cs_server_flag  = 1 ;
    DBG1 (( MF__,"client pid %ld ref %d flg %d",
		(long) comseg->cs_client_pid , comseg->cs_client_ref ,
		comseg->cs_client_flag ));
    DBG1 (( MF__,"server pid %ld ref %d flg %d sem %d",
		(long) comseg->cs_server_pid , comseg->cs_server_ref ,
		comseg->cs_server_flag , comseg->cs_server_semid ));
    DBG1 (( MF__,"shm %d off %ld adr 0x%08lx",
		comseg->cs_shmid , cip->ci_big_offset , (long) comseg ));
    sql32_unlock_comseg ( cip );

    /*
     *  Set the state before waking NETWORK.
     *  Otherwise, the first packet may arrive, while the state
     *  is still CON_CONNECTING.
     */
    cip->ci_state    = CON_ESTABLISHED ;

    /*
     *  Wake the application
     */
    DBG1 (( MF__,"waking application" ));
    rc = e75_wake_peer ( cip );
    if ( rc != SP1CE_OK )
    {
        int logLength ;
        char logbuf[512];
    	struct tm timeBuffer;
	    struct tm *pTime = localtime_r( &cip->ci_connect_time, &timeBuffer );
        if ( pTime )
        {
            (void) sp77sprintf ( logbuf , sizeof(logbuf), "Client died to early? (e75_connect_request) Connected to T%d since %02d:%02d:%02d",
                tcb->index, pTime->tm_hour, pTime->tm_min, pTime->tm_sec );
        }
        else
        {
            (void) sp77sprintf ( logbuf , sizeof(logbuf), "Client died to early? Connected to T%d since ?%ld?",
                tcb->index, (long)cip->ci_connect_time );
        }
        logLength = strlen ( logbuf );
        if ( cip->ci_peer_node[0] )
		    (void) sp77sprintf ( logbuf + logLength , sizeof(logbuf) - logLength, " remote %s" , cip->ci_peer_node );
        else
		    (void) sp77sprintf ( logbuf + logLength , sizeof(logbuf) - logLength, " local" );
        logLength = strlen ( logbuf );
        if ( cip->ci_remote_pid[0] )
		    (void) sp77sprintf ( logbuf + logLength , sizeof(logbuf) - logLength, " remote_pid %s" , cip->ci_remote_pid );
        logLength = strlen ( logbuf );
		(void) sp77sprintf ( logbuf + logLength , sizeof(logbuf) - logLength, " peer_pid %ld" , (long) cip->ci_peer_pid );
    	MSGD (( ERR_DISTRIB_WAKE_SEMOP, logbuf ));
    }
    if ( (rc != SP1CE_OK) || (result != SP1CE_OK) )
    {
		e74_release_comseg ( cip, tcb );
		e75_release_connection ( SP1CE_NOTOK , FALSE ); /* no wait */
		tcb->state = stack_avail ? TSK_CONNECTWAIT : TSK_INACTIVE ; 
		return ( -1 );
    }

    /*
     *  Log the connection establishment.
     */
    (void) sp77sprintf ( logbuf , sizeof(logbuf), "Connected  T%d" , tcb->index );
    rc = strlen ( logbuf );
    if ( cip->ci_peer_node[0] )
		(void) sp77sprintf ( logbuf + rc , sizeof(logbuf) - rc, " %s" , cip->ci_peer_node );
    else
		(void) sp77sprintf ( logbuf + rc , sizeof(logbuf) - rc, " local" );
    rc = strlen ( logbuf );
    if ( cip->ci_peer_dbname[0] )
    {
		(void) sp77sprintf ( logbuf + rc , sizeof(logbuf) - rc, ":%s" , cip->ci_peer_dbname );
		rc = strlen ( logbuf );
    }
    if ( cip->ci_remote_pid[0] )
		(void) sp77sprintf ( logbuf + rc , sizeof(logbuf) - rc, " %s" , cip->ci_remote_pid );
    else
		(void) sp77sprintf ( logbuf + rc , sizeof(logbuf) - rc, " %ld" , (long) cip->ci_peer_pid );

#ifdef DEBUG_RTE
    rc = strlen ( logbuf );
    (void) sp77sprintf ( logbuf + rc , sizeof(logbuf) - rc, " %c%08lx" ,
			(cip->ci_peer_semid == -2)?'N':
			((cip->ci_protocol != PROT_BIGSHM_EO003)?'S':'B') ,
			(long) cip->ci_comseg );
#endif /*DEBUG_RTE*/


    MSGD (( INFO_CONNECTING_TASK, logbuf ));

	switch ( tcb->state )
	{
		case TSK_INACTIVE : 
		case TSK_CONNECTWAIT :
			/*
			CLR_CURR_TASK_STAT_COUNTER ;
			 */
			rc = 0 ;	/* means ok and return to task */
			break ; 
		default :
			MSGD ((IERR_CONNECT_UNEXP_STATE, tcb->state ));
			e75_release_connection ( SP1CE_NOTOK , FALSE ); /*no wait*/
			tcb->state = TSK_CONNECTWAIT ; 
			rc = -1 ;
	}

    DBG1 (( MF__,"leaving %d", rc ));
	DBGOUT;
    return ( rc );
}
/* e75_connect_request */

/*
 *  =======================================================================
 */

void e75_release_request ( struct DOUBLY_LINKED *lquu )
{
#undef  MF__
#define MF__ MOD__"e75_release_request"
ten50_UKT_Control               * this_ukt = THIS_UKT_CTRL;
    connection_info		*cip ;
    comseg_header		*comseg ;


    DBGIN;

    if ( this_ukt->curr_task->state != TSK_VRECEIVE )
    {
		DBG1 (( MF__,"ignoring RELEASE request for T%d",
								this_ukt->curr_task->index ));
		return ;
    }

    /*
     *  Application died, simulate an incoming packet.
     */
    cip = this_ukt->curr_task->connection;
    comseg = cip->ci_comseg ;
    if ( comseg )
    {
		comseg->cs_client_state = SP1CE_CRASH ;
		comseg->cs_client_flag = 1 ;
    }

    DBGOUT;
}
