/*!
  @file           ven33.c
  @author         JoergM
  @brief          RunTime: Communication Functions for remote Access
  @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
*/

/*PRETTY*/

#include "RunTime/System/RTESys_MemoryBarrier.h"

/* exported functions */
#include "gen00.h"
#include "heo00.h"
#include "vsp001c.h"
#include "gen003.h"
#include "gen33.h"

/* imported functions */

#include "gen32.h"
#include "gen41.h"
#include "gen42.h"
#include "geo001.h"
#include "geo57.h"
#include "hen40.h"

/* local functions */

/* exported data */

static void sql33_detach_shm ( connection_info     *cip );

static void sql33_remove_shm ( connection_info     *cip );

static void sql33_remove_sem ( connection_info     *cip );

static  int sql33_attach_big_comseg ( connection_info *cip ,
                                      connection_info  conn_info [ ],
                                      int              count);

static void sql33_detach_big_comseg ( connection_info *cip ,
                                      connection_info  conn_info [ ],
                                      int              count);

/* imported data */


/* local data */


/* Macros */

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

externC teo00_Longuint 
en33Request ( connection_info         *pConnInfo, 
              teo00_Longuint           ulDataLen,
              tsp00_ErrTextc           pErrText )
{
#undef	MF__
#define	MF__	"en33Request"
  teo00_Longuint ulCommState;

  DBGIN;

  pConnInfo->ci_request_lgt = ulDataLen ;

  pConnInfo->ci_reply = (rte_header*) 
                        (((char*) pConnInfo->ci_request) + ulDataLen + RTE_HEADER_SIZE_EO003 );

  pConnInfo->ci_reply_size  = pConnInfo->ci_max_data_size - pConnInfo->ci_request_lgt ;

  ulCommState = sql33_request ( pConnInfo, pErrText ) ;

  return( ulCommState ) ;
}

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

externC teo00_Longuint 
en33Receive ( connection_info          *pConnInfo, 
              teo003_CommPacketRecord **ppResultPacket,
              teo00_Longuint           *pulResultLen,
              tsp00_ErrTextc            pErrText )
{
#undef	MF__
#define	MF__	"en33Receive"
  teo00_Longuint                  ulCommState;

  DBGIN;

  ulCommState = sql33_receive( pConnInfo, pErrText );

  *ppResultPacket = (teo003_CommPacketRecord *) pConnInfo->ci_reply ;
  *pulResultLen   = pConnInfo->ci_reply->rh_max_send_len - RTE_HEADER_SIZE_EO003 ;

  return( ulCommState ) ;
}

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

int     sql33_connect ( 
connection_info		*cip ,
tsp00_ErrTextc      pErrText,
connection_info		conn_info [ ],
int                 count)
{
#undef	MF__
#define	MF__	"sql33_connect"
    int				rc ;
    int				idx ;
    int				savpktcnt ;
    int				reply_fd ;
    int				kernel_fd ;
    int				messclass ;
    tsp00_Int4			myref ;
    int				retcod ;
    int				service ;
    SQL_DBNAMEC			mydb ;
    SQL_DBNAMEC			peerdb ;
    tsp00_Int4			shmid4 ;
    uid_t			uid ;
    long			siz ;
    long			off ;
    char			*ptr ;
    comseg_header		*comseg ;
    rte_header			*header ;
    char			packet [ RTE_CONPKT_SIZE ];
    VF_FILENAMEC		file ;
    struct sembuf		semrcv ;
    tsp00_DbNamec   peer_dbname;  


    DBG1 (( MF__,"local dbname '%s' service %d \n",
			cip->ci_peer_dbname , cip->ci_service ))

    strcpy (peer_dbname, cip->ci_peer_dbname);

	for (idx = 0; cip->ci_peer_dbname[idx] != 0; ++idx)
	{
		if (islower (cip->ci_peer_dbname[idx]))
		{
			peer_dbname[idx] = toupper (cip->ci_peer_dbname[idx]);
		}
	}

	rc = sql32_open_kernel_fifo ( peer_dbname , &kernel_fd ,
		&uid , pErrText );
	if ( rc != commErrOk_esp01 )
	{
		DBG1 (( MF__,"cannot open knl fifo: %s\n", pErrText ))
			return ( rc );
	}

    DBG1 (( MF__,"opened kernel fifo, fd %d \n", kernel_fd ))

    /*
     *  The reply fifo must be open before REQUESTOR writes to it.
     *  Otherwise REQUESTOR might be fast enough to close the reply fifo
     *  before the application had it open.
     *  The last close on a fifo clears its contents.
     */
    rc = sql32_open_reply_fifo ( peer_dbname , cip->ci_my_pid ,
				cip->ci_my_ref , (char *)file , &reply_fd , pErrText );
    if ( rc != commErrOk_esp01 )
    {
	DBG1 (( MF__,"cannot open reply fifo: %s\n", pErrText ))
	(void) close ( kernel_fd );
	return ( rc );
    }

    /*
     *  Create own semaphore for communication with DB.
     *  Key for semaphore is own pid modified by reference.
     *  If a semaphore key of this value exists, try some other values.
     */
    cip->ci_my_semid = sql41_create_sem ( (key_t)0 , (int) cip->ci_my_ref , 16 ,
			    0666 , uid , "us" , peer_dbname );
    DBG1 (( MF__,"semid %d \n", cip->ci_my_semid ))
    if ( cip->ci_my_semid == UNDEF )
    {
	    en42FillErrText(pErrText, "cannot create communication semaphore");
	    (void) close ( kernel_fd );
	    (void) close ( reply_fd );
	    (void) unlink ( (char *)file );
	    return ( commErrNotOk_esp01 );
    }

    /*
     *  This method works with a single packet only.
     */
    savpktcnt = cip->ci_packet_cnt ;
    cip->ci_packet_cnt = 1 ;

    cip->ci_protocol = PROT_BIGSHM_EO003 ;
    /*
     *  Don't initialize these. They are used by vserver
     *  and are otherwise initialized by ven03c.
     *
     *  cip->ci_max_segment_size = 0 ;
     *  cip->ci_max_data_size = 0 ;
     *  cip->ci_packet_size = 0 ;
     *  cip->ci_min_reply_size = 0 ;
     */

    header = (rte_header*) packet ;
    sql42_create_conpkt ( header , RSQL_USER_CONN_REQUEST_EO003 ,
			    cip->ci_my_ref , (tsp00_Int4)0 ,
			    commErrOk_esp01 , cip->ci_service ,
			    cip->ci_max_segment_size ,
			    cip->ci_max_data_size ,
			    cip->ci_packet_size ,
			    cip->ci_min_reply_size ,
			    "" , cip->ci_peer_dbname );
    sql42_put_int4 ( header , RSQL_OPT_PKTCNT_EO003 , (tsp00_Int4) cip->ci_packet_cnt );
    sql42_put_long ( header , RSQL_OPT_PID_EO003    , (long) cip->ci_my_pid );
    sql42_put_int4 ( header , RSQL_OPT_SEMID_EO003  , (tsp00_Int4) cip->ci_my_semid );
    sql42_put_string (header, RSQL_OPT_FIFO_EO003   , (char *)file );
	sql42_put_int1 ( header, RSQL_OPT_ALTER_SERV_SEM_EO003, (tsp00_Uint1) true );
    /*
     *  The following will be used by vserver.
     */
    if ( cip->ci_peer_node[0] )
    {
	sql42_put_string ( header , RSQL_OPT_NODE_EO003 , (char *)cip->ci_peer_node );
    }
    if ( cip->ci_remote_pid[0] )
    {
	sql42_put_string ( header , RSQL_OPT_REM_PID_EO003 , (char *)cip->ci_remote_pid );
    }

    rc = sql42_send_conpkt ( kernel_fd , header , pErrText );
    if ( rc != commErrOk_esp01 )
    {
	    DBG1 (( MF__,"cannot write to kernel fifo: %s \n", pErrText ))
	    (void) close ( kernel_fd );
	    (void) close ( reply_fd );
	    (void) unlink ( (char *)file );
	    sql33_remove_sem ( cip );
	    cip->ci_packet_cnt = savpktcnt ;
	    return ( rc );
    }
    (void) close ( kernel_fd );
    DBG1 (( MF__,"sent connect request to '%s' \n", cip->ci_peer_dbname ))

    rc = sql42_recv_conpkt ( reply_fd , header , &cip->ci_state , pErrText );
    if ( rc != commErrOk_esp01 )
    {
	    DBG1 (( MF__": %s \n", pErrText ))
	    RTE_save_close ( reply_fd );
	    RTE_save_unlink ( (char *)file );
	    sql33_remove_sem ( cip );
	    cip->ci_packet_cnt = savpktcnt ;
	    return ( rc );
    }
    DBG1 (( MF__,"received reply from fd %d lgt %d \n", reply_fd , header->rh_max_send_len ))

    (void) close ( reply_fd );
    (void) unlink ( (char *)file );
    DBG1 (( MF__,"closed/unlinked '%s', fd %d \n", file , reply_fd ))

    shmid4 = -1 ;
    cip->ci_big_offset = -1 ;
    sql42_extract_conpkt ( header , &messclass ,
			    &myref , &cip->ci_peer_ref ,
			    &retcod , &service ,
			    &cip->ci_max_segment_size ,
			    &cip->ci_max_data_size ,
			    &cip->ci_packet_size ,
			    &cip->ci_min_reply_size ,
			    &cip->ci_peer_swap_type ,
			    (char *)mydb , (char *)peerdb );
    sql42_get_int4 ( header , RSQL_OPT_SHMID_EO003 , &shmid4 );
    sql42_get_long ( header , RSQL_OPT_OFFSET_EO003 , &cip->ci_big_offset );
    cip->ci_shmid = shmid4 ;
    DBG1 (( MF__,"big shmid %d off %ld \n",
		cip->ci_shmid , cip->ci_big_offset ))

    /*
     *  Check the received information.
     */
    rc = commErrOk_esp01 ;
    if ( messclass != RSQL_USER_CONN_REPLY_EO003 )
    {
	    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "server messclass %d expected %d \n",
					    messclass , RSQL_USER_CONN_REPLY_EO003 ))
	    en42FillErrText(pErrText, "protocol error: got %d not USER_CONN_REPLY", messclass);
#if ACCEPT_KERN_CONN_REPLY
	    if ( messclass != RSQL_KERN_CONN_REPLY_EO003 )
