/*!
  @file           vos53k.c
  @author         RaymondR
  @brief          Communication
  @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
*/


#include "RunTime/System/RTESys_MemoryBarrier.h"

/*
 * INCLUDE FILES
 */
//#include "gos00.h"
#include "gos41.h"
#include "heo00.h"
#include "heo46.h"
#include "geo007_1.h"
#include "gos00k.h"
#include "geo002.h"
#include "gos003.h"
#include "heo52.h"
#include "RunTime/System/RTESys_MicroTime.h"
#include "geo67.h"
#include "heo56.h"
#include "gos74.h"
#include "heo420.h"

/*
 *  DEFINES
 */
#define MOD__  "VOS53KC : "
#define MF__   MOD__"UNDEFINED"

/*
 *  MACROS
 */


/*
 *  LOCAL TYPE AND STRUCT DEFINITIONS
 */


/*
 * EXTERNAL VARIABLES
 */


/*
 *  EXPORTED VARIABLES
 */


/*
 * LOCAL VARIABLES
 */


/*
 * LOCAL FUNCTION PROTOTYPES
 */
static ULONG sql53k_check_comm_seg  ( PCOMM_SEG_HEADER_REC  pCSHeader,
                                      PCOMM_SEG_OFFSET_REC  pCSOffsetList );

static ULONG sql53k_receive         ( PTASK_CTRL_REC        pTaskCtrl,
                                      PUSER_TASK_COMM_CTRL  pUserCommCtrl,
                                      PCOMM_SEG_HEADER_REC  pCSHeader,
                                      ULONG                 ulTimeOut,
                                      PCHAR                 *ppcRcvPacket,
                                      PULONG                pulRcvPacketLen );

static ULONG sql53k_reply           ( PTASK_CTRL_REC        pTaskCtrl,
                                      PUSER_TASK_COMM_CTRL  pUserCommCtrl,
                                      PCHAR                 pcRplPacket,
                                      ULONG                 ulRplPacketLen );

static VOID sql53k_release          ( PTASK_CTRL_REC        pTaskCtrl );

static VOID sql53k_handle_ping      ( PTASK_CTRL_REC        pTaskCtrl,
                                      PUSER_TASK_COMM_CTRL  pUserCommCtrl );

static VOID sql53k_remove_unrel_conn( PTASK_CTRL_REC        pTaskCtrl );

static tsp00_Uint1 sql53k_new_swap_type ();

/*
 * ========================== GLOBAL FUNCTIONS ================================
 */

VOID  vconnect ( PROCESS_ID      pid,
                 tsp00_Int4        * max_data_len,
                 tsp01_CommErr   * returncode )
  {
  #undef  MF__
  #define MF__ MOD__"vconnect"
  #ifdef DEVELOP_CHECKS
   PTASK_CTRL_REC                pTaskCtrl     = THIS_UKT_CTRL->pCTask;
  #else
   PTASK_CTRL_REC                pTaskCtrl     = &kgs.pFirstTaskCtrl[pid - 1];
  #endif
  PUSER_TASK_COMM_CTRL           pUserCommCtrl = pTaskCtrl->pUserCommCtrl;
  PDLQ_REC                       pConnReq;
  DLQ_CONNECT_REQ_ARGS_REC       *pConnReqArgs;
  PCOMM_SEG_HEADER_REC           pCSHeader;
  ULONG                          ulCnt;
  PCOMM_SEG_OFFSET_REC           pCSOffsetList;
  ULONG                          rc;

  DBGIN_T (pTaskCtrl->ulTaskIndex);

  pTaskCtrl->TaskState = TSK_CONNECTWAIT;


  if ( pUserCommCtrl->pCSHeader != NULL )
    {
    MSGCD (( ERR_TASK_ALREADY_CONNECTED, pTaskCtrl->ulTaskIndex ));
    *returncode          = commErrNotOk_esp01;
    pTaskCtrl->TaskState = TSK_RUNNING;
    DBGOUT;
    return;
    }

  pConnReq = sql73k_DLQ_dequ_nolock ( &pTaskCtrl->DLQ_ConnReq );

  // --- connect request already received?
  if ( pConnReq == NULL )
    {
    GOTO_DISP( &pTaskCtrl->pUKT );
    pConnReq = pTaskCtrl->pUKT->pCurrReq;
    }

  *max_data_len = 0;
  *returncode   = commErrOk_esp01;
  pConnReqArgs  = &pConnReq->ReqArgs.ConnectRequest;

  //
  // --- get contents of the connect-queue-element
  //
  pUserCommCtrl->hCS                 = pConnReqArgs->hCS;
  pUserCommCtrl->pCSHeader           = pConnReqArgs->pCSHeader;
  pUserCommCtrl->hClientSem          = pConnReqArgs->hClientSem;
  pUserCommCtrl->hLocalClientProcess = pConnReqArgs->hLocalClientProcess;
  pUserCommCtrl->pidLocalClientPID   = pConnReqArgs->pidLocalClientPID;

  RELEASE_FREELIST_ELEM ( pConnReq );

  //
  // --- check some of the communication segment values
  //
  pCSHeader      = pUserCommCtrl->pCSHeader;
  pCSOffsetList  = (PCOMM_SEG_OFFSET_REC)
                   ((PCHAR)pCSHeader + pCSHeader->ulOffsetRecord);

  *returncode = (tsp01_CommErr) sql53k_check_comm_seg( pCSHeader,
                                                       pCSOffsetList );

  if ( *returncode == commErrOk_esp01 )
    {
    //
    // --- save same communication parameters
    //
    pUserCommCtrl->pidClientPID    = pCSHeader->pidClientOrPeerPID;
    pUserCommCtrl->ulClientRef     = pCSHeader->ulClientOrPeerRef;
    pUserCommCtrl->ulPacketCnt     = pCSHeader->ulPacketCnt;
    pUserCommCtrl->ulMaxDataLen    = pCSHeader->ulMaxDataLen;
    pUserCommCtrl->ulMaxCmdDataLen = pCSHeader->ulMaxDataLen -
                                     pCSHeader->ulMinReplySize;
    pUserCommCtrl->ulCommState     = commErrOk_esp01;
    pUserCommCtrl->ulCmdWaitTime   = (ULONG)UNDEF;
    strcpy ( pUserCommCtrl->szClientNode, pCSHeader->szClientOrPeerNode );

    for ( ulCnt = 0; ulCnt < pCSHeader->ulPacketCnt; ulCnt++ )
      {
      pUserCommCtrl->pCommPacketList[ulCnt] =
        (PCOMM_PACKET_REC)((PCHAR)pCSHeader + pCSOffsetList->ulOffset[ulCnt]);
      }

    if ( pCSHeader->iCSVersion == COMM_SEG_VERSION_WITH_SEMNAME_REPLY )
      {
      // set long term move lock...
      sql74k_long_term_move_lock( pTaskCtrl, CLIENT_NOT_TASK_MOVE_ENABLED, true );

      strcpy ( pCSHeader->szSemPath, SEM_UKT );
      strcpy ( pCSHeader->szSemName, kgs.pSemaNames[pTaskCtrl->pUKT->ulSemaNo] );
      }

    /* Set move lock, because the task should not move to another UKT
    until we have received a command from client */ 
    sql74k_long_term_move_lock( pTaskCtrl, WAITING_FOR_NEW_COMMAND, true );

    //
    // --- send communication parameter to client
    //
    pCSHeader->ulSemaNo          = pTaskCtrl->pUKT->ulSemaNo;
    pCSHeader->ulCommFlagNo      = pTaskCtrl->ulCommFlagNo;
    pCSHeader->ulServerCommState = commErrOk_esp01;
    pCSHeader->ulServerRef       = pTaskCtrl->ulTaskIndex;
    pCSHeader->ulServerFlag      = 1;
    pCSHeader->ulClientFlag      = 2;
    GETPROCESSID (&pCSHeader->pidServerPID);

    kgs.pulCommFlags[pTaskCtrl->ulCommFlagNo] = 0;
    kgs.ConnectedUserTasks += pTaskCtrl->TaskType == TT_US ? 1 : 0;

    //
    // ---  Wake up the client
    //
    rc = sql41c_post_event_sem ( pUserCommCtrl->hClientSem, "Client" );

    if (( rc != NO_ERROR ) && ( rc != ERROR_ALREADY_POSTED ))
      {
      // --- release client semaphore
      sql41c_close_event_sem ( pUserCommCtrl->hClientSem, "Client" );
      pUserCommCtrl->hClientSem = INVALID_HANDLE_VALUE;

      //
      // --- release connection
      //
      pUserCommCtrl->ulCommState = commErrCrash_esp01;
      *returncode                = commErrCrash_esp01;

      sql53k_release ( pTaskCtrl );
      }
    else if ( pUserCommCtrl->ulServiceType == srvPing_esp01 )
      {
      MSGD (( INFO_CONN_TASK_WITH_APP, pTaskCtrl->ulTaskIndex,
              pCSHeader->szClientOrPeerNode,
              pCSHeader->pidClientOrPeerPID ));

      sql53k_handle_ping ( pTaskCtrl, pUserCommCtrl );

      // --- release connection
      pUserCommCtrl->ulCommState = commErrNotOk_esp01;
      *returncode                = (tsp01_CommErr)pUserCommCtrl->ulCommState;
      sql53k_release ( pTaskCtrl );
      }
    else
      {
        *max_data_len = pCSHeader->ulMaxDataLen;

        MSGD (( INFO_CONN_TASK_WITH_APP, pTaskCtrl->ulTaskIndex,
                pCSHeader->szClientOrPeerNode,
                pCSHeader->pidClientOrPeerPID ));

        if ( pTaskCtrl->TaskType == TT_EV )
        {
          if ( !eo67ConnectEventTask(pid) )
          {
            ABORT ();
          }
        }
        else
        {
          /* PTS 1004575 */
          eo67InsertSessionEvent(true, pid);
        }
      }
    }
  else
    {
    //
    // --- release connection
    //
    pUserCommCtrl->ulCommState = commErrCrash_esp01;

    sql53k_release ( pTaskCtrl );
    }

  pTaskCtrl->TaskState = TSK_RUNNING;


  DBGOUT_T (pTaskCtrl->ulTaskIndex);
  return;
  }


