fis-gtm/sr_unix_cm/omi_srvc_xct.c

491 lines
12 KiB
C

/****************************************************************
* *
* Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
/*
* omi_srvc_xct.c ---
*
* Process a client's transaction.
*
*/
#include "mdef.h"
#include <errno.h>
#include "gtm_stdio.h"
#include "gtm_unistd.h"
#include "gtm_string.h"
#include "gtm_time.h" /* for time() */
#include "gtmio.h"
#include "have_crit.h"
#include "omi.h"
#include "gtcm.h"
#include "error.h"
#ifndef lint
static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_srvc_xct.c,v 1.8 2013/10/23 03:49:32 tuskentower Exp $";
#endif
GBLREF int4 omi_errno;
GBLREF char *omi_pklog;
GBLREF char *omi_oprlist[];
GBLREF char *omi_errlist[];
GBLREF char *omi_pklog_addr;
GBLREF int history;
GBLREF boolean_t servtime_expired;
static omi_op omi_dispatch_table[OMI_OP_MAX] =
{
0,
omi_prc_conn,
omi_prc_stat,
omi_prc_disc,
0, 0, 0, 0, 0, 0,
omi_prc_set,
/* omi_prc_setp*/0,
/* omi_prc_sete*/0,
omi_prc_kill,
/* omi_prc_incr*/0,
0, 0, 0, 0, 0,
omi_prc_get,
omi_prc_def,
omi_prc_ordr,
omi_prc_next,
omi_prc_qry,
omi_prc_rord,
/* omi_prc_rqry*/0,
0, 0, 0,
omi_prc_lock,
omi_prc_unlk,
omi_prc_unlc,
omi_prc_unla
};
int omi_srvc_xact (omi_conn *cptr)
{
extern int4 omi_nxact, omi_nerrs, omi_brecv, omi_bsent, gtcm_stime;
extern int4 gtcm_ltime, omi_nxact2;
omi_vi mlen, xlen;
omi_li nxact;
omi_si hlen;
omi_req_hdr rh;
omi_err_hdr eh;
int4 rv, blen;
int bunches, xblk, i, fatal;
char buff[OMI_BUFSIZ], *bptr, *xend, *bend;
#ifdef BSD_TCP
int cc, save_errno;
/* If true, an error occurred */
cc =(int)(&cptr->buff[cptr->bsiz] - &cptr->bptr[cptr->blen]);
while (!servtime_expired && (cc = (int)(read(cptr->fd, &cptr->bptr[cptr->blen], cc))) < 0 && errno == EINTR)
;
save_errno = errno;
if (servtime_expired)
return -1;
if (cc < 0)
{
if (errno == ETIMEDOUT)
{
OMI_DBG((omi_debug, "%s: connection %d to %s timed out.\n",
SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai)));
}
else if (errno == ECONNRESET)
{
OMI_DBG((omi_debug, "%s: connection %d to %s closed by remote client.\n",
SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai)));
}
else
{
char msg[256];
SPRINTF(msg, "Attempted read from connection %d to %s failed",
cptr->stats.id, gtcm_hname(&cptr->stats.ai));
gtcm_rep_err(msg, save_errno);
}
return -1;
}
/* If true, the connection has closed */
else if (cc == 0)
{
return -1;
}
/* Buffer in use between &cptr->bptr[0] and &cptr->buff[cptr->bsiz] */
cptr->blen += cc;
cptr->stats.bytes_recv += cc;
omi_brecv += cc;
#else /* defined(BSD_TCP) */
#ifdef FILE_TCP
int cc;
cc = (int)(&cptr->buff[cptr->bsiz] - &cptr->bptr[cptr->blen]);
/* If true, an error occurred */
if ((cc = (int)read(cptr->fd, &cptr->bptr[cptr->blen], 4)) <= 0)
{
return -1;
}
cptr->blen += 4;
cptr->xptr = cptr->bptr;
OMI_VI_READ(&mlen, cptr->xptr);
if ((cc = (int)read(cptr->fd, &cptr->bptr[cptr->blen], mlen.value)) <= 0)
{
return -1;
}
cptr->blen += cc;
cptr->stats.bytes_recv += cc + 4;
omi_brecv += cc + 4;
#else /* defined(FILE_TCP) */
return -1;
#endif /* !defined(FILE_TCP) */
#endif /* !defined(BSD_TCP) */
/* If true, we don't have all of the transaction length yet */
if (cptr->blen < OMI_VI_SIZ)
{
/* If true, push the piece we have to the beginning of the buffer */
if (cptr->bptr != cptr->buff)
{
memmove(cptr->buff, cptr->bptr, cptr->blen);
cptr->bptr = cptr->buff;
}
return 0;
}
/* Place the transaction pointer so we can move through the data */
cptr->xptr = cptr->bptr;
OMI_VI_READ(&mlen, cptr->xptr);
if (mlen.value + 4 > OMI_BUFSIZ)
{
char msg[256];
SPRINTF(msg, "OMI packet length (%d) larger than max (%d)", mlen.value+4, OMI_BUFSIZ);
gtcm_cpktdmp((char *)cptr->bptr, cptr->blen, msg);
return -1;
}
/* If true, we don't have the full transaction yet */
if (cptr->blen < mlen.value + 4)
{
/* If true, push the piece we have to the beginning of the buffer */
if (cptr->bptr != cptr->buff)
{
memmove(cptr->buff, cptr->bptr, cptr->blen);
cptr->bptr = cptr->buff;
}
return 0;
}
/* We have the whole transaction in the buffer, decompose it. */
if (history)
{
init_omi_hist(cptr->stats.id);
save_omi_req(cptr->bptr, cptr->blen);
}
#ifdef DEBUG
/*
* if (omi_pklog && !INV_FD_P(cptr->pklog))
* if (!omi_pklog_addr || (!strcmp(omi_pklog_addr, strchr(cptr->stats.addr, '@')+1)))
* omi_dump_pkt(cptr);
*/
#endif /* defined(DEBUG) */
/* This is set to indicate a fatal error in a bunch */
fatal = 0;
/* This is set to indicate we processed an xblk */
xblk = 0;
/* If true, we need to worry about bunches */
if ((bunches = (cptr->exts & OMI_XTF_BUNCH)))
{
OMI_LI_READ(&nxact, cptr->xptr);
bptr = buff + OMI_VI_SIZ + OMI_LI_SIZ;
if (nxact.value * (OMI_RH_SIZ + 1) > mlen.value) /* || nxact.value < 0 */ /* is commented as it is always FALSE */
{
char msg[256];
SPRINTF(msg, "invalid OMI packet (invalid nxact)");
gtcm_cpktdmp((char *)cptr->bptr, cptr->blen, msg);
return -1;
}
}
else
{
nxact.value = 1;
bptr = buff;
xlen = mlen;
}
/* This is the end of the response buffer (for the *_prc_*() routines) */
bend = ARRAYTOP(buff);
/* Loop through the transaction(s) */
for (i = nxact.value; i > 0; i--)
{
if (bunches)
OMI_VI_READ(&xlen, cptr->xptr);
/* This pointer marks the end of this transaction */
xend = cptr->xptr + xlen.value;
/* Check the size of the operation-independent header */
OMI_SI_READ(&hlen, cptr->xptr);
/* Operation class and type */
OMI_LI_READ(&rh.op_class, cptr->xptr);
OMI_SI_READ(&rh.op_type, cptr->xptr);
/* User and Group */
OMI_LI_READ(&rh.user, cptr->xptr);
OMI_LI_READ(&rh.group, cptr->xptr);
/* Sequence number */
OMI_LI_READ(&rh.seq, cptr->xptr);
/* Reference ID */
OMI_LI_READ(&rh.ref, cptr->xptr);
/* Initialize in case of an error */
eh.type = 0;
/* Sanity check the transaction */
if (xlen.value > mlen.value || hlen.value != OMI_RH_SIZ)
{
eh.type = OMI_ER_PR_INVMSGFMT;
fatal = -1;
}
else if (cptr->state == OMI_ST_DISC && rh.op_type.value != OMI_CONNECT)
{
char msg[256];
SPRINTF(msg, "Request (%x) sent before session was established",
rh.op_type.value);
eh.type = OMI_ER_SE_NOSESS;
}
else if (cptr->state == OMI_ST_CONN && rh.op_type.value == OMI_CONNECT)
{
eh.type = OMI_ER_SE_CONNREQ;
fatal = 1;
}
else if (rh.op_class.value != 1)
{
if (!(cptr->exts & OMI_XTF_RC && rh.op_class.value == 2))
{
eh.type = OMI_ER_PR_INVMSGFMT;
fatal = -1;
}
}
else if (rh.op_type.value >= OMI_OP_MAX)
{
cptr->stats.xact[0]++;
eh.type = OMI_ER_PR_INVOPTYPE;
}
else if (!omi_dispatch_table[rh.op_type.value])
{
cptr->stats.xact[rh.op_type.value]++;
eh.type = OMI_ER_PR_INVOPTYPE;
}
/* Report any errors */
if (eh.type != OMI_ER_NO_ERROR || fatal)
{
if (eh.type == OMI_ER_NO_ERROR)
eh.type = OMI_ER_PR_INVMSGFMT;
eh.class = 1;
eh.modifier = 0;
omi_buff_rsp(&rh, &eh, 0, bptr, 0);
bptr += OMI_HDR_SIZ;
cptr->xptr = xend;
cptr->stats.errs[eh.type]++;
omi_nerrs++;
OMI_DBG((omi_debug, "gtcm_server: %6d: Error (PD): %s\n",
cptr->stats.id, omi_errlist[eh.type]));
if (fatal < 0)
break;
continue;
}
/* start counting server up time with the first transaction */
if (!omi_nxact)
gtcm_stime = (int4)time(0);
/* If true, this is an RC request; service it in the RC code */
if (cptr->exts & OMI_XTF_RC && rh.op_class.value == 2)
{
#ifdef GTCM_RC
omi_nxact++;
omi_nxact2++;
if ((rv = rc_srvc_xact(cptr, xend)) >= 0)
{
xblk = 1;
blen = rv + OMI_HDR_SIZ;
bptr = cptr->bptr;
bend = &cptr->buff[cptr->bsiz];
}
#else /* defined(RC) */
fatal = 1;
rv = -OMI_ER_PR_INVMSGFMT;
#endif /* !defined(GTCM_RC) */
}
/* Otherwise, deal with the OMI/EMI request */
else
{
/* Update the stats, do the operation */
cptr->stats.xact[rh.op_type.value]++;
omi_nxact++;
omi_nxact2++;
/* OMI_DBG((omi_debug, "gtcm_server: %6d: %s\n", cptr->stats.id,
* omi_oprlist[rh.op_type.value]));*/
omi_errno = OMI_ER_NO_ERROR;
/* Service the transaction(s) */
rv = (*omi_dispatch_table[rh.op_type.value])(cptr, xend, bptr + OMI_HDR_SIZ, bend);
/* If true (or true if) an exception is raised */
if (omi_errno != OMI_ER_NO_ERROR)
rv = -omi_errno;
}
/* If true, an error occurred servicing this transaction */
if (rv < 0)
{
eh.class = 1;
eh.type = -rv;
eh.modifier = 0;
omi_buff_rsp(&rh, &eh, 0, bptr, 0);
bptr += OMI_HDR_SIZ;
cptr->xptr = xend;
cptr->stats.errs[eh.type]++;
omi_nerrs++;
OMI_DBG((omi_debug, "gtcm_server: %6d: Error (AD): %s\n",
cptr->stats.id, omi_errlist[eh.type]));
omi_dump_pkt(cptr);
}
else
{
if (cptr->xptr != xend)
{
/* Only report this if we're not doing RC */
if (!(cptr->exts & OMI_XTF_RC && rh.op_class.value == 2))
NON_IA64_ONLY(OMI_DBG((omi_debug, "gtcm_server: xptr != xend (%d)\n", xend - cptr->xptr)));
IA64_ONLY(OMI_DBG((omi_debug, "gtcm_server: xptr != xend (%ld)\n", xend - cptr->xptr)));
cptr->xptr = xend;
}
omi_buff_rsp(&rh, (omi_err_hdr *)0, 0, bptr, rv);
bptr += OMI_HDR_SIZ + rv;
}
if (bptr >= bend)
{
gtcm_rep_err("Buffer overrun error", -1);
return -1;
}
}
/* If true, this was not an RC XBLK, so we need to calculate the
* size of the response */
if (!xblk)
{
blen = (int)(bptr - buff);
bptr = buff;
if (bunches)
{
OMI_VI_WRIT(blen - OMI_VI_SIZ, bptr);
OMI_LI_WRIT(nxact.value, bptr);
bptr = buff;
}
}
else
bptr = cptr->bptr;
/* Send the response(s) back to the client */
if (history)
save_omi_rsp(bptr, blen);
#ifdef BSD_TCP
/* Write out the response (in pieces if necessary) */
while (blen > 0)
{
while(!servtime_expired && (cc = (int)(write(cptr->fd, bptr, blen))) < 0)
;
save_errno = errno;
if (cc < 0)
{
if (errno == ETIMEDOUT)
{
OMI_DBG((omi_debug, "%s: connection %d to %s timed out.\n",
SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai)));
}
else if (errno == ECONNRESET)
{
OMI_DBG((omi_debug, "%s: connection %d to %s closed by remote client.\n",
SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai)));
}
else if (errno == EPIPE)
{
OMI_DBG((omi_debug, "%s: remote client no longer attached to connection %d, %s.\n",
SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai)));
}
else if (errno == EINTR)
continue;
else
{
char msg[256];
SPRINTF(msg, "Write attempt to connection %d failed", cptr->stats.id);
gtcm_rep_err(msg, save_errno);
}
return -1;
}
bptr += cc;
blen -= cc;
cptr->stats.bytes_send += cc;
omi_bsent += cc;
}
#else /* defined(BSD_TCP) */
#ifdef FILE_TCP
bptr += blen;
cptr->stats.bytes_send += blen;
omi_bsent += blen;
blen -= blen;
#endif /* defined(FILE_TCP) */
#endif /* !defined(BSD_TCP) */
/* If true, a fatal error occurred with the last transaction */
/* also exitt if we received a disconnect request */
if (fatal || rh.op_type.value == OMI_DISCONNECT)
{
return -1;
}
/* Get ready for the next transaction */
cptr->bptr += mlen.value + 4;
cptr->blen -= mlen.value + 4;
if (cptr->xptr > cptr->bptr)
{
gtcm_rep_err("buffer size error", errno);
return -1;
}
/* If true, move the partial buffer to the beginning of the buffer */
if (cptr->blen > 0 && cptr->bptr != cptr->buff)
memmove(cptr->buff, cptr->bptr, cptr->blen);
/* Reset to the beginning of the buffer */
cptr->bptr = cptr->buff;
return 0;
}