/*!
  @file           vos33o.c
  @author         RaymondR
  @brief          old local 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 FILES
 */
//#include "gos00.h"
#include "gos41.h"
#include "heo00.h"
#include "heo46.h"
#include "gos003.h"
#include "hos33.h"
#include "geo007_1.h"
#include "geo007_2.h"


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

// --- UKT semaphore name size
#define UKT_SEM_BASENAME_SIZE            (MX_DBNAME + 20)
#define UKT_SEM_NAME_SIZE                (UKT_SEM_BASENAME_SIZE + 8)



#if defined(_WIN32)
 #define OLD_SEM_USR                    "SQLDB-USR-"
 #define OLD_SEM_UKT                    "SQLDB-UKT-"
 #define OLD_SHM_COMMSEG                "SQLDB-COMMSEG-"

 #define OLD_MAIL_REQ    ((sql02_get_platform_id () != VER_PLATFORM_WIN32_NT) ? \
                         "\\\\.\\mailslot\\SQLDB\\REQ\\" :                  \
                          "\\\\.\\mailslot\\SQLDB-REQ-" )
#else
 #define OLD_QUE_REQ                    "\\QUEUES\\SQLDB\\REQ\\"
#endif

/*
 *  MACROS
 */


/*
 *  LOCAL TYPE AND STRUCT DEFINITIONS
 */
typedef CHAR                          UNIQUE_OBJ_NAME[30];

typedef struct old_comm_segment_record
  {
  USHORT                          usCommState;

  #if defined(_WIN32)
   CHAR                           szUKTSemName[ UKT_SEM_NAME_SIZE ];
  #else
   HEV                            hevApplicSem;       // - OS/2 only
   HEV                            hevUKTSem;          // - OS/2 only
  #endif

  PID                             ApplPid;
  tsp01_Service                     Service;
  ULONG                           ulKernelRef;
  ULONG                           ulApplicRef;
  ULONG                           ulCommFlags;

  ULONG                           ulSendCounter;
  ULONG                           ulReplyCounter;

  ULONG                           ulNumOfSQLPackets;
  ULONG                           ulReqSQLPacket;

  #if defined(_WIN32)
   ULONG                          ulUKTIndex;         // - NT only
   UNIQUE_OBJ_NAME                Unused;             // - 3.1.2 only
  #endif

  OLD_SQL_PACKET_REC              SQLPacket[1];
  } OLD_COMM_SEGMENT_REC;

typedef OLD_COMM_SEGMENT_REC      *POLD_COMM_SEGMENT_REC;


//
// ---  Local connect request (via message queue to REQUESTOR thread)
//
#if defined(_WIN32)

typedef struct old_comm_request_record
  {
  ULONG                           ulReqType;
  ULONG                           ulKernelRef;
  ULONG                           ulCommSegLen;
  UNIQUE_OBJ_NAME                 UniqueObjName;
  } OLD_COMM_REQUEST_REC;

#else

typedef struct old_comm_request_bit_record
  {
  INT                             bf28KernelRef: 28,
                                  bf4Type      : 4;
  } OLD_COMM_REQUEST_BIT_REC;

typedef union old_comm_request_record
  {
  ULONG                           ulBitBlk;
  COMM_REQUEST_BIT_REC            BitFields;
  } OLD_COMM_REQUEST_REC;

#endif


/*
 * EXTERNAL VARIABLES
 */


/*
 *  EXPORTED VARIABLES
 */


/*
 * LOCAL VARIABLES
 */

/*
 * LOCAL FUNCTION PROTOTYPES
 */

static VOID    sql33o_connect_cleanup       ( POLD_SHM_INFO_REC  pConnInfo );

#if defined(_WIN32)
 static VOID   sql33o_build_unique_obj_name ( PSZ  pszUniqueObjName );
#endif


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