#endif
	    rc = commErrNotOk_esp01 ;
    }
    if ( myref != cip->ci_my_ref )
    {
	    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "server reference %d expected %d \n",
						        myref , cip->ci_my_ref ))
	    en42FillErrText(pErrText,
                        "protocol error: ref %d/%d",
                        myref,
                        cip->ci_my_ref);
	    rc = commErrNotOk_esp01 ;
    }
    if ( service != cip->ci_service )
    {
	    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "server service %d expected %d \n",
						    service , cip->ci_service ))
	    en42FillErrText(pErrText,
                        "protocol error: service %d/%d",
                        service,
                        cip->ci_service);
	    rc = commErrNotOk_esp01 ;
    }
    if ( strcmp ( (char *)peerdb , (char *)cip->ci_peer_dbname ) )
    {
	    en42FillErrText(pErrText,
                        "protocol error: dbname %d/%d",
                        peerdb,
                        cip->ci_peer_dbname);
	    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "server dbname '%s' expected '%s' \n",
						    peerdb , cip->ci_peer_dbname ))
	    rc = commErrNotOk_esp01 ;
    }
    if ( retcod != commErrOk_esp01 )
    {
	    if ( rc == commErrOk_esp01 )
	    {
	        switch ( retcod )
	        {
	        case commErrNotOk_esp01 :
	            en42FillErrText(pErrText,
                                "protocol error",
                                retcod);
                break;
	        case SP1CE_TIMEOUT :
	            en42FillErrText(pErrText,
                                "protocol error: TIMEOUT" );
	    	    break ;
	        case SP1CE_TASKLIMIT :
	            en42FillErrText(pErrText,
                                "task limit" );
		        break ;
	        case SP1CE_RELEASED :
	            en42FillErrText(pErrText,
                                "server rejected connection" );
		        break ;
	        default :
	            en42FillErrText(pErrText,
                                "database not running:retcod %d", retcod );
		        break ;
	        }
	        rc = (int) retcod ;
	        DBG1 (( MF__,"sql33_connect: server returned %d \n", rc ))
	    }
    }
    else /* if retcod != commErrOk_esp01 */
    {
	    if ( shmid4 == -1 )
	    {
	        MSGD (( -11987, ERR_TYPE, "COMMUNIC", "server '%s' didn't return shmid \n",
							    cip->ci_peer_dbname ))
	        en42FillErrText(pErrText,
                            "protocol error: shmid == -1" );
	        rc = commErrNotOk_esp01 ;
	    }
	    if ( cip->ci_big_offset == -1 )
	    {
	        MSGD (( -11987, ERR_TYPE, "COMMUNIC", "server '%s' didn't return offset\n",
							    cip->ci_peer_dbname ))
	        en42FillErrText(pErrText,
                            "protocol error: shmoffset == -1" );
	        rc = commErrNotOk_esp01 ;
	    }
    }
    /* end if retcod != commErrOk_esp01 */

    /*
     *  On any protocol error close connection.
     */
    if ( rc != commErrOk_esp01 )
    {
	    sql33_remove_sem ( cip );
	    cip->ci_packet_cnt = savpktcnt ;
	    return ( rc );
    }

    /*
     *  Well, the REQUESTOR made the connection and everything is fine,
     *  except of the fact that the UKP did not yet initialize the comseg.
     *  Wait on own semaphore until notified by the UKP.
     */
    {
        struct sembuf ownrcv;
        ownrcv.sem_num = 0;
        ownrcv.sem_op = -1;
        ownrcv.sem_flg = 0;
        DBG1 (( MF__,"wait  semid  %d \n", cip->ci_my_semid ))
        rc = RTE_save_semop ( cip->ci_my_semid , &ownrcv , 1 );
    }
    DBG1 (( MF__,"awoke semid  %d \n", cip->ci_my_semid ))
    if ( (rc == UNDEF) && (errno != EIDRM) && (errno != EINVAL) )
    {
    	en42FillErrText( pErrText,
                         "connection broken: semop (%d:%s)",
                         errno,
                         sqlerrs() );
	    MSGD (( -11987, ERR_TYPE, "CONNECT ", "receive sem %d : %s\n",
						cip->ci_my_semid , &pErrText[0] ))
	    cip->ci_packet_cnt = savpktcnt ;
	    return ( commErrNotOk_esp01 );
    }

    /*
     *  Fine, the UKP awoke us. Now, the comseg should be set up right.
     *  Attach the big communication segment,
     *  if not already attached by another session,
     *  and initialize the comseg pointers.
     */
    rc = sql33_attach_big_comseg ( cip , conn_info, count );
    if ( rc != commErrOk_esp01 )
    {
    /* PTS 1109601 */
        (void)sql33_cancel ( cip, pErrText );
        /*
           If attach of big communication shared memory segment fails due to client resource problem
           (number of shared memory segments exceeded) the kernel resources for this connection are
           blocked forever! Therefore a cancellation request is enforced here. sql33_cancel() is
           needed, since sql33_release() would need a valid shared memory...
         */
    	en42FillErrText(pErrText,
                        "database not accessible: attach failed" );
	    sql33_remove_sem ( cip );
	    cip->ci_packet_cnt = savpktcnt ;
	    return ( rc );
    }
    comseg = cip->ci_comseg ;

    /*
     *  Check the big comseg values.
     */
    sql32_lock_comseg ( cip , "sql33_connect: 0x%08lx \n" );
    if ( comseg->cs_server_state != commErrOk_esp01 )
    {
    	en42FillErrText(pErrText,
                        "server rejected connection server state %d",
                        comseg->cs_server_state );
	    MSGD (( -11987, ERR_TYPE, "CONNECT ", "server state %d \n",
				        comseg->cs_server_state ))
	    rc = comseg->cs_server_state ;
    }
    else if (    (comseg->cs_client_pid  != cip->ci_my_pid)
              || (comseg->cs_client_ref  != cip->ci_my_ref)
              || (comseg->cs_packet_cnt  != cip->ci_packet_cnt)
	      || (comseg->cs_packet_size != cip->ci_packet_size)  )
    {
    	en42FillErrText(pErrText,
                        "server rejected connection pid/ref/cnt/size mismatch" );
	    MSGD (( -11987, ERR_TYPE, "CONNECT ", "wrong packet values: \n" ))
	    MSGD (( -11987, ERR_TYPE, "CONNECT ", "  pid %ld ref %d cnt %d siz %ld \n",
			    (long) comseg->cs_client_pid , comseg->cs_client_ref ,
			    comseg->cs_packet_cnt , comseg->cs_packet_size ))
	    MSGD (( -11987, ERR_TYPE, "CONNECT ", "  wanted: pid %ld ref %d cnt %d siz %ld \n",
			    (long) cip->ci_my_pid , cip->ci_my_ref ,
			    cip->ci_packet_cnt , cip->ci_packet_size ))
	    rc = commErrNotOk_esp01 ;
    }
    if ( rc != commErrOk_esp01 )
    {
	    sql32_unlock_comseg ( cip );
	    sql33_detach_big_comseg ( cip , conn_info, count );
	    sql33_remove_sem ( cip );
	    cip->ci_packet_cnt = savpktcnt ;
	    return ( rc );
    }

    /*
     *  update connection info
     */
    cip->ci_peer_pid   = comseg->cs_server_pid ;
    cip->ci_peer_ref   = comseg->cs_server_ref ;
    cip->ci_peer_semid = comseg->cs_server_semid ;
    DBG1 (( MF__,"peer ref   %ld \n", (long) comseg->cs_server_ref ))
    DBG1 (( MF__,"peer semid %d \n", comseg->cs_server_semid ))

    /*
     *  initialize shared memory
     */
    comseg->cs_client_state = commErrOk_esp01 ;
    comseg->cs_client_semid = cip->ci_my_semid ;
    comseg->cs_client_flag  = 0 ;
    comseg->cs_server_flag  = 2 ;
    sql32_unlock_comseg ( cip );

    DBG1 (( MF__,"my_pid    %ld \n", (long) comseg->cs_client_pid ))
    DBG1 (( MF__,"peer_pid  %ld \n", (long) comseg->cs_server_pid ))
    DBG1 (( MF__,"my_ref    %d \n", comseg->cs_client_ref ))
    DBG1 (( MF__,"peer_ref  %d \n", comseg->cs_server_ref ))
    DBG1 (( MF__,"cs_shmid  %d \n", comseg->cs_shmid      ))

    /*
     *  Allocate a packet buffer for the application.
     *  Restore the original packet count.
     *  Use ci_compack to point into the comseg,
     *  while ci_packet is used to point into the local buffer.
     *  Add 8 bytes for alignment.
     */
    cip->ci_packet_cnt = savpktcnt ;
    cip->ci_compack    = cip->ci_packet[0];
    siz = cip->ci_packet_cnt * cip->ci_packet_size ;
    if ( ALLOC_MEM_EO57( (void **)&ptr, siz + 8 ) != NO_ERROR_EO001 )
    {
	    sql32_lock_comseg ( cip , "sql33_connect: 0x%08lx \n" );
	    if ( (comseg->cs_client_pid == cip->ci_my_pid) &&
	         (comseg->cs_client_ref == cip->ci_my_ref) )
	    {
		    union semun     arg ;
	        DBG1 (( MF__,"free shm \n" ))
	        comseg->cs_client_state = commErrNotOk_esp01 ;
            RTESys_WriteMemoryBarrier();
	        comseg->cs_client_flag  = 1 ;
		    arg.val = 1 ;
		    RTE_save_semctl ( comseg->cs_server_semid, 0 , SETVAL , SEMCTL_SETVAL(arg) );
	    }
	    sql32_unlock_comseg ( cip );
	    rc= commErrNotOk_esp01 ;
    }
    else
    {
	    cip->ci_packet_buffer = ptr ;
	    off = (long) ptr & 7 ;
	    if ( off )
	    {
	        ptr += 8 - off ;
	    }
	    siz = cip->ci_packet_size ;
	    for ( idx = 0 ; idx < cip->ci_packet_cnt ; idx ++ )
	    {
	        cip->ci_packet[idx] = (rte_header*) ptr ;
	        ptr += siz ;
	    }
    }

    DBG1 (( MF__,"returning %d \n", rc ))
    return ( rc );
}

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