/*------------------------------*/

VOID  vreceive ( PROCESS_ID     pid,
                 tsp00_Int4       timeout,
                 char           ** rcv_packet_ptr,
                 tsp00_Int4       * rcv_packet_length,
                 char           ** reply_packet_ptr,
                 tsp00_Int4       * reply_packet_size,
                 tsp01_CommErr * returncode )
  {
  #undef  MF__
  #define MF__ MOD__"vreceive"
  #ifdef DEVELOP_CHECKS
   PTASK_CTRL_REC                pTaskCtrl     = THIS_UKT_CTRL->pCTask;
  #else
   PTASK_CTRL_REC                pTaskCtrl     = &kgs.pFirstTaskCtrl[pid - 1];
  #endif
  PUSER_TASK_COMM_CTRL           pUserCommCtrl = pTaskCtrl->pUserCommCtrl;
  PCOMM_SEG_HEADER_REC           pCSHeader     = pUserCommCtrl->pCSHeader;
  PCHAR                          pcRcvPacket;
  ULONG                          ulRcvPacketLen;

  DBGIN_T (pTaskCtrl->ulTaskIndex);

  pUserCommCtrl->ulCmdWaitTime = kgs.ulCurrTime; // - set wait time first !!!

  pTaskCtrl->TaskState = TSK_VRECEIVE;

  if ( pUserCommCtrl->ulConnected == 0 )
    {
    MSGCD (( ERR_COMM_WITHOUT_CONNECTION, pTaskCtrl->ulTaskIndex ));
    *returncode          = commErrNotOk_esp01;
    pTaskCtrl->TaskState = TSK_RUNNING;
    pTaskCtrl->TaskStateStat.vreceiveORvreplyLeaveTime = 0;
    DBGOUT;
    return;
    }

  *returncode        = commErrOk_esp01;
  *rcv_packet_ptr    = NULL;
  *rcv_packet_length = 0;
  *reply_packet_ptr  = NULL;
  *reply_packet_size = 0;


  *returncode = (tsp01_CommErr) sql53k_receive (pTaskCtrl, pUserCommCtrl,
                                                 pCSHeader, timeout,
                                                 &pcRcvPacket, &ulRcvPacketLen);

  if  ( *returncode != commErrOk_esp01 )
    {
    pTaskCtrl->TaskState = TSK_RUNNING;
    pTaskCtrl->TaskStateStat.vreceiveORvreplyLeaveTime = 0;
    DBGOUT_T (pTaskCtrl->ulTaskIndex);
    return;
    }

  *rcv_packet_ptr    = pcRcvPacket;
  *rcv_packet_length = (INT4) ulRcvPacketLen;
  *reply_packet_ptr  = (PCHAR)pUserCommCtrl->pReplyCommPacket->pDataPart;

  if ( pCSHeader->ulMinReplySize )
    *reply_packet_size = (INT4) pUserCommCtrl->ulMaxDataLen - ALIGN ( ulRcvPacketLen, SQL_PACKET_ALIGNMENT);
  else
    *reply_packet_size = (INT4) pUserCommCtrl->ulMaxDataLen;

  /*
    We have entered the dispatcher before, so 'pTaskCtrl->TimeCollectionEnabled' is setup if time measurtement is enabled.
    We later use 'vreceiveORvreplyLeaveTime != 0' as condition to allow collection of time in vreply.

    Time measurement values collect here at end of vreceive (pTaskCtrl->TaskStateStat):
        vreceiveORvreplyLeaveTime                Timestamp of last 'end' of vreply routine, updated with actualMicroSeconds
        runqueueEnqueueTime                     Time when task was moved from COM queue to RUN queue
        RplRcvStat.ulAbsMicroSeconds            Sum of all time intervals between vreply and following 'end' of vreceive
        RplRcvStat.ulRelMicroSeconds            Sum of all time intervals between vreply and following entering RUN queue
        RplRcvStat.ulCount                      Number of intervals added
  */
  if ( pTaskCtrl->TimeCollectionEnabled )
  {
      SAPDB_UInt8 actualMicroSeconds = RTESys_MicroSecTimer();

      if ( pTaskCtrl->TaskStateStat.vreceiveORvreplyLeaveTime )
      {
          pTaskCtrl->TaskStateStat.RplRcvStat.ulCount++;
          pTaskCtrl->TaskStateStat.RplRcvStat.ulAbsMicroSeconds += 
             ( actualMicroSeconds - pTaskCtrl->TaskStateStat.vreceiveORvreplyLeaveTime );
          pTaskCtrl->TaskStateStat.RplRcvStat.ulRelMicroSeconds += 
             ( pTaskCtrl->TaskStateStat.runqueueEnqueueTime - pTaskCtrl->TaskStateStat.vreceiveORvreplyLeaveTime );
      }

      pTaskCtrl->TaskStateStat.vreceiveORvreplyLeaveTime  = actualMicroSeconds;
  }
  else
  {
      /* Reset start timestamp, so vreply wont produce illegal values */
      pTaskCtrl->TaskStateStat.vreceiveORvreplyLeaveTime  = 0;
  }

  pTaskCtrl->TaskState = TSK_RUNNING;


  DBGOUT_T (pTaskCtrl->ulTaskIndex);
  return;
  }