ULONG       sql33o_connect ( POLD_SHM_INFO_REC     pConnInfo,
                             ULONG                 ulApplicRef,
                             ULONG                 ulService,
                             PSZ                   pszServerDB,
                             PSECURITY_ATTRIBUTES  pWorldSA,
                             PSECURITY_ATTRIBUTES  pLockSA,
                             PULONG                pulKernelRef,
                             PVOID                 *ppSQLPacket,
                             tsp00_ErrTextc       pErrText,
                             ULONG                 ulTimeOut )
  {
  #undef  MF__
  #define MF__ MOD__"sql33o_connect"

  APIRET                          rc             = NO_ERROR;
  PSZ                             pszPath        = NULL;
  PSZ                             pszName        = NULL;
  static PID                      Pid            = (PID)UNDEF;
  PID                             pidKernel;             // --- OS/2 only
  POLD_COMM_SEGMENT_REC           pCommSeg;
  OLD_COMM_REQUEST_REC            Request;
  ULONG                           ulCommState;
  #if defined(_WIN32)
   ULONG                          ulRetry = 10;
   UNIQUE_OBJ_NAME                UniqueObjName;
  #endif

  DBGIN;

  if ( Pid == (PID)UNDEF )
    GETPROCESSID (&Pid);

  pConnInfo->ulApplicRef = ulApplicRef;
  strcpy ( pConnInfo->szServerDB, pszServerDB);
  strupr ( pConnInfo->szServerDB );

  #if defined(_WIN32)
   sql33o_build_unique_obj_name ( UniqueObjName );
  #endif

  pConnInfo->hevApplicSem   = (HEV)INVALID_HANDLE_VALUE;
  pConnInfo->hCommHandle    = INVALID_HANDLE_VALUE;
  pConnInfo->pCommSeg       = NULL;
  pConnInfo->hCommSeg       = (HANDLE)INVALID_HANDLE_VALUE;
  /*
   *  'pConnInfo->hevUKTSem' is not initialized here,
   *  because it holds the own UKT's
   *  sem handle in case of distribution and OS/2.
   *  Likewise, 'pConnInfo->szUKTSemName' holds the own UKT's
   *  sem name in case of distribution and NT.
   */

  //
  //
  // --- open mailslot / fifo queue
  //
  //
  #if defined(_WIN32)
   pszPath = OLD_MAIL_REQ;
  #else
   pszPath = OLD_QUE_REQ;
  #endif

  rc = sql41c_open_queue_mailslot ( &pidKernel,                 // - OS/2 only
                                    &pConnInfo->hCommHandle,
                                    pszPath, pConnInfo->szServerDB );

  if ( rc == ERROR_FILE_NOT_FOUND )
    {
    MSGD (( ERR_DATABASE_NOT_STARTED, pConnInfo->szServerDB ));
    eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_DATABASE_NOT_STARTED, 0 );

    DBGOUT;
    return ( commErrStartRequired_esp01 );
    }

  if ( rc != NO_ERROR)
    {
    eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_SERVER_OR_DB_NOT_ACC, rc );

    DBGOUT;
    return ( commErrNotOk_esp01 );
    }


  //
  //
  // --- create event semaphore
  //
  //
  #if defined(_WIN32)
   pszPath = OLD_SEM_USR;
   pszName = UniqueObjName;
  #else
   pszPath = NULL;
   pszName = NULL;
  #endif

  rc = sql41c_create_event_sem ( &pConnInfo->hevApplicSem,
                                 pszPath, pszName,
                                 CREATE_EVENT_SEM_SHARED, 0,
                                 pWorldSA );         // - WIN32 only

  #if defined(_WIN32)
   // --- unique name already in use?
   while (( rc == ERROR_DUPLICATE_NAME ) && (--ulRetry) )
     {
     SLEEP ( 1 );

     // -- build a new unique name
     sql33o_build_unique_obj_name ( UniqueObjName );

     rc = sql41c_create_event_sem ( &pConnInfo->hevApplicSem,
                                    pszPath, pszName,
                                    CREATE_EVENT_SEM_SHARED, 0,
                                    pWorldSA );      // - WIN32 only
     }
  #endif

  if ( rc != NO_ERROR )
    {
    pConnInfo->hevApplicSem = (HEV) INVALID_HANDLE_VALUE;
    DBG1 (( MF__, "ERROR: create event sem, rc =  %d", rc ));

    MSGD (( ERR_CANT_CREATE_COM_SEM, rc ));
    eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_CANT_CREATE_COM_SEM, rc );

    sql33o_connect_cleanup ( pConnInfo );

    DBGOUT;
    return ( commErrNotOk_esp01 );
    }


  //
  //
  // --- alloc shared communication memory segment with "world access"
  //
  //

  #if defined(_WIN32)
   pszPath = OLD_SHM_COMMSEG;
   pszName = UniqueObjName;
  #else
   pszPath = NULL;
   pszName = NULL;
  #endif

  rc = sql41c_create_shrd_mem ( (PVOID*) &pConnInfo->pCommSeg,
                                sizeof(OLD_COMM_SEGMENT_REC),
                                pszPath, pszName,
                                pWorldSA,                   // - WIN32 only
                                &pConnInfo->hCommSeg );     // - WIN32 only

  if ( rc != NO_ERROR )
    {
    DBG1 (( MF__, "ERROR: 'DosAllocSharedMem', rc =  %d", rc ));

    MSGD (( ERR_CANT_ALLOC_COM_SEG, rc ));
    eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_CANT_ALLOC_COM_SEG, rc );
    sql33o_connect_cleanup ( pConnInfo );

    DBGOUT;
    return ( commErrNotOk_esp01 );
    }



  //
  //
  // --- set access rights of the shared communication memory segment
  //     ( OS/2 only )
  //
  //

  #if !defined(_WIN32)
   rc = sql41c_give_shrd_mem ( pConnInfo->pCommSeg,
                               pidKernel, NULL, NULL );

   if ( rc != NO_ERROR )
     {
     eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_CANT_GIVE_COM_SEG, rc );
     sql33o_connect_cleanup ( pConnInfo );

     DBGOUT;
     return ( commErrNotOk_esp01 );
     }
  #endif


  //
  //
  // --- initialize shared communication memory segment
  //
  //

  pCommSeg = pConnInfo->pCommSeg;
  memset ( pCommSeg, 0, sizeof (OLD_COMM_SEGMENT_REC) );

  #if defined(_WIN32)
   strcpy ( pCommSeg->Unused, UniqueObjName); // - 3.1.2, 6.1.1 CL12 only !!!!!
   memset ( pCommSeg->szUKTSemName, 0, sizeof(pCommSeg->szUKTSemName) );
   pCommSeg->ulUKTIndex          = (ULONG) UNDEF;
  #else
   pCommSeg->hevApplicSem        = pConnInfo->hevApplicSem;
   pCommSeg->hevUKTSem           = (HEV) INVALID_HANDLE_VALUE;
  #endif


  pCommSeg->ApplPid             = Pid;
  pCommSeg->usCommState         = commErrOk_esp01;

  pCommSeg->Service             = (tsp01_Service)ulService;
  pCommSeg->ulKernelRef         = (ULONG)UNDEF;
  pCommSeg->ulApplicRef         = pConnInfo->ulApplicRef;
  pCommSeg->ulCommFlags         = CS_IN_USE;
  pCommSeg->ulSendCounter       = 1;
  pCommSeg->ulReplyCounter      = 0; // - for Distribution

  pCommSeg->ulNumOfSQLPackets   = 1;
  pCommSeg->ulReqSQLPacket      = 0;



  //
  //
  // --- send a connect request
  //
  //

  #if defined(_WIN32)
   Request.ulReqType               = SQL_RTE_CONNECT;
   Request.ulKernelRef             = 0;
   Request.ulCommSegLen            = sizeof (OLD_COMM_SEGMENT_REC);
   strcpy ( Request.UniqueObjName, UniqueObjName );
  #else
   Request.BitFields.bf4Type       = SQL_RTE_CONNECT;
   Request.BitFields.bf28KernelRef = 0;
  #endif

  rc = sql41c_write_queue_mailslot ( pConnInfo->hCommHandle,
                                     &Request,
                                     sizeof (OLD_COMM_REQUEST_REC),
                                     sizeof (OLD_COMM_SEGMENT_REC),// OS/2 only
                                     pCommSeg );                   // OS/2 only

  if ( rc != NO_ERROR )
    {
    DBG1 (( MF__, "ERROR: 'sql41c_write_queue_mailslot', rc =  %d", rc ));

    // --- signal connection lost!
    pCommSeg->ApplPid     = (PID)UNDEF;
    pCommSeg->ulApplicRef = (ULONG)UNDEF;
    pCommSeg->usCommState = commErrCrash_esp01;
    sql33o_connect_cleanup ( pConnInfo );

    if (( rc == ERROR_HANDLE_EOF ) || ( rc == ERROR_FILE_NOT_FOUND ))
      eo46BuildErrorStringRC( pErrText, ERRMSG_COM_DATABASE_NOT_STARTED, 0 );
    else
      eo46BuildErrorStringRC( pErrText, ERRMSG_COM_CANT_WRITE_COM_QUE, rc );

    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  /*
   *  This is now initialized here, because it held the own UKT's
   *  sem handle (sem name) in case of distribution and OS/2 (NT).
   */
  pConnInfo->hevUKTSem = (HEV)INVALID_HANDLE_VALUE;
  (void) memset ( pConnInfo->szUKTSemName, 0,
                  sizeof(pConnInfo->szUKTSemName) );

  //
  //
  // --- wait on own semaphore
  //
  //
  rc =  sql41c_wait_event_sem ( pConnInfo->hevApplicSem,
                                ulTimeOut * 1000, "COM" );

  if ( rc != NO_ERROR )
    {
    // --- signal connection lost!
    pCommSeg->ApplPid     = (PID)UNDEF;
    pCommSeg->ulApplicRef = (ULONG)UNDEF;
    pCommSeg->usCommState = commErrCrash_esp01;

    if ( rc == ERROR_TIMEOUT )
      {
      MSGD (( ERR_CONN_TIMEOUT ));
      eo46BuildErrorStringRC ( pErrText, ERRMSG_CONN_TIMEOUT, 0 );
      }
    else
      {
      MSGD (( ERR_WAIT_COM_SEM, rc ));
      eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_WAIT_COM_SEM, rc );
      }

    sql33o_connect_cleanup ( pConnInfo );

    DBGOUT;
    return ( commErrNotOk_esp01 );
    }


  //
  //
  // --- got message
  //
  //

  if ( pCommSeg->usCommState != commErrOk_esp01 )
    {
    pCommSeg->ApplPid     = (PID)UNDEF;
    pCommSeg->ulApplicRef = (ULONG)UNDEF;
    ulCommState           = pCommSeg->usCommState;

    MSGD (( ERR_CONN_REFUSED ))
    eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_CONN_REFUSED, 0 );
    sql33o_connect_cleanup ( pConnInfo );

    DBGOUT;
    return ( ulCommState );
    }
  else
    {
    pConnInfo->ulKernelRef = pCommSeg->ulKernelRef;
    *pulKernelRef          = pCommSeg->ulKernelRef;
    *ppSQLPacket           = (PVOID)pCommSeg->SQLPacket;
    }


  //
  //
  // --- lock shared communication memory segment
  //     ( NT only )
  //
  //
  #if defined(_WIN32)

   // --- set security descriptor with "no access"
   rc = sql49c_set_kernel_obj_sec ( pLockSA->lpSecurityDescriptor,
                                    pConnInfo->hCommSeg );

   if ( rc != NO_ERROR )
     {
     pCommSeg->ApplPid     = (PID)UNDEF;
     pCommSeg->ulApplicRef = (ULONG)UNDEF;
     pCommSeg->usCommState = commErrCrash_esp01;

     DBG1 (( MF__, "ERROR: 'sql49c_set_kernel_obj_sec', rc =  %d", rc ));
     eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_CANT_SET_OBJ_SEC, rc );
     sql33o_connect_cleanup ( pConnInfo );

     DBGOUT;
     return ( commErrNotOk_esp01 );
     }
  #endif


  // --- connection still alive?
  if ( (pCommSeg->ulCommFlags & CS_CONN_RELEASED) == 0 )
    {
    //
    //
    // --- open ukt semaphore
    //
    //

    #if defined(_WIN32)
     pszPath = OLD_SEM_UKT;
     pszName = pCommSeg->szUKTSemName;
    #else
     pszPath = NULL;
     pszName = NULL;

     pConnInfo->hevUKTSem  = pCommSeg->hevUKTSem;
    #endif

    rc = sql41c_open_event_sem ( &pConnInfo->hevUKTSem, pszPath,
                                 pszName, NO_ERROR );

    if ( rc != NO_ERROR )
      {
      DBG1 (( MF__, "ERROR: 'sql41c_open_event_sem', rc =  %d", rc ));

      pCommSeg->ApplPid     = (PID)UNDEF;
      pCommSeg->ulApplicRef = (ULONG)UNDEF;
      pCommSeg->usCommState = commErrCrash_esp01;

      MSGD (( ERR_CANT_OPEN_UKT_SEM, rc ));
      eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_CANT_OPEN_UKT_SEM, rc );
      sql33o_connect_cleanup ( pConnInfo );

      DBGOUT;
      return ( commErrNotOk_esp01 );
      }
    }


  DBGOUT;
  return ( commErrOk_esp01 );
  }

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

ULONG      sql33o_request ( POLD_SHM_INFO_REC     pConnInfo,
                            tsp00_ErrTextc       pErrText )
  {
  #undef  MF__
  #define MF__ MOD__"sql33o_request"
  APIRET                          rc       = NO_ERROR;
  POLD_COMM_SEGMENT_REC           pCommSeg;

  DBGIN;

  pCommSeg = pConnInfo->pCommSeg;

  DBG3 (( MF__, "usCommState   :   %d", pCommSeg->usCommState    ));
  DBG3 (( MF__, "ulSendCounter :   %d", pCommSeg->ulSendCounter  ));
  DBG3 (( MF__, "ulReplyCounter:   %d", pCommSeg->ulReplyCounter ));


  if ( pCommSeg->ulSendCounter != pCommSeg->ulReplyCounter )
    {
    if ( pCommSeg->ulKernelRef != pConnInfo->ulKernelRef ||
         pCommSeg->usCommState == commErrTimeout_esp01 )
      {
      MSGD (( INFO_COM_TIMEOUT ));
      eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_TIMEOUT, 0 );
      return ( commErrTimeout_esp01 );
      }
    else if ( pCommSeg->usCommState != commErrOk_esp01 )
      {
      eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_CONN_BROKEN, 0 );
      return ( pCommSeg->usCommState );
      }
    else if ( pCommSeg->ulCommFlags & CS_CONN_RELEASED )
      {
      eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_CONN_BROKEN, 0 );
      return ( commErrNotOk_esp01 );
      }
    else if ( pCommSeg->ulReplyCounter < pCommSeg->ulSendCounter )
      {
      MSGD (( ERR_UNBAL_REQUEST_REPLY ));
      eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_UNBALANCED_REQUEST_REPLY,
                                  0 );
      return ( commErrNotOk_esp01 );
      }
    }
  else if ( pCommSeg->usCommState != commErrOk_esp01 )
    {
    eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_CONN_BROKEN, 0 );
    return ( pCommSeg->usCommState );
    }

  pCommSeg->ulSendCounter++;

  // ---  Wake up the UKT!
  rc = sql41c_post_event_sem ( pConnInfo->hevUKTSem, "UKT" );

  if (( rc != NO_ERROR ) && ( rc != ERROR_ALREADY_POSTED ))
    {
    DBG1 (( MF__, "ERROR: Posting event sem, rc =  %d", rc ));
    eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_POST_UKT_SEM, rc );

    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  DBG3 (( MF__, "ulSendCounter :   %d", pCommSeg->ulSendCounter  ));
  DBG3 (( MF__, "ulReplyCounter:   %d", pCommSeg->ulReplyCounter ));

  DBGOUT;
  return ( commErrOk_esp01 );
  }

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