/*ARGSUSED*/	/* pErrText unused */
int     sql33_release ( 
connection_info		*cip ,
tsp00_ErrTextc VAR_ARRAY_REF pErrText,
connection_info		conn_info [ ],
int                 count)
{
#undef	MF__
#define	MF__	"sql33_release"
    comseg_header		*comseg ;


    DBGIN;
    comseg = cip->ci_comseg ;

    /*
     *  In case the session is not completed, we simulate a request with
     *  SP1CE_RELEASED, which will terminate the session
     *  if the UKP is in VRECEIVE.
     *  This MUST NOT be done, if the comseg has been dedicated to another
     *  session meanwhile (e.g. because of a command timeout).
     */
    if ( comseg && (cip->ci_shmid > 0) )
    {
	    sql32_lock_comseg ( cip , "sql33_release: 0x%08lx \n" );
	    if ( (comseg->cs_client_pid == cip->ci_my_pid) &&
	         (comseg->cs_client_ref == cip->ci_my_ref) )
	    {
		    union semun     arg ;
	        DBG1 (( MF__,"free shm \n" ))
	        comseg->cs_client_state = SP1CE_RELEASED ;
            RTESys_WriteMemoryBarrier();
	        comseg->cs_client_flag  = 1 ;
		    arg.val = 1 ;
		    RTE_save_semctl ( comseg->cs_server_semid, 0 , SETVAL , SEMCTL_SETVAL(arg) );
	    }
	    sql32_unlock_comseg ( cip );
    }

    if ( cip->ci_protocol == PROT_BIGSHM_EO003 )
    {
	    sql33_detach_big_comseg ( cip , conn_info, count );
	    cip->ci_shmid = 0 ;
    }
    else
    {
	    sql33_detach_shm ( cip );
	    sql33_remove_shm ( cip );
    }
    sql33_remove_sem ( cip );

    FREE_MEM_EO57( cip->ci_packet_buffer );
    cip->ci_packet_buffer = 0 ;

    DBG1 (( MF__,"returning %d \n", commErrOk_esp01 ))
    return ( commErrOk_esp01 );
}

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