/*------------------------------*/

INT4  vcmd_wait_time ( PROCESS_ID  pid )
  {
  #undef  MF__
  #define MF__ MOD__"vcmd_wait_time"
  PTASK_CTRL_REC                 pTaskCtrl = &kgs.pFirstTaskCtrl[pid - 1];
  PUSER_TASK_COMM_CTRL           pUserCommCtrl = pTaskCtrl->pUserCommCtrl;
  INT4                           i4CmdWaitTime;

  DBGIN_T (pTaskCtrl->ulTaskIndex);

  if ( pTaskCtrl->TaskState == TSK_VRECEIVE )
    i4CmdWaitTime = (INT4)(kgs.ulCurrTime - pUserCommCtrl->ulCmdWaitTime);
  else
    i4CmdWaitTime = 0;


  DBGOUT_T (pTaskCtrl->ulTaskIndex);
  return ( i4CmdWaitTime ) ;
  }

/*------------------------------*/

VOID vreply ( PROCESS_ID      pid,
              char            * reply_packet_ptr,
              tsp00_Int4        reply_packet_length,
              tsp01_CommErr  * returncode )
  {
  #undef  MF__
  #define MF__ MOD__"vreply"
  #ifdef DEVELOP_CHECKS
   PTASK_CTRL_REC                pTaskCtrl     = THIS_UKT_CTRL->pCTask;
  #else
   PTASK_CTRL_REC                pTaskCtrl     = &kgs.pFirstTaskCtrl[pid - 1];
  #endif
  PUSER_TASK_COMM_CTRL           pUserCommCtrl = pTaskCtrl->pUserCommCtrl;

  DBGIN_T (pTaskCtrl->ulTaskIndex);

  pTaskCtrl->TaskState = TSK_VREPLY;

  if ( pUserCommCtrl->ulConnected == 0 )
    {
    MSGCD (( ERR_COMM_WITHOUT_CONNECTION, pTaskCtrl->ulTaskIndex ));
    pTaskCtrl->TaskState = TSK_RUNNING;
    *returncode = commErrNotOk_esp01;
    pTaskCtrl->TaskStateStat.vreceiveORvreplyLeaveTime = 0;
    DBGOUT;
    return;
    }

  *returncode = (tsp01_CommErr) sql53k_reply (pTaskCtrl, pUserCommCtrl,
                                              reply_packet_ptr,
                                              reply_packet_length );

  if ( *returncode != commErrOk_esp01 )
    {
    pTaskCtrl->TaskState = TSK_RUNNING;
    DBGOUT_T (pTaskCtrl->ulTaskIndex);
    return;
    }

  /*
    We have called vreceive before, so pTaskCtrl->TaskStateStat.vreceiveORvreplyLeaveTime would be set to beginning of command
    if time measurement was active then. So we use it as indication, that time measurement is possible

    Time measurement values collect here at end of vreply (pTaskCtrl->TaskStateStat):
        vreceiveORvreplyLeaveTime                Timestamp of last 'end' of vreceive routine, updated with actualMicroSeconds
        RcvRplStat.ulAbsMicroSeconds            Sum of all command times ( intervals between end of vreceive and end of vreply )
        RcvRplStat.ulCount                      Number of intervals summed
        ulRcvRplToLong                          Number of command, where time interval vreceive - vreply was longer than 1 second
   */
  if ( kgs.fTimeMeasure )
  {
      SAPDB_UInt8 actualMicroSeconds = RTESys_MicroSecTimer();

      if ( pTaskCtrl->TaskStateStat.vreceiveORvreplyLeaveTime )
      {
          pTaskCtrl->TaskStateStat.RcvRplStat.ulCount++;
          pTaskCtrl->TaskStateStat.RcvRplStat.ulAbsMicroSeconds += 
             ( actualMicroSeconds - pTaskCtrl->TaskStateStat.vreceiveORvreplyLeaveTime );
#define OS53_TOO_LONG_LIMIT_IN_MICROSECONDS (1000000U)
          if ( (actualMicroSeconds - pTaskCtrl->TaskStateStat.vreceiveORvreplyLeaveTime) > EO52_TOO_LONG_LIMIT_IN_MICROSECONDS )
          {
              pTaskCtrl->TaskStateStat.ulRcvRplToLong ++;
          }
      }
      pTaskCtrl->TaskStateStat.vreceiveORvreplyLeaveTime = actualMicroSeconds;
  }
  else
  {
      pTaskCtrl->TaskStateStat.vreceiveORvreplyLeaveTime = 0;
  }

  pTaskCtrl->TaskState = TSK_RUNNING;


  DBGOUT_T (pTaskCtrl->ulTaskIndex);
  return;
  }

/*------------------------------*/

VOID vrelease ( PROCESS_ID  pid )
  {
  #undef  MF__
  #define MF__ MOD__"vrelease"
  #ifdef DEVELOP_CHECKS
   PTASK_CTRL_REC                pTaskCtrl = THIS_UKT_CTRL->pCTask;
  #else
   PTASK_CTRL_REC                pTaskCtrl = &kgs.pFirstTaskCtrl[pid - 1];
  #endif


  DBGIN_T (pTaskCtrl->ulTaskIndex);

  pTaskCtrl->TaskState = TSK_VRELEASE;

  #ifdef DEVELOP_CHECKS
   if ( (ULONG)pid != pTaskCtrl->ulTaskIndex )
     {
     MSGD (( ERR_VXXXX_WRONG_TASK, "vrelease", pid ));
     DBG1 (( MF__, "[T:0x%03u] Wrong pid %u", pTaskCtrl->ulTaskIndex, pid ));
     ABORT();
     }
  #endif

  if (( pTaskCtrl->TaskType != TT_US ) 
   && ( pTaskCtrl->TaskType != TT_UT )
   && ( pTaskCtrl->TaskType != TT_EV )
     )
    {
    MSGD  (( ERR_TASK_TYPE_UNEXPECTED, "vrelease",
             pTaskCtrl->TaskType ));
    ABORT ();
    }

  if ( pTaskCtrl->TaskType == TT_EV )
  {
      if ( !eo67ReleaseEventTask(pid) )
      {
          ABORT ();
      }
  }
  else
  {
      /* PTS 1004575 */
      eo67InsertSessionEvent(false, pid);
  }

  // --- release connection
  sql53k_release ( pTaskCtrl );

  MSGD (( INFO_CONN_RELEASED, pTaskCtrl->ulTaskIndex ));
  pTaskCtrl->TaskState = TSK_RUNNING;

  return;
  }

/*------------------------------*/

tsp00_Int4  vconnectedusertasks ()
{
    return kgs.ConnectedUserTasks;
}

/*------------------------------*/

VOID	vgetapplpid( PROCESS_ID         tid ,
                     tsp00_NodeId		appl_node ,
                     tsp00_Int4			*appl_pid ,
                     BOOLEAN			*ok )
{
#undef  MF__
#define MF__ MOD__"vgetapplpid"

    if ( ( tid > 0 ) && ( ((ULONG)tid) <= kgs.ulNumOfTasks ) )
    {
        PTASK_CTRL_REC				pTaskCtrl = &kgs.pFirstTaskCtrl[tid - 1];

        if ( pTaskCtrl->pUserCommCtrl )
        {
	 	    *appl_pid = pTaskCtrl->pUserCommCtrl->pidClientPID ;

            eo46CtoP ( appl_node, 
		               pTaskCtrl->pUserCommCtrl->szClientNode[0] == '\0' 
 				     ? kgs.szServerNode  
				     : pTaskCtrl->pUserCommCtrl->szClientNode, sizeof(tsp00_NodeId) );
            *ok = true;
        }
	    else 
        {
		    *appl_pid = -1;
		    eo46CtoP ( appl_node, kgs.szServerNode, sizeof(tsp00_NodeId) ); 
            *ok = false;
        }
    }
    else
    {
#ifdef SDB_DEV_ONLY_CHECK
        MSGD (( ERR_KERN_PARAM_PID_OUT_OF_RANGE, tid ));
        ABORT();
#else
        *appl_pid = -1;
		eo46CtoP ( appl_node, (char *)"", sizeof(tsp00_NodeId) ); 
        *ok = false;
#endif
    }
}

/*------------------------------*/

void sql53k_cancel_task ( PTASK_CTRL_REC  pTaskCtrl )
  {
  #undef  MF__
  #define MF__ MOD__"sql53k_cancel_task"
  PUSER_TASK_COMM_CTRL           pUserCommCtrl;

  DBGIN;

  //
  // --- this function should be used by foreign threads
  //     to cancel the actual command or kill the the connection
  //
  pUserCommCtrl = pTaskCtrl->pUserCommCtrl;

  if ( pUserCommCtrl->ulConnected != 0 ) // - Do a dirty read first!
  {
    WAIT_UNTIL_ALONE( &pTaskCtrl->lExclusive );

    if ( pUserCommCtrl->ulConnected != 0 )
    {
      pTaskCtrl->KernelCtrlRecord.to_cancel = TRUE;
      /* PTS 1105149 */
      if ( pTaskCtrl->TaskType == TT_EV )
      {
        CLEARLOCK( &pTaskCtrl->lExclusive );
        vcontinue(pTaskCtrl->ulTaskIndex); /* Get it out of blocking call */
        WAIT_UNTIL_ALONE( &pTaskCtrl->lExclusive );
      }
    }

    CLEARLOCK( &pTaskCtrl->lExclusive );
  }

  DBGPAS;
  }

/*------------------------------*/

BOOL sql53k_comm_cancel ( PTASK_CTRL_REC  pTaskCtrl,
                          ULONG           ulCommState )
  {
  #undef  MF__
  #define MF__ MOD__"sql53k_comm_cancel"
  BOOL                           fCanceled = FALSE;
  PUSER_TASK_COMM_CTRL           pUserCommCtrl;

  DBGIN;

  //
  // --- this function should be used by foreign threads
  //     to cancel the actual command or kill the the connection
  //
  pUserCommCtrl = pTaskCtrl->pUserCommCtrl;

  if ( pUserCommCtrl->ulConnected != 0 ) // - Do a dirty read first!
  {
    if ( ulCommState == commErrOk_esp01 )
    {
      MSGD (( INFO_CANCEL_REQ_FOR_TSK, pTaskCtrl->ulTaskIndex ));
    }

    WAIT_UNTIL_ALONE( &pTaskCtrl->lExclusive );

    if ( pUserCommCtrl->ulConnected != 0 )
    {
      if ( ulCommState != commErrOk_esp01 )
      {
        // --- on error kill connection
        pUserCommCtrl->ulGlobCommState = ulCommState;
        RTESys_WriteMemoryBarrier();
        kgs.pulCommFlags[pTaskCtrl->ulCommFlagNo] = 1;
      }

      pTaskCtrl->KernelCtrlRecord.to_cancel = TRUE;
      fCanceled                             = TRUE;
      /* PTS 1105149 */
      if ( pTaskCtrl->TaskType == TT_EV )
      {
        CLEARLOCK( &pTaskCtrl->lExclusive );
        vcontinue(pTaskCtrl->ulTaskIndex); /* Get it out of blocking call */
        WAIT_UNTIL_ALONE( &pTaskCtrl->lExclusive );
      }
    }

    CLEARLOCK( &pTaskCtrl->lExclusive );

    if ( fCanceled )
      sql72k_wake_ukt ( pTaskCtrl->pUKT );
  }

  DBGPAS;

  return ( fCanceled );
  }

/*------------------------------*/

BOOL sql53k_comm_termination_cleanup ( PTASK_CTRL_REC  pTaskCtrl )
  {
  #undef  MF__
  #define MF__ MOD__"sql53k_comm_termination_cleanup"
  BOOL                           fRemoved      = FALSE;
  PUSER_TASK_COMM_CTRL           pUserCommCtrl = pTaskCtrl->pUserCommCtrl;
  PCOMM_SEG_HEADER_REC           pCSHeader;
  HANDLE                         hClientSem;
  ULONG                          ulCommState;

  DBGIN;

/*
  if ( pTaskCtrl->ulTaskIndex == kgs.taskResponsibleForOffline ) // PTS 1134089
  {
      return false;
  }
 */

  // --- this function should be used by foreign threads
  //     to terminate the the connection during DB-system crash or shutdown
  //
  if (( *kgs.pDBState  == SERVER_SHUTDOWN )       ||
      ( *kgs.pDBState  == SERVER_SHUTDOWNREINIT ) ||
      ( *kgs.pDBState  == SERVER_SHUTDOWNKILL ))
    ulCommState = commErrShutdown_esp01;
  else
    ulCommState = commErrCrash_esp01;

  if ( pUserCommCtrl )
  {
      pCSHeader  = pUserCommCtrl->pCSHeader;
      
      if ( pCSHeader && pUserCommCtrl->ulConnected != 0 ) // - Do a dirty read first!
      {
          WAIT_UNTIL_ALONE( &pTaskCtrl->lExclusive );
          
          pCSHeader  = pUserCommCtrl->pCSHeader;

          if ( pCSHeader && pUserCommCtrl->ulConnected != 0 )
          {
              pCSHeader->ulServerCommState              = ulCommState;
              pCSHeader->ulServerRef                    = (ULONG)UNDEF;
              pCSHeader->ulServerFlag                   = 1;
              
              pUserCommCtrl->ulGlobCommState            = ulCommState;
              pTaskCtrl->KernelCtrlRecord.to_cancel     = TRUE;
              RTESys_WriteMemoryBarrier();
              kgs.pulCommFlags[pTaskCtrl->ulCommFlagNo] = 1;
              
              hClientSem                                = pUserCommCtrl->hClientSem;
              fRemoved                                  = TRUE;
          }
          
          CLEARLOCK( &pTaskCtrl->lExclusive );
          
          if ( fRemoved )
          {
              // --- wake up the client and UKT
              sql41c_post_event_sem ( hClientSem, "Client" );
              sql72k_wake_ukt ( pTaskCtrl->pUKT );
          }
      }
  }
  DBGPAS;

  return ( fRemoved );
  }

/*------------------------------*/

VOID sql53k_remove_unrel_connnections ( VOID )
  {
  #undef  MF__
  #define MF__ MOD__"sql53k_remove_unrel_connnections"
  PTASK_CTRL_REC                  pTaskCtrl;

  #if defined(_WIN32)
   for ( pTaskCtrl =  kgs.pFirstUserTaskCtrl;
         pTaskCtrl <= kgs.pLastUserTaskCtrl;
         pTaskCtrl++ )
     {
     sql53k_remove_unrel_conn( pTaskCtrl );
     }

         /* PTS 1103964 jrg */
   for ( pTaskCtrl =  kgs.pFirstEVTaskCtrl;
        /* It is possible to have no event tasks, so we have to check on 'NULL' */
         pTaskCtrl != NULL && pTaskCtrl <= kgs.pLastEVTaskCtrl;
         pTaskCtrl++ )
     {
     sql53k_remove_unrel_conn( pTaskCtrl );
     }

   sql53k_remove_unrel_conn( kgs.pUT );
  #endif

  DBGOUT;
  return;
  }


/*------------------------------*/

ULONG sql53k_get_connection_state ( PTASK_CTRL_REC  pTaskCtrl )
  {
  #undef  MF__
  #define MF__ MOD__"sql53k_get_connection_state"

  ULONG                          ulConnState = CON_UNUSED_EO003;
  PUSER_TASK_COMM_CTRL           pUserCommCtrl;
  PCOMM_SEG_HEADER_REC           pCSHeader;
  ULONG                          ulClientFlag;
  ULONG                          ulServerFlag;
  ULONG                          ulRetry = 3;

  pUserCommCtrl = pTaskCtrl->pUserCommCtrl;

  if ( pUserCommCtrl->ulConnected != 0 ) // - Do a dirty read first!
  {
    WAIT_UNTIL_ALONE( &pTaskCtrl->lExclusive );

    pCSHeader = pUserCommCtrl->pCSHeader;

    if ( pCSHeader && pUserCommCtrl->ulConnected != 0 )
    {
     /*
      *    The ulClientFlag and ulServerFlag:
      *              
      *                  c s
      *           init-> -+-    
      *                  0 0  
      *                   |        c s 
      *             sqlaconnect -> -+-
      *                       \    1 0
      *                        \      \
      *                         \    vconnect
      *                          \   /
      *                 c s       c s
      *                 -+-       -+-
      *                 0 2       2 1
      *                /   \      
      *      sqlareceive   sqlarequest,sqlarelease
      *              /       \   
      *           c s         c s
      *           -+-         -+-          0: no event
      *           2 1         1 2          1: event pending
      *              \       /             2: destination has received the event
      *   vreply,vrelease   vreceive
      *                \   /
      *                 c s
      *                 -+-
      *                 2 0
      *
      *
      *
      *    if the communication is crashing:
      *
      *      kernel:   c s         client:   c s
      *                -+-                   -+-
      *                ? 1                   1 ?
      */

      if ( pCSHeader->ulServerCommState == commErrOk_esp01 )
      {
        do {
          ulServerFlag = pCSHeader->ulServerFlag;
          ulClientFlag = pCSHeader->ulClientFlag;

          if (( ulServerFlag == 0 ) && ( ulClientFlag  == 0 ))
            ulConnState = CON_INITIALIZED_EO003;
          else if (( ulServerFlag == 2 ) && ( ulClientFlag  == 0 ))
            ulConnState = CON_CONNECTED_EO003;
          else if (( ulServerFlag == 2 ) && ( ulClientFlag  == 1 ))
            ulConnState = CON_REQUESTED_EO003;
          else if (( ulServerFlag == 0 ) && ( ulClientFlag  == 2 ))
            ulConnState = CON_RECEIVED_EO003;
          else if (( ulServerFlag == 1 ) && ( ulClientFlag  == 2 ))
            ulConnState = CON_REPLIED_EO003;
          else
            Sleep (0);

        } while ( ulConnState == CON_UNUSED_EO003 && --ulRetry );
      }
      else
        ulConnState = CON_CONNECTED_EO003;
    }
    CLEARLOCK( &pTaskCtrl->lExclusive );
  }

  DBGOUT;
	return ulConnState;
  }

/*
 * ========================== LOCAL FUNCTIONS =================================
 */