ULONG      sql33o_receive ( POLD_SHM_INFO_REC     pConnInfo,
                            tsp00_ErrTextc        pErrText )
  {
  #undef  MF__
  #define MF__ MOD__"sql33o_receive"
  APIRET                          rc                = NO_ERROR;
  POLD_COMM_SEGMENT_REC           pCommSeg;

  DBGIN;

  pCommSeg = pConnInfo->pCommSeg;

  DBG3 (( MF__, "usCommState   :   %d", pCommSeg->usCommState    ));
  DBG3 (( MF__, "ulSendCounter :   %d", pCommSeg->ulSendCounter  ));
  DBG3 (( MF__, "ulReplyCounter:   %d", pCommSeg->ulReplyCounter ));


  do
    {
    //
    // --- wait on own semaphore
    //
    rc =  sql41c_wait_event_sem (pConnInfo->hevApplicSem,
                                 (ULONG)-1, "COM" );

    if ( rc != NO_ERROR )
      {
      DBG1 (( MF__, "ERROR: 'sql41c_wait_event_sem', rc =  %d", rc ));
      MSGD (( ERR_WAIT_COM_SEM, rc ));
      eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_WAIT_COM_SEM, rc );

      DBGOUT;
      return ( commErrNotOk_esp01 );
      }
    }
  while (( pCommSeg->ulSendCounter >  pCommSeg->ulReplyCounter ) &&
         ( pCommSeg->usCommState   == commErrOk_esp01 ));

  if ( pCommSeg->usCommState != commErrOk_esp01 )
    {
    eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_CONN_BROKEN, 0 );

    DBGOUT;
    return ( (ULONG)pCommSeg->usCommState );
    }

  if (( pCommSeg->ulSendCounter  != pCommSeg->ulReplyCounter )  &&
      ( pCommSeg->ulReplyCounter != (ULONG)UNDEF ))
    {
    DBG1 (( MF__, "ulSendCounter :   %d", pCommSeg->ulSendCounter  ));
    DBG1 (( MF__, "ulReplyCounter:   %d", pCommSeg->ulReplyCounter ));
    MSGD (( ERR_UNBAL_REQUEST_REPLY ));
    eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_UNBALANCED_REQUEST_REPLY, 0 );

    return ( commErrNotOk_esp01 );
    }

  if ( pCommSeg->SQLPacket[0].MaxSendLen < OLD_RTE_HEADER_SIZE )
    pCommSeg->SQLPacket[0].MaxSendLen = OLD_RTE_HEADER_SIZE;

  DBG3 (( MF__, "ulSendCounter :   %d", pCommSeg->ulSendCounter  ));
  DBG3 (( MF__, "ulReplyCounter:   %d", pCommSeg->ulReplyCounter ));

  DBGOUT;
  return ( commErrOk_esp01 );
  }

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