int     sql33_request ( 
connection_info		*cip ,
tsp00_ErrTextc VAR_ARRAY_REF pErrText )
{
#undef	MF__
#define	MF__	"sql33_request"
    int				rc ;
    comseg_header		*comseg ;


    DBGIN;
    comseg = cip->ci_comseg ;

    /*
     *  Set a lock on the comseg.
     */
    sql32_lock_comseg ( cip , "sql33_request: 0x%08lx \n" );
    DBG1 (( MF__,"client-pid %ld ref %d state %d \n",
			(long) comseg->cs_client_pid , comseg->cs_client_ref ,
			comseg->cs_client_state ))
    DBG1 (( MF__,"client-flag %d semid %d \n",
			comseg->cs_client_flag , comseg->cs_client_semid ))
    DBG1 (( MF__,"server-pid %ld ref %d state %d \n",
			(long) comseg->cs_server_pid , comseg->cs_server_ref ,
			comseg->cs_server_state ))
    DBG1 (( MF__,"server-flag %d semid %d \n",
			comseg->cs_server_flag , comseg->cs_server_semid ))

    if ( (comseg->cs_client_pid != cip->ci_my_pid)
	  || (comseg->cs_client_ref != cip->ci_my_ref) )
    {
	    /*
	     *  Kernel timed out and dedicated the User-Task to
	     *  another application. We should try a reconnect.
	     */
	    sql32_unlock_comseg ( cip );
	    en42FillErrText(pErrText,
                        "command timeout: pid %d/%d ref %d/%d",
                        comseg->cs_client_pid,
                        cip->ci_my_pid,
                        comseg->cs_client_ref,
                        cip->ci_my_ref ) ;
	    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "session re-used, command timeout? \n" ));
	    return ( SP1CE_TIMEOUT );
    }

    /*
     *  If there were previous errors, refuse the request
     */
    if ( comseg->cs_server_state != commErrOk_esp01 )
    {
	    rc = comseg->cs_server_state;
	    sql32_unlock_comseg ( cip );
        if ( rc == SP1CE_SHUTDOWN )
        {
    	    en42FillErrText(pErrText,
                            "connection broken by SHUTDOWN" );
        } else if ( rc == SP1CE_TIMEOUT )
        {
    	    en42FillErrText(pErrText,
                            "connection broken by TIMEOUT" );
        }
	    else
	    {
	        switch ( rc )
	        {
	        case SP1CE_RELEASED :
    	        en42FillErrText(pErrText,
                                "connection broken by kernel release" );
		        MSGD (( -11987, ERR_TYPE, "COMMUNIC", "kernel released connection! \n" ))
		        break ;
	        case SP1CE_CRASH :
    	        en42FillErrText(pErrText,
                                "connection broken by kernel CRASH" );
    		    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "kernel aborted connection! \n" ))
    		    break ;
	        default :
    	        en42FillErrText(pErrText,
                                "connection broken by server state %d", rc );
    		    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "kernel broke connection! \n" ))
	    	    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "   (server-state %d) \n", rc ))
                break;
	        }
	    }
	    return ( rc );
    }

    if (    (comseg->cs_server_pid   != cip->ci_peer_pid)
	 || (comseg->cs_server_ref   != cip->ci_peer_ref))
    {
    	en42FillErrText(pErrText,
                        "connection broken by pid,ref or semid mismatch");
	    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "kernel broke connection! \n" ))
	    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "   (server-pid %5ld ref %3d sem %5d \n",
	        (long) comseg->cs_server_pid , comseg->cs_server_ref ,
	        comseg->cs_server_semid ))
	    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "   remembered %5ld     %3d     %5d) \n",
	        (long) cip->ci_peer_pid , cip->ci_peer_ref , cip->ci_peer_semid ))
	    sql32_unlock_comseg ( cip );
	    return ( commErrNotOk_esp01 );
    }

    /*
     *  We have to observe a strictly alternating communication
     */
    if ( (comseg->cs_client_flag != 0) || (comseg->cs_server_flag != 2) )
    {
	    sql32_unlock_comseg ( cip );
    	en42FillErrText(pErrText,
                        "unbalanced request/reply %d/%d",
                        comseg->cs_client_flag,
                        comseg->cs_server_flag );
	    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "unbalanced request/reply \n" ))
	    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "    cliflg,srvflg %d,%d \n", 
		         comseg->cs_client_flag , comseg->cs_server_flag ))
	    return ( commErrNotOk_esp01 );
    }

    /*
     *  Now, we can access the comseg.
     */
    DBG1 (( MF__,"comseg 0x%08lx cmpack 0x%08lx \n",
	    (long) comseg , (long) cip->ci_compack ))
    DBG1 (( MF__,"shmreq 0x%08lx shmrpl 0x%08lx \n",
	    (long) cip->ci_compack , (long) (cip->ci_compack + 1)
					    + cip->ci_request_lgt ))
    DBG1 (( MF__,"reques 0x%08lx reply  0x%08lx \n",
	    (long) cip->ci_request , (long) cip->ci_reply ))
    DBG1 (( MF__,"req_lgt %ld send_len %d \n",
	    cip->ci_request_lgt , cip->ci_request->rh_max_send_len ))
    memcpy ( cip->ci_compack , cip->ci_request ,
	   RTE_HEADER_SIZE_EO003 + cip->ci_request_lgt );
    /*
     *  Flag the comseg as 'filled in by application'.
     */
    RTESys_WriteMemoryBarrier();
    comseg->cs_client_flag = 1 ;
    /*
     *  If connected via big-comseg, set the common flag.
     */
    if ( cip->ci_big_comseg ) cip->ci_big_comseg->bc_common_flag = 1 ;

    /* get new semid */
    cip->ci_peer_semid = comseg->cs_server_semid;

    /*
     *  Release the lock on the comseg.
     */
    sql32_unlock_comseg ( cip );

    /*
     *  Wake the remote kernel process
     */
    if ( cip->ci_big_comseg && ! cip->ci_big_comseg->bc_kp_running )
    {
	    union semun     arg ;
	    arg.val = 1 ;
	    DBG1 (( MF__,"semctl semid  %d \n", cip->ci_peer_semid ))
	    rc = RTE_save_semctl ( cip->ci_peer_semid , 0 , SETVAL , SEMCTL_SETVAL(arg) );
    }
    if ( rc == UNDEF )
    {
	    DBG1 (( MF__,"semctl (setval %d) error: %s \n", cip->ci_peer_semid , sqlerrs() ))
	    /*
	     *  If the kernel is too busy to check it's mail, ignore it.
	     */
	    if ( errno != ERANGE )
	    {
	        en42FillErrText(pErrText, "connection broken:semctl (%d:%s)", errno, sqlerrs() ) ;
	        MSGD (( -11987, ERR_TYPE, "COMMUNIC", "semctl (setval %d) error: %s \n",
					        cip->ci_peer_semid , sqlerrs() ))
	        return ( commErrNotOk_esp01 );
	    }
    }

    DBG1 (( MF__,"returning %d \n", commErrOk_esp01 ))
    return ( commErrOk_esp01 );
}

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

int     sql33_replyavailable ( 
connection_info *cip ,
tsp00_ErrTextc   pErrText )
{
#undef	MF__
#define	MF__	"sql33_replyavailable"
    int				rc ;
    rte_header			*header ;
    comseg_header		*comseg ;
    struct sembuf		semrcv ;


    DBGIN;
    comseg = cip->ci_comseg ;

    /*
     *  We don't lock the comseg here.
     */
    DBG1 (( MF__,"client-pid %ld ref %d state %d \n",
			(long) comseg->cs_client_pid , comseg->cs_client_ref ,
			comseg->cs_client_state ))
    DBG1 (( MF__,"client-flag %d semid %d \n",
			comseg->cs_client_flag , comseg->cs_client_semid ))
    DBG1 (( MF__,"server-pid %ld ref %d state %d \n",
			(long) comseg->cs_server_pid , comseg->cs_server_ref ,
			comseg->cs_server_state ))
    DBG1 (( MF__,"server-flag %d semid %d \n",
			comseg->cs_server_flag , comseg->cs_server_semid ))

    if (    (comseg->cs_client_pid   != cip->ci_my_pid)
	 || (comseg->cs_client_ref   != cip->ci_my_ref)
         || (comseg->cs_server_pid   != cip->ci_peer_pid )
	 || (comseg->cs_server_ref   != cip->ci_peer_ref )
	 || (comseg->cs_server_state != commErrOk_esp01)
	 || (comseg->cs_server_flag  == 1)
       )
    {
        return ( commErrOk_esp01 );
    }

    en42FillErrText(pErrText, "no reply available" );
    DBG1 (( MF__,"returning %d \n", SP1CE_START_REQUIRED ))
    return ( SP1CE_WOULDBLOCK );
}

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

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