static ULONG sql53k_check_comm_seg ( PCOMM_SEG_HEADER_REC pCSHeader,
                                     PCOMM_SEG_OFFSET_REC pCSOffsetList )
  {
  #undef  MF__
  #define MF__ MOD__"sql53k_check_comm_seg"
  ULONG                          ulCnt;
  ULONG                          ulCommPacketEndOffset;

  //
  // --- check some of the communication segment header values
  //
  if ( pCSHeader->iCSVersion > COMM_SEG_VERSION )
    {
    MSGD  (( ERR_WRONG_COMMSEG_VERSION, pCSHeader->iCSVersion ));
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  if (pCSHeader->ulCSSize < pCSHeader->ulOffsetRecord + COMM_OFFSET_LIST_SIZE)
    {
    MSGD  (( ERR_WRONG_OFFSET_REC_POS, pCSHeader->ulOffsetRecord,
             pCSHeader->ulOffsetRecord + COMM_OFFSET_LIST_SIZE));
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  if (pCSHeader->ulPacketCnt > MAX_SQL_PACKETS)
    {
    MSGD  (( ERR_WRONG_PACKET_COUNT,
             pCSHeader->ulPacketCnt, MAX_SQL_PACKETS ));
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  if (pCSHeader->ulPacketCnt != pCSOffsetList->ulOffsetCnt)
    {
    MSGD  (( ERR_PACKET_COUNT_MISMATCH,
             pCSHeader->ulPacketCnt, pCSOffsetList->ulOffsetCnt));
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  if (( pCSHeader->ulPacketSize > XPARAM(ulPacketSize) ) ||
      ( pCSHeader->ulMaxDataLen > XPARAM(ulPacketSize) ))
    {
    MSGD  (( ERR_WRONG_PACKET_SIZE, pCSHeader->ulPacketSize));
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  if ( pCSHeader->ulMinReplySize > XPARAM(ulMinReplySize) )
    {
    MSGD  (( ERR_WRONG_MIN_REPLY_SIZE, pCSHeader->ulMinReplySize,
             XPARAM(ulMinReplySize) ));
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  for ( ulCnt = 0; ulCnt < pCSHeader->ulPacketCnt; ulCnt++ )
    {
    ulCommPacketEndOffset = pCSOffsetList->ulOffset[ulCnt] +
                            pCSHeader->ulMaxDataLen +
                            (RTE_HEADER_SIZE * 2) - 1;

    //
    // - check if the packets are not inside the communication segment
    //
    if ( ulCommPacketEndOffset + 1 > pCSHeader->ulCSSize )
      {
      MSGD  (( ERR_WRONG_COMM_PACKET_POS,
               pCSOffsetList->ulOffset[ulCnt],
               ulCommPacketEndOffset ));
      DBGOUT;
      return ( commErrNotOk_esp01 );
      }

    //
    // - check if the packets are overlapping each other
    //
    if (( ulCnt + 1             <  pCSHeader->ulPacketCnt ) &&
        ( ulCommPacketEndOffset >= pCSOffsetList->ulOffset[ulCnt + 1] ))
      {
      MSGD  (( ERR_WRONG_COMM_PACKET_POS,
               pCSOffsetList->ulOffset[ulCnt],
               ulCommPacketEndOffset ));
      DBGOUT;
      return ( commErrNotOk_esp01 );
      }
    }

  DBGOUT;
  return ( commErrOk_esp01 );
  }

/*------------------------------*/

static ULONG sql53k_receive ( PTASK_CTRL_REC        pTaskCtrl,
                              PUSER_TASK_COMM_CTRL  pUserCommCtrl,
                              PCOMM_SEG_HEADER_REC  pCSHeader,
                              ULONG                 ulTimeOut,
                              PCHAR                 *ppcRcvPacket,
                              PULONG                pulRcvPacketLen )
  {
  #undef  MF__
  #define MF__ MOD__"sql53k_receive"
  PCOMM_PACKET_REC               pCommPacket;
  PCOMM_PACKET_REC               pReplyCommPacket;
  PRTE_HEADER_REC                pCmdRTEHeader;
  ULONG                          ulCurrentPacket;
  PRTE_HEADER_REC                pReplyRTEHeader;

  DBGIN;

  pUserCommCtrl->ulCommState = commErrOk_esp01;

  // - Data replied?
  if ( pCSHeader->ulServerFlag == 0 )
    {
    MSGD (( ERR_VREC_WITHOUT_REPLY, pTaskCtrl->ulTaskIndex ));
    pUserCommCtrl->ulCommState = commErrNotOk_esp01;
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  // - kill connection exception received?
  if ( pUserCommCtrl->ulGlobCommState != commErrOk_esp01 )
    {
    MSGD (( INFO_CONNECTION_KILLED, pTaskCtrl->ulTaskIndex ));
    pUserCommCtrl->ulCommState = pUserCommCtrl->ulGlobCommState;
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  //
  // -- reset timeout flag and caclulate timeout value
  //
  pTaskCtrl->fTimeOut = FALSE;

  if ( ulTimeOut > 0 )
    {
    if ( ulTimeOut <= MIN_COMMAND_TIMEOUT )
      pTaskCtrl->ulCOMTimeOut = kgs.ulCurrTime + MIN_COMMAND_TIMEOUT;
    else
      pTaskCtrl->ulCOMTimeOut = kgs.ulCurrTime + ulTimeOut;
    }
  else
    pTaskCtrl->ulCOMTimeOut = MAXTIMEVALUE;

  //
  // --- wait for a valid packet or connection release
  //

  // --- insert task into COM queue, where it waits for a packet
  sql73k_COM_enqu (pTaskCtrl->pUKT, pTaskCtrl);

  GOTO_DISP( &pTaskCtrl->pUKT );
  RTESys_ReadMemoryBarrier();

  while (( pCSHeader->ulClientFlag        != 1 )               &&
         ( pUserCommCtrl->ulGlobCommState == commErrOk_esp01 ) &&
         ( pCSHeader->pidClientOrPeerPID  != (PID)UNDEF )      &&
         ( pTaskCtrl->fTimeOut            == FALSE )) 
  {   // Oops, the client flag has been set, but there is no packet or error outstanding.
      // Correct the semaphore number and try it again!

      pCSHeader->ulSemaNo  = pTaskCtrl->pUKT->ulSemaNo;  // we are waiting on this UKT semaphore
      RTESys_WriteMemoryBarrier();

      // --- insert task into COM queue, where it waits for a packet
      sql73k_COM_enqu (pTaskCtrl->pUKT, pTaskCtrl);

      GOTO_DISP( &pTaskCtrl->pUKT );
      RTESys_ReadMemoryBarrier();
  }

  // --- Connection killed?
  if ( pUserCommCtrl->ulGlobCommState != commErrOk_esp01 )
    {
    MSGD (( INFO_CONNECTION_KILLED, pTaskCtrl->ulTaskIndex ));
    pUserCommCtrl->ulCommState = pUserCommCtrl->ulGlobCommState;
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  //
  // - we must not look for command timeouts,
  //   before a shutdown event is handled.
  //
  if ( ( *kgs.pDBState == SERVER_SHUTDOWN ) &&
       ( pTaskCtrl->TaskType != TT_EV ) )
    {
    pUserCommCtrl->ulCommState = commErrShutdown_esp01;
    DBGOUT;
    return ( commErrShutdown_esp01 );
    }

  if ( pTaskCtrl->fTimeOut == TRUE )
    {
    MSGD (( INFO_COMM_TIMEOUT, pTaskCtrl->ulTaskIndex ));
    pUserCommCtrl->ulCommState = commErrTimeout_esp01;
    pTaskCtrl->fTimeOut        = FALSE;
    DBGOUT;
    return ( commErrTimeout_esp01 );
    }

  if (( pCSHeader->pidClientOrPeerPID == (PID)UNDEF ) &&
      ( pCSHeader->ulClientFlag       != 1 ))
    {
    MSGD (( INFO_CLIENT_CONN_RELEASE, pTaskCtrl->ulTaskIndex ));
    pUserCommCtrl->ulCommState = commErrNotOk_esp01;
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  //
  // - after all local errors are handled the only posible way to get
  //   here is that the 'ulClientFlag' is equal 1!
  //

  // --- signal that we have received the data
  pCSHeader->ulClientFlag = 2;

  if ( pCSHeader->ulClientCommState != commErrOk_esp01 )
    {
    MSGD (( INFO_CONN_BROKEN, pTaskCtrl->ulTaskIndex ));
    pUserCommCtrl->ulCommState = pCSHeader->ulClientCommState;
    DBGOUT;
    return ( pCSHeader->ulClientCommState );
    }

  ulCurrentPacket = pCSHeader->ulCurrentPacket;

  // --- wrong packet requested?
  if ( ulCurrentPacket > pUserCommCtrl->ulPacketCnt )
    {
    MSGD (( ERR_VREC_WRONG_PACKET_REQ, pTaskCtrl->ulTaskIndex ));
    pUserCommCtrl->ulCommState = commErrNotOk_esp01;
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  pCommPacket       = pUserCommCtrl->pCommPacketList[ulCurrentPacket];
  pCmdRTEHeader     = &pCommPacket->RTEHeader;

  if ( pCSHeader->ulMinReplySize )
    pReplyCommPacket  = (PCOMM_PACKET_REC)((PCHAR)pCommPacket + ALIGN ( (ULONG)pCmdRTEHeader->ActSendLen, SQL_PACKET_ALIGNMENT));
  else
    pReplyCommPacket  = (PCOMM_PACKET_REC)(PCHAR)pCommPacket;

  // --- RTE-Header check
  if (( pCmdRTEHeader->ResidualPackets    != 0 )                          ||
      ( (ULONG)pCmdRTEHeader->SenderRef   != pUserCommCtrl->ulClientRef ) ||
      ( (ULONG)pCmdRTEHeader->ReceiverRef != pTaskCtrl->ulTaskIndex )     ||
      ( pCmdRTEHeader->ProtocolID         != RSQL_RTE_PROT_LOCAL_EO003 )  ||
      ( pCmdRTEHeader->MessClass          != RSQL_USER_DATA_REQUEST_EO003 )     ||
      ( pCmdRTEHeader->MaxSendLen         != pCmdRTEHeader->ActSendLen ))
    {
    MSGD (( ERR_PROTOCOL, "vreceive", 0 ));

    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  *ppcRcvPacket    = pCommPacket->pDataPart;
  *pulRcvPacketLen = (ULONG)pCmdRTEHeader->ActSendLen - RTE_HEADER_SIZE;

  // --- wrong packet size?
  if (( pCmdRTEHeader->ActSendLen != pCmdRTEHeader->MaxSendLen ) ||
      ( *pulRcvPacketLen          >  pUserCommCtrl->ulMaxCmdDataLen ))
    {
    MSGD (( ERR_VREC_ILL_LENGTH, pCommPacket->RTEHeader.ActSendLen,
            pCommPacket->RTEHeader.MaxSendLen));
    pUserCommCtrl->ulCommState = commErrNotOk_esp01;
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  // --- set the reply packet position
  pUserCommCtrl->pReplyCommPacket = pReplyCommPacket;

  //
  // --- Init the RTE reply header. This is needed if the kernel
  //     releases the connection without a reply.
  //
  pReplyRTEHeader                  = &pReplyCommPacket->RTEHeader;
  pReplyRTEHeader->ActSendLen      = (INT4)RTE_HEADER_SIZE;
  pReplyRTEHeader->ProtocolID      = RSQL_RTE_PROT_LOCAL_EO003;
  pReplyRTEHeader->MessClass       = (INT1)UNDEF;
  pReplyRTEHeader->RTEFlags        = RSQL_NORMAL_EO003;
  pReplyRTEHeader->ResidualPackets = 0;
  pReplyRTEHeader->SenderRef       = UNDEF;
  pReplyRTEHeader->ReceiverRef     = pUserCommCtrl->ulClientRef;
  pReplyRTEHeader->RTEReturnCode   = commErrNotOk_esp01;
  pReplyRTEHeader->NewSwapType     = sql53k_new_swap_type();
  pReplyRTEHeader->Filler1         = 0;

  pReplyRTEHeader->MaxSendLen      = (INT4)RTE_HEADER_SIZE;

  // --- signal that we are ready for the 'reply'
  pCSHeader->ulServerFlag = 0;

  DBGOUT;
  return ( commErrOk_esp01 );
  }

/*------------------------------*/

static ULONG sql53k_reply ( PTASK_CTRL_REC        pTaskCtrl,
                            PUSER_TASK_COMM_CTRL  pUserCommCtrl,
                            PCHAR                 pcRplPacket,
                            ULONG                 ulRplPacketLen )
  {
  #undef  MF__
  #define MF__ MOD__"sql53k_reply"
  APIRET                         rc            = NO_ERROR;
  PRTE_HEADER_REC                pReplyRTEHeader;
  PCOMM_SEG_HEADER_REC           pCSHeader;

  pCSHeader       = pUserCommCtrl->pCSHeader;
  pReplyRTEHeader = &pUserCommCtrl->pReplyCommPacket->RTEHeader;

  // - Data replied?
  if ( pCSHeader->ulServerFlag != 0 )
    {
    MSGD (( ERR_VREP_WITHOUT_RECEIVE, pTaskCtrl->ulTaskIndex ));
    pUserCommCtrl->ulCommState = commErrNotOk_esp01;
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  // - kill connection exception received?
  if ( pUserCommCtrl->ulGlobCommState != commErrOk_esp01 )
    {
    MSGD (( INFO_CONNECTION_KILLED, pTaskCtrl->ulTaskIndex ));
    pUserCommCtrl->ulCommState = pUserCommCtrl->ulGlobCommState;
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  // - is the packet address valid?
  if ( pcRplPacket != (PCHAR)pReplyRTEHeader + RTE_HEADER_SIZE )
    {
    MSGD (( ERR_WRONG_PACK_ADDR, pcRplPacket ));
    pUserCommCtrl->ulCommState = commErrCrash_esp01;
    ABORT();
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  //
  // --- Setup the RTE header.
  //
  pReplyRTEHeader->ActSendLen      = (INT4)ulRplPacketLen +
                                     RTE_HEADER_SIZE;
  pReplyRTEHeader->ProtocolID      = RSQL_RTE_PROT_LOCAL_EO003;
  pReplyRTEHeader->MessClass       = RSQL_USER_DATA_REPLY_EO003;
  pReplyRTEHeader->RTEFlags        = RSQL_NORMAL_EO003;
  pReplyRTEHeader->ResidualPackets = 0;
  pReplyRTEHeader->SenderRef       = pTaskCtrl->ulTaskIndex;
  pReplyRTEHeader->ReceiverRef     = pUserCommCtrl->ulClientRef;
  pReplyRTEHeader->RTEReturnCode   = commErrOk_esp01;
  pReplyRTEHeader->NewSwapType     = sql53k_new_swap_type();
  pReplyRTEHeader->Filler1         = 0;
  pReplyRTEHeader->MaxSendLen      = (INT4)ulRplPacketLen +
                                     RTE_HEADER_SIZE;

  pCSHeader->ulSemaNo              = pTaskCtrl->pUKT->ulSemaNo;            // we are waiting on this UKT semaphore
  sql74k_long_term_move_lock( pTaskCtrl, WAITING_FOR_NEW_COMMAND, true );  // so that, we should not move to other UKTs

  pCSHeader->ulServerCommState     = pUserCommCtrl->ulCommState;
  RTESys_WriteMemoryBarrier();
  pCSHeader->ulServerFlag          = 1;

  // --- wake up client
  rc = sql41c_post_event_sem ( pUserCommCtrl->hClientSem, "Client" );

  if (( rc != NO_ERROR ) && ( rc != ERROR_ALREADY_POSTED ))
    {
    pUserCommCtrl->ulCommState = commErrCrash_esp01;
    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  DBGOUT;
  return ( commErrOk_esp01 );
  }

/*------------------------------*/

static VOID sql53k_release ( PTASK_CTRL_REC    pTaskCtrl )
  {
  #undef  MF__
  #define MF__ MOD__"sql53k_release"
  PUSER_TASK_COMM_CTRL           pUserCommCtrl;
  PCOMM_SEG_HEADER_REC           pCSHeader;
  APIRET                         rc = NO_ERROR;

/*
  if ( pTaskCtrl->ulTaskIndex == kgs.taskResponsibleForOffline )  // PTS 1134089
  {
      return;
  }
 */
  pUserCommCtrl = pTaskCtrl->pUserCommCtrl;
  pCSHeader     = pUserCommCtrl->pCSHeader;

  if ( pUserCommCtrl->pCSHeader != NULL ) // --- if still attached
    {
    pCSHeader->ulServerCommState = pUserCommCtrl->ulCommState;
    pCSHeader->ulServerRef       = (ULONG)UNDEF;
    RTESys_WriteMemoryBarrier();
    pCSHeader->ulServerFlag      = 1;
    }

  //
  // --- wake up the client and free it's semaphore
  //
  if ( pUserCommCtrl->hClientSem != INVALID_HANDLE_VALUE )
    {
    // --- wake up client
    sql41c_post_event_sem ( pUserCommCtrl->hClientSem, "Client" );

    // --- release client semaphore
    sql41c_close_event_sem ( pUserCommCtrl->hClientSem, "Client" );
    pUserCommCtrl->hClientSem = INVALID_HANDLE_VALUE;
    }


  WAIT_UNTIL_ALONE( &pTaskCtrl->lExclusive );

  //
  // --- free the client process handle
  //
  #if defined(_WIN32)
   if ( pUserCommCtrl->hLocalClientProcess != INVALID_HANDLE_VALUE )
     {
     if ( CloseHandle (pUserCommCtrl->hLocalClientProcess) != TRUE )
       {
       rc = GetLastError();
       MSGD (( ERR_CLOSING, "client process handle", rc ));
       DBG1 (( MF__, "INTERNAL ERROR: on closing %s, rc = %u",
               "client process handle", rc ));
       }

     pUserCommCtrl->hLocalClientProcess = INVALID_HANDLE_VALUE;
     }
  #endif


  if ( pUserCommCtrl->pCSHeader != NULL ) // --- if still attached
    {
    rc = sql41c_free_shrd_mem( pUserCommCtrl->pCSHeader,
                               pUserCommCtrl->hCS );

    pUserCommCtrl->pCSHeader = NULL;

    if ( rc != NO_ERROR )
      {
      CLEARLOCK( &pTaskCtrl->lExclusive );
      DBG1 ((MF__, "Could not shared free memory, rc = %u", rc ));
      ABORT();
      }
    }

  // remove long term move lock
  sql74k_long_term_move_lock( pTaskCtrl, CLIENT_NOT_TASK_MOVE_ENABLED, false );
  sql74k_long_term_move_lock( pTaskCtrl, WAITING_FOR_NEW_COMMAND, false );

  sql70k_init_user_comm_ctrl ( pUserCommCtrl );

  kgs.ConnectedUserTasks -= pTaskCtrl->TaskType == TT_US ? 1 : 0;

  CLEARLOCK( &pTaskCtrl->lExclusive );

  DBGOUT_T (pTaskCtrl->ulTaskIndex);
  return;
  }

/*------------------------------*/

static VOID sql53k_handle_ping ( PTASK_CTRL_REC        pTaskCtrl,
                                 PUSER_TASK_COMM_CTRL  pUserCommCtrl )
{
#   undef  MF__
#   define MF__ MOD__"sql53k_handle_ping"
    ULONG     ulCommState = commErrOk_esp01;

    PCOMM_SEG_HEADER_REC  pCSHeader   = pUserCommCtrl->pCSHeader;
    PCHAR                 pcRcvPacket;
    ULONG                 ulRcvPacketLen;

    do
    {
        ulCommState = sql53k_receive (pTaskCtrl, pUserCommCtrl, pCSHeader, 240, &pcRcvPacket, &ulRcvPacketLen);

        if  ( ulCommState == commErrOk_esp01 )
        {
           if ( eo420ExtractPingPacket( (char*)pcRcvPacket, ulRcvPacketLen, 0, 0, 0 ) )
           {
               ULONG ulReplyLen;
               if ( pCSHeader->ulMinReplySize )
                   ulReplyLen = pUserCommCtrl->ulMaxDataLen - ALIGN ( ulRcvPacketLen, SQL_PACKET_ALIGNMENT);
               else
                   ulReplyLen = pUserCommCtrl->ulMaxDataLen;

                ulReplyLen =  eo420FillPingPacket ( (char*) pUserCommCtrl->pReplyCommPacket->pDataPart,
                                                    ulReplyLen,
                                                    1,   // hops greater than 0 means that the final destination was reached
                                                    kgs.szServerDB,
                                                    XPARAM(szKernelVersion), 0 );

                if ( ulReplyLen )
                    ulCommState = sql53k_reply ( pTaskCtrl, pUserCommCtrl, (PCHAR)pUserCommCtrl->pReplyCommPacket->pDataPart, ulReplyLen );
                else
                    ulCommState = commErrNotOk_esp01;
            }
            else
                ulCommState = commErrNotOk_esp01;
        }
        else
            ulCommState = commErrNotOk_esp01;
    } 
    while( ulCommState == commErrOk_esp01  );
}

/*------------------------------*/

static VOID sql53k_remove_unrel_conn ( PTASK_CTRL_REC  pTaskCtrl )
  {
  #undef  MF__
  #define MF__ MOD__"sql53k_remove_unrel_conn"
  BOOL                            fWake = FALSE;
  PUSER_TASK_COMM_CTRL            pUserCommCtrl;
  PCOMM_SEG_HEADER_REC            pCSHeader;
  tsp00_Longuint                  ulConnected;
  #if defined(_WIN32)
   APIRET                         rc             = NO_ERROR;
  #endif

  //
  //  --- remove a unreleased connection
  //
  pUserCommCtrl  = pTaskCtrl->pUserCommCtrl;
  ulConnected    = pUserCommCtrl->ulConnected;   // - get logon time.

  if (( ulConnected          == 0 )               ||
      ( pTaskCtrl->TaskState == TSK_INACTIVE    ) ||
      ( pTaskCtrl->TaskState == TSK_TERMINATED  ) ||
      ( pTaskCtrl->TaskState == TSK_CONNECTWAIT ) ||
      ( pTaskCtrl->TaskState == TSK_VRELEASE    ) /* ||
      ( pTaskCtrl->ulTaskIndex == kgs.taskResponsibleForOffline ) */ )  // PTS 1134089
    {
    DBGOUT;
    return;
    }

   if( WaitForSingleObject( pUserCommCtrl->hLocalClientProcess, 0) != WAIT_TIMEOUT )
     {
     WAIT_UNTIL_ALONE( &pTaskCtrl->lExclusive );

     if ( ulConnected == pUserCommCtrl->ulConnected )
       {
       pUserCommCtrl->ulGlobCommState            = commErrCrash_esp01;
       RTESys_WriteMemoryBarrier();
       kgs.pulCommFlags[pTaskCtrl->ulCommFlagNo] = 1;
       pTaskCtrl->KernelCtrlRecord.to_cancel     = TRUE;
       fWake                                     = TRUE;
       }
     CLEARLOCK( &pTaskCtrl->lExclusive );
     }

   if ( fWake )
     {
     MSGD (( INFO_UNREL_CONN_FOUND, pTaskCtrl->ulTaskIndex ));
     sql72k_wake_ukt ( pTaskCtrl->pUKT );
     }

  // --- wake task if the client has not done this correctly!
  WAIT_UNTIL_ALONE( &pTaskCtrl->lExclusive );

  pCSHeader = pUserCommCtrl->pCSHeader;

  if (( pUserCommCtrl->ulConnected     == ulConnected) &&
      ( pCSHeader                      != NULL  )      &&
      (( pCSHeader->pidClientOrPeerPID == (PID)UNDEF ) ||
       ( pCSHeader->ulClientCommState  != commErrOk_esp01 )))
    {
    kgs.pulCommFlags[pTaskCtrl->ulCommFlagNo] = 1;
    fWake                                     = TRUE;
    }

  CLEARLOCK( &pTaskCtrl->lExclusive );

  if ( fWake )
    sql72k_wake_ukt ( pTaskCtrl->pUKT );

  DBGOUT;
  return;
  }

/*------------------------------*/

static tsp00_Uint1 sql53k_new_swap_type ()
{ 
  static  tsp00_Uint1               SwapType = (tsp00_Uint1)UNDEF_SP00;

  if ( SwapType == (tsp00_Uint1)UNDEF_SP00 )
  {
    union { tsp00_Int8         int8;
            tsp00_C8           c8; }  SwapCheck;
    
    /* --- set int8 to 0x100000000 */
    SwapCheck.int8   = 0x01;
    SwapCheck.int8 <<= 32;
    
    for ( SwapType = 0;
          ( SwapType < 8 ) && ( SwapCheck.c8[ SwapType ] != 1 ); 
          SwapType++ ) { ; }
  }
  
  return SwapType;
}


/*
 * =============================== END ========================================
 */