ULONG       sql33o_cancel ( POLD_SHM_INFO_REC     pConnInfo,
                            tsp00_ErrTextc       pErrText )
  {
  #undef  MF__
  #define MF__ MOD__"sql33o_cancel"
  APIRET                          rc = NO_ERROR;
  OLD_COMM_REQUEST_REC            Request;

  DBGIN;

  //
  // --- send a cancel request
  //

  #if defined(_WIN32)
   Request.ulReqType               = SQL_RTE_CANCEL;
   Request.ulKernelRef             = pConnInfo->ulKernelRef;
   Request.ulCommSegLen            = 0;
  #else
   Request.BitFields.bf4Type       = SQL_RTE_CANCEL;
   Request.BitFields.bf28KernelRef = pConnInfo->ulKernelRef;
  #endif

  rc = sql41c_write_queue_mailslot ( pConnInfo->hCommHandle,
                                     &Request,
                                     sizeof (OLD_COMM_REQUEST_REC),
                                     0,                         // - OS/2 only
                                     NULL );                    // - OS/2 only

  if ( rc != NO_ERROR )
    {
    DBG1 (( MF__, "ERROR: 'sql41c_write_queue_mailslot', rc =  %d", rc ));

    if ( rc == ERROR_HANDLE_EOF )
      eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_DATABASE_NOT_STARTED, 0 );
    else
      eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_CANT_WRITE_COM_QUE, rc );

    DBGOUT;
    return ( commErrNotOk_esp01 );
    }

  DBGOUT;
  return ( commErrOk_esp01 );
  }

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