int     en33CheckedReceive ( 
int (*checkCallback)(void *arg),
void *arg,
connection_info *cip ,
tsp00_ErrTextc   pErrText )
{
#undef	MF__
#define	MF__	"en33CheckedReceive"
    int				rc ;
    rte_header			*header ;
    comseg_header		*comseg ;
    struct sembuf		semrcv ;

    DBGIN;

    /*
     *  wait on own semaphore until received
     */
restart_after_interrupt:
    {
        struct sembuf ownrcv;
        ownrcv.sem_num = 0;
        ownrcv.sem_op = -1;
        ownrcv.sem_flg = 0;
        DBG1 (( MF__,"wait  semid  %d \n", cip->ci_my_semid ))
        rc = semop ( cip->ci_my_semid , &ownrcv , 1 );
    }
    DBG1 (( MF__,"awoke semid  %d rc %d \n", cip->ci_my_semid , rc ))
    if ( (rc == UNDEF) && (errno != EIDRM) && (errno != EINVAL) )
    {
	    if ( errno == EINTR )
	    {
            if ( (0 != checkCallback) && (0 != (*checkCallback)(arg)) )
            {
     	        MSGD (( -11987, ERR_TYPE, "COMMUNIC", "semop (receive %d) interrupted and check reports error\n",
						    cip->ci_my_semid ))
	            en42FillErrText(pErrText, "connection broken check reports error" );
	            return ( commErrNotOk_esp01 );
            }
	        goto restart_after_interrupt ;
	    }

        en42FillErrText(pErrText, "connection broken semop (%d:%s)", errno, sqlerrs() );
	    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "checked receive sem %d : %s \n",
						cip->ci_my_semid , &pErrText[0] ))
	    return ( commErrNotOk_esp01 );
    }

    comseg = cip->ci_comseg ;

    sql32_lock_comseg ( cip , "sql33_receive: 0x%08lx \n" );

    DBG1 (( MF__,"client-pid %ld ref %d state %d \n",
			(long) comseg->cs_client_pid , comseg->cs_client_ref ,
			comseg->cs_client_state ))
    DBG1 (( MF__,"client-flag %d semid %d \n",
			comseg->cs_client_flag , comseg->cs_client_semid ))
    DBG1 (( MF__,"server-pid %ld ref %d state %d \n",
			(long) comseg->cs_server_pid , comseg->cs_server_ref ,
			comseg->cs_server_state ))
    DBG1 (( MF__,"server-flag %d semid %d \n",
			comseg->cs_server_flag , comseg->cs_server_semid ))

    /*
     *  BIG_COMSEG: the comseg might be given to a new session before
     *  the application was scheduled by UNIX.
     *  In this case, cs_client_pid and/or cs_client_ref were changed.
     */
    if (    (comseg->cs_client_pid != cip->ci_my_pid)
	 || (comseg->cs_client_ref != cip->ci_my_ref) )
    {
    	sql32_unlock_comseg ( cip );
    	en42FillErrText(pErrText,
                        "command timeout" );
    	MSGD (( -11987, ERR_TYPE, "COMMUNIC", "session re-used, command timeout? \n" ))
	    return ( SP1CE_TIMEOUT );
    }

    /*
     *  If the kernel releases (either asynchronously via Command Timeout
     *  or Console Kill or synchronously via Commit/Rollback Release command,
     *  it clears cs_server_pid and cs_server_ref,
     *  updates cs_server_flag and sets the semaphore.
     *  If sql33_receive awakes and cs_server_pid, cs_server_ref
     *  and cs_server_flag are ok, deliver the last reply.
     *  A later sqlrequest (if any) will then find the connection broken.
     */
    if ( (comseg->cs_server_pid   == 0)
	  && (comseg->cs_server_ref   == 0)
	  && (comseg->cs_server_state == commErrOk_esp01)
	  && (comseg->cs_server_flag  == 1)
       )
    {
	    /*
	     *  It must be a reply fo a release command. Deliver it.
	     */
	    DBG1 (( MF__,"assuming reply for release command \n" ))
    }
    else
    {
	    if ( comseg->cs_server_state != commErrOk_esp01 )
	    {
	        rc = comseg->cs_server_state ;
	        sql32_unlock_comseg ( cip );
	        en42FillErrText( pErrText,
                             "connection broken server state %d",
                             comseg->cs_server_state);
	        if ( (rc != SP1CE_SHUTDOWN)
		      && (rc != SP1CE_TIMEOUT) )
	        {
		        switch ( rc )
		        {
		        case SP1CE_RELEASED :
		            MSGD (( -11987, ERR_TYPE, "COMMUNIC", "kernel released connection! \n" ))
		            break ;
		        case SP1CE_CRASH :
		            MSGD (( -11987, ERR_TYPE, "COMMUNIC", "kernel aborted connection! \n" ))
		            break ;
		        default :
		            MSGD (( -11987, ERR_TYPE, "COMMUNIC", "kernel broke connection! \n" ))
		            MSGD (( -11987, ERR_TYPE, "COMMUNIC", " (server-state %d) \n", rc ))
		        }
	        }
	        return ( rc );
	    }

        if (    (comseg->cs_server_pid   != cip->ci_peer_pid)
	         || (comseg->cs_server_ref   != cip->ci_peer_ref) )
	    {
	        en42FillErrText(pErrText, "connection broken pid or ref differ");
	        MSGD (( -11987, ERR_TYPE, "COMMUNIC", "kernel broke connection! \n" ))
	        MSGD (( -11987, ERR_TYPE, "COMMUNIC", "  (server-pid %5ld ref %3d \n",
		        (long) comseg->cs_server_pid , comseg->cs_server_ref ))
	        MSGD (( -11987, ERR_TYPE, "COMMUNIC", "   remembered %5ld     %3d) \n",
		        (long) cip->ci_peer_pid , cip->ci_peer_ref ))
	        sql32_unlock_comseg ( cip );
	        return ( commErrNotOk_esp01 );
	    }

        if ( rc == UNDEF )
	    {
	        en42FillErrText(pErrText, "connection broken semid %d disappeared", cip->ci_my_semid );
	        MSGD (( -11987, ERR_TYPE, "COMMUNIC", "semid %d disappeared! \n",
						        cip->ci_my_semid ))
	        sql32_unlock_comseg ( cip );
	        return ( commErrNotOk_esp01 );
	    }

        if ( comseg->cs_server_flag != 1 )
	    {
	        sql32_unlock_comseg ( cip );
	        MSGD (( -11987, ERR_TYPE, "COMMUNIC", "awoke, but no message found \n" ))
	        goto restart_after_interrupt ;
	    }
	    /*
	     *  Everything is ok with the connection.
	     */
    }

    if (cip->ci_request_lgt & 7)
    {
        cip->ci_request_lgt += 8 - (cip->ci_request_lgt & 7);
    }

    header = (rte_header*) ((char*) (cip->ci_compack + 1)
				    + cip->ci_request_lgt);
    DBG1 (( MF__,"comseg 0x%08lx cmpack 0x%08lx \n",
	    (long) comseg , (long) cip->ci_compack ))
    DBG1 (( MF__,"shmreq 0x%08lx shmrpl 0x%08lx \n",
	    (long) cip->ci_compack , (long) header ))
    DBG1 (( MF__,"reques 0x%08lx reply  0x%08lx \n",
	    (long) cip->ci_request , (long) cip->ci_reply ))
    DBG1 (( MF__,"rpl_siz %ld recv_len %d \n",
	    cip->ci_reply_size , header->rh_max_send_len ))

    if (    (header->rh_max_send_len < RTE_HEADER_SIZE_EO003)
	 || (header->rh_max_send_len > cip->ci_reply_size + RTE_HEADER_SIZE_EO003) )
    {
	    sql32_unlock_comseg ( cip );
	    en42FillErrText(pErrText, "protocol error: header length %d", header->rh_max_send_len);
	    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "illegal packet size %d max %ld \n",
	        header->rh_max_send_len - RTE_HEADER_SIZE_EO003 , cip->ci_reply_size ))
	    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "  pktsiz %ld datsiz %ld reqlen %ld \n",
	        cip->ci_packet_size , cip->ci_max_data_size , cip->ci_request_lgt ))
	    return ( commErrNotOk_esp01 );
    }
    memcpy ( cip->ci_reply , header , header->rh_max_send_len );

    /*
     *  cs_client_flag and cs_server_flag represent four states
     *  of the communication. See ven00cc for a picture of these.
     *  Setting the flags here indicates the last state
     *  transition and shows that we got the packet.
     */
    comseg->cs_client_flag = 0 ;
    comseg->cs_server_flag = 2 ;
    sql32_unlock_comseg ( cip );

    DBG1 (( MF__,"returning %d \n", commErrOk_esp01 ))
    return ( commErrOk_esp01 );
}

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

int     sql33_receive ( 
connection_info *cip ,
tsp00_ErrTextc   pErrText )
{
#undef	MF__
#define	MF__	"sql33_receive"
    int				rc ;
    struct sembuf		semrcv ;

    DBGPAS;
    return en33CheckedReceive(0, 0, cip, pErrText);
}

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

int     sql33_cancel ( 
connection_info *cip ,
tsp00_ErrTextc   pErrText )
{
#undef	MF__
#define	MF__	"sql33_cancel"
    int				rc ;
    int				kernel_fd ;
    uid_t			uid ;
    rte_header			*header ;
    char			packet [ RTE_CONPKT_SIZE ];
    tsp00_DbNamec   peer_dbname;  
    int             idx;


    DBGIN;

    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "cancel local session %d, knlref %d \n",
			cip->ci_my_ref , cip->ci_peer_ref ))


    strcpy (peer_dbname, cip->ci_peer_dbname);

    rc = sql32_open_kernel_fifo (peer_dbname , &kernel_fd ,
                                  &uid , pErrText);
    if ( rc != commErrOk_esp01 )
    {
        for (idx = 0; cip->ci_peer_dbname[idx] != 0; ++idx)
        {
            if (islower (cip->ci_peer_dbname[idx]))
            {
                peer_dbname[idx] = toupper (cip->ci_peer_dbname[idx]);
            }
        }

        rc = sql32_open_kernel_fifo ( peer_dbname , &kernel_fd ,
                                      &uid , pErrText );
        if ( rc != commErrOk_esp01 )
        {
	        DBG1 (( MF__,"cannot open knl fifo: %s\n", pErrText ))
	        return ( rc );
        }
    }

    header = (rte_header*) packet ;
    sql42_create_conpkt ( header , RSQL_USER_CANCEL_REQUEST_EO003 ,
			    cip->ci_my_ref , cip->ci_peer_ref ,
			    commErrOk_esp01 , cip->ci_service ,
			    cip->ci_max_segment_size ,
			    cip->ci_max_data_size ,
			    cip->ci_packet_size ,
			    cip->ci_min_reply_size ,
			    "" , cip->ci_peer_dbname );

    rc = sql42_send_conpkt ( kernel_fd , header , pErrText );
    if ( rc != commErrOk_esp01 )
    {
	DBG1 (( MF__,"cannot write to kernel fifo: %s \n", pErrText ))
	(void) close ( kernel_fd );
	return ( rc );
    }
    (void) close ( kernel_fd );

    DBG1 (( MF__,"returning %d \n", commErrOk_esp01 ))
    return ( commErrOk_esp01 );
}

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

int     sql33_dump   ( 
connection_info *cip ,
tsp00_ErrTextc   pErrText )
{
#undef	MF__
#define	MF__	"sql33_dump"
    int				rc ;
    int				kernel_fd ;
    uid_t			uid ;
    rte_header			*header ;
    char			packet [ RTE_CONPKT_SIZE ];
    tsp00_DbNamec   peer_dbname;  
    int             idx;


    DBGIN;

    MSGD (( -11987, ERR_TYPE, "COMMUNIC", "dumping local server '%s' \n", cip->ci_peer_dbname ))

    strcpy (peer_dbname, cip->ci_peer_dbname);

    rc = sql32_open_kernel_fifo (peer_dbname , &kernel_fd ,
                                  &uid , pErrText);
    if ( rc != commErrOk_esp01 )
    {
        for (idx = 0; cip->ci_peer_dbname[idx] != 0; ++idx)
        {
            if (islower (cip->ci_peer_dbname[idx]))
            {
                peer_dbname[idx] = toupper (cip->ci_peer_dbname[idx]);
            }
        }

        rc = sql32_open_kernel_fifo ( peer_dbname , &kernel_fd ,
                                      &uid , pErrText );
        if ( rc != commErrOk_esp01 )
        {
	        DBG1 (( MF__,"cannot open knl fifo: %s\n", pErrText ))
	        return ( rc );
        }
    }

    header = (rte_header*) packet ;
    sql42_create_conpkt ( header , RSQL_DUMP_REQUEST_EO003 ,
			    cip->ci_my_ref , cip->ci_peer_ref ,
			    commErrOk_esp01 , cip->ci_service ,
			    cip->ci_max_segment_size ,
			    cip->ci_max_data_size ,
			    cip->ci_packet_size ,
			    cip->ci_min_reply_size ,
			    "" , cip->ci_peer_dbname );

    rc = sql42_send_conpkt ( kernel_fd , header , pErrText );
    if ( rc != commErrOk_esp01 )
    {
	DBG1 (( MF__,"cannot write to kernel fifo: %s \n", pErrText ))
	(void) close ( kernel_fd );
	return ( rc );
    }
    (void) close ( kernel_fd );

    DBG1 (( MF__,"returning %d \n", commErrOk_esp01 ))
    return ( commErrOk_esp01 );
}

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

/*ARGSUSED*/	/* pErrText unused */

int     sql33_clear ( 
connection_info		*cip ,
tsp00_ErrTextc      pErrText ,
connection_info		conn_info [ ],
int                 count)
{
#undef	MF__
#define	MF__	"sql33_clear"

    DBGIN;

    if ( cip->ci_protocol == PROT_BIGSHM_EO003 )
    {
	sql33_detach_big_comseg ( cip , conn_info, count );
	cip->ci_shmid = 0 ;
    }
    else
    {
	sql33_detach_shm ( cip );
    }

    FREE_MEM_EO57( cip->ci_packet_buffer );
    cip->ci_packet_buffer = 0 ;

    DBG1 (( MF__,"returning %d \n", commErrOk_esp01 ))
    return ( commErrOk_esp01 );
}

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

void    sql33_cleanup ( 
connection_info		*cip )
{
#undef	MF__
#define	MF__	"sql33_cleanup"

    sql33_detach_shm ( cip );
    sql33_remove_shm ( cip );
    sql33_remove_sem ( cip );
}

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

static  void    sql33_detach_shm ( 
connection_info		*cip )
{
#undef	MF__
#define	MF__	"sql33_detach_shm"

    if ( cip->ci_protocol == PROT_SHM_EO003 )
    {
	DBG1 (( MF__,"detach shmaddr 0x%08lx \n",
				    (long) cip->ci_comseg ))
	(void) sql41_detach_shm ( (char**) &cip->ci_comseg );
    }
}

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

static  void    sql33_remove_shm ( 
connection_info		*cip )
{
#undef	MF__
#define	MF__	"sql33_remove_shm"

    if ( cip->ci_protocol == PROT_SHM_EO003 )
    {
		SAPDB_UInt4		idx;
 		tsp00_DbNamec   peer_dbname;  
 
 		DBG1 (( MF__,"remove shmid %d\n", cip->ci_shmid ))
 
 		strcpy (peer_dbname, cip->ci_peer_dbname);
 
 		for (idx = 0; cip->ci_peer_dbname[idx] != 0; ++idx)
 		{
 			if (islower (cip->ci_peer_dbname[idx]))
 			{
 				peer_dbname[idx] = toupper (cip->ci_peer_dbname[idx]);
 			}
 		}
 
 		(void) sql41_remove_shm ( &cip->ci_shmid , "us" , peer_dbname );
    }
}

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

static  void    sql33_remove_sem ( 
connection_info		*cip )
{
#undef	MF__
#define	MF__	"sql33_remove_sem"

 	tsp00_DbNamec   peer_dbname; 
	SAPDB_UInt4		idx;
 
 	DBG1 (( MF__,"remove semid %d \n", cip->ci_my_semid ))
 	strcpy (peer_dbname, cip->ci_peer_dbname);
 
 	for (idx = 0; cip->ci_peer_dbname[idx] != 0; ++idx)
 	{
 		if (islower (cip->ci_peer_dbname[idx]))
 		{
 			peer_dbname[idx] = toupper (cip->ci_peer_dbname[idx]);
 		}
 	}

    (void) sql41_remove_sem ( &cip->ci_my_semid , "us" , peer_dbname );
}

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

static	int	sql33_attach_big_comseg ( 
connection_info		*cip ,
connection_info		conn_info [ ],
int                 count)
{
#undef	MF__
#define	MF__	"sql33_attach_big"
    int				idx ;
    connection_info		*scip ;


    DBG1 (( MF__,"search shmid %d conn 0x%08lx \n",
			cip->ci_shmid , (long) conn_info ))

    cip->ci_big_comseg = 0 ;
    cip->ci_big_size   = 0 ;
    if ( conn_info )
    {
	for ( idx = 0 ; idx < count ; idx ++ )
	{
	    scip = conn_info + idx ;
	    if (    scip->ci_big_comseg
		 && (scip->ci_shmid == cip->ci_shmid) )
	    {
		DBG1 (( MF__,"found shmaddr 0x%08lx (ref %d) \n",
					(long) scip->ci_big_comseg , idx+1 ))
		cip->ci_big_comseg = scip->ci_big_comseg ;
		cip->ci_big_size   = scip->ci_big_size ;
		break ;
	    }
	}
    }

    idx = sql32_attach_comseg ( cip );
    return ( idx );
}

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

static	void	sql33_detach_big_comseg ( 
connection_info		*cip ,
connection_info		conn_info [ ],
int                 count)
{
#undef	MF__
#define	MF__	"sql33_detach_big"
    int				to_detach ;
    int				idx ;
    connection_info		*scip ;


    DBG1 (( MF__,"called  shmaddr 0x%08lx \n",
		(long) cip->ci_big_comseg ))

    to_detach = TRUE ;
    if ( conn_info )
    {
	for ( idx = 0 ; idx < count ; idx ++ )
	{
	    scip = conn_info + idx ;
	    if ( (scip != cip) &&
		 (scip->ci_shmid == cip->ci_shmid) &&
	         (scip->ci_big_comseg == cip->ci_big_comseg) )
	    {
		DBG1 (( MF__,"reference %d using comseg \n", idx ))
		to_detach = FALSE ;
		break ;
	    }
	}
    }

    if ( to_detach )
    {
        (void) sql41_detach_shm ( (char**) &cip->ci_big_comseg );
	cip->ci_big_size = 0 ;
    }

    DBG1 (( MF__,"leaving shmaddr 0x%08lx \n",
			    (long) cip->ci_big_comseg ))
}