ULONG      sql33o_release ( POLD_SHM_INFO_REC     pConnInfo,
                            tsp00_ErrTextc         pErrText )
  {
  #undef  MF__
  #define MF__ MOD__"sql33o_release"
  ULONG                           ulCommState = commErrOk_esp01;
  POLD_COMM_SEGMENT_REC           pCommSeg;
  APIRET                          rc = NO_ERROR;

  DBGIN;

  /*
   *  In case the session is not completed, we simulate a request with
   *  commErrNotOk_esp01, which will terminate the session if the UKT is in VRECEIVE
   */
  pCommSeg                = pConnInfo->pCommSeg;
  pConnInfo->pCommSeg = NULL;

  if ( pCommSeg != NULL )
     {
     pCommSeg->SQLPacket[0].ActSendLen  = 0;
     pCommSeg->usCommState              = commErrNotOk_esp01;
     pCommSeg->ulSendCounter            = (ULONG)UNDEF;
     pCommSeg->ulApplicRef              = pConnInfo->ulApplicRef;

     if (( (pCommSeg->ulCommFlags & CS_CONN_RELEASED) == 0 ) &&
         ( pConnInfo->hCommHandle  != (HEV) INVALID_HANDLE_VALUE ))
       {
       // ---  Wake up the UKT!
       rc = sql41c_post_event_sem ( pConnInfo->hevUKTSem, "UKT" );

       if (( rc != NO_ERROR ) && ( rc != ERROR_ALREADY_POSTED ))
         {
         // --- signal connection lost!
         pCommSeg->ApplPid               = (PID)UNDEF;
         pCommSeg->ulApplicRef           = (ULONG)UNDEF;
         pCommSeg->usCommState           = commErrCrash_esp01;
         ulCommState                     = commErrNotOk_esp01;

         eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_POST_UKT_SEM, rc );
         }
       }

     rc = sql41c_free_shrd_mem ( pCommSeg, pConnInfo->hCommSeg );

     if ( rc != NO_ERROR )
       {
       ulCommState = commErrNotOk_esp01;
       eo46BuildErrorStringRC ( pErrText, ERRMSG_COM_CANT_FREE_MEM, rc );
       }
     }

  pConnInfo->ulKernelRef = (ULONG)-1;

  if ( pConnInfo->hCommHandle != (HEV) INVALID_HANDLE_VALUE )
    {
    sql41c_close_queue_mailslot ( pConnInfo->hCommHandle );
    pConnInfo->hCommHandle = INVALID_HANDLE_VALUE;
    }

  if ( pConnInfo->hevApplicSem != (HEV) INVALID_HANDLE_VALUE )
    {
    sql41c_close_event_sem ( pConnInfo->hevApplicSem, "Application" );
    pConnInfo->hevApplicSem  = (HEV) INVALID_HANDLE_VALUE;
    }

  if ( pConnInfo->hevUKTSem != (HEV) INVALID_HANDLE_VALUE )
    {
    sql41c_close_event_sem ( pConnInfo->hevUKTSem, "UKT" );
    pConnInfo->hevUKTSem = (HEV) INVALID_HANDLE_VALUE;
    }

  DBGOUT;
  return ( ulCommState );
  }

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

#if defined(_WIN32)

static VOID sql33o_build_unique_obj_name ( PSZ  pszUniqueObjName )
  {
  #undef  MF__
  #define MF__ MOD__"sql33o_get_unique_obj_name"
  ULONG                 ulStrLen;
  ULONG                 ulCurrTime;
  static ULONG          ulIdx = 0;
  static PID            Pid   = (PID)UNDEF;
  TID                   Tid;

  DBGPAS;

  if ( Pid == (PID)UNDEF )
    GETPROCESSID (&Pid);

  Tid        = THREADID;
  ulCurrTime = GetCurrentTime ();

  _ultoa ( (ULONG)Pid, pszUniqueObjName, 16 );

  ulStrLen = (ULONG)strlen ( pszUniqueObjName );
  pszUniqueObjName [ ulStrLen ] = '-';
  _ultoa ( (ULONG)Tid, pszUniqueObjName + ulStrLen + 1, 16 );

  ulStrLen = (ULONG)strlen ( pszUniqueObjName );
  pszUniqueObjName [ ulStrLen ] = '-';
  _ultoa ( ++ulIdx, pszUniqueObjName + ulStrLen + 1, 16 );

  ulStrLen = (ULONG)strlen ( pszUniqueObjName );
  pszUniqueObjName [ ulStrLen ] = '-';
  _ultoa ( ulCurrTime, pszUniqueObjName + ulStrLen + 1, 16 );

  strupr (pszUniqueObjName);

  DBG3 (( MF__, "pszUniqueObjName : '%s'", pszUniqueObjName ));

  #if 0
   // --- for debug purpose only
   MSGCD (( 0,0, "pszUniqueObjName: %s", pszUniqueObjName ));
  #endif

  return;
  }

#endif

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

VOID sql33o_connect_cleanup ( POLD_SHM_INFO_REC     pConnInfo )
  {
  #undef  MF__
  #define MF__ MOD__"sql33o_connect_cleanup"

  DBGPAS;

  if ( pConnInfo->hevApplicSem != (HEV) INVALID_HANDLE_VALUE)
    {
    sql41c_close_event_sem ( pConnInfo->hevApplicSem, "Application" );
    pConnInfo->hevApplicSem = (HEV) INVALID_HANDLE_VALUE;
    }

  if ( pConnInfo->hCommHandle != INVALID_HANDLE_VALUE )
    {
    sql41c_close_queue_mailslot ( pConnInfo->hCommHandle );
    pConnInfo->hCommHandle = INVALID_HANDLE_VALUE;
    }

  if ( pConnInfo->pCommSeg != NULL )
    {
    sql41c_free_shrd_mem ( pConnInfo->pCommSeg,
                           pConnInfo->hCommSeg );
    pConnInfo->pCommSeg = NULL;
    pConnInfo->hCommSeg = (HANDLE)INVALID_HANDLE_VALUE;
    }

  return;
  }

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