fis-gtm/sr_unix_cm/gtcm_loop.c

255 lines
5.5 KiB
C

/****************************************************************
* *
* Copyright 2001, 2012 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. *
* *
****************************************************************/
/*
* gtcm_loop.c ---
*
* GTCM server forever loop. BSD_TCP!
*
*/
#include "mdef.h"
#include "gtm_string.h"
#include "gtm_unistd.h" /* for execlp and fork */
#include "gtm_stdlib.h" /* for exit */
#include "gtm_stdio.h" /* for SPRINTF */
#include <sys/wait.h> /* for wait */
#include "gtcm.h"
#if defined(sun) || defined(mips)
# include <sys/time.h>
#else
# ifdef SEQUOIA
# include <sys/bsd_time.h>
# else
# include "gtm_time.h"
# endif
#endif
#include <errno.h>
#ifdef DEBUG
#include "gtm_fcntl.h"
#endif /* defined(DEBUG) */
#include "gt_timer.h" /* for cancel_timer and start_timer and TID declaration at least */
#include "error.h"
#include "gtmio.h"
#include "have_crit.h"
#ifndef lint
static char rcsid[] = "$Header:$";
#endif
GBLREF int psock;
GBLREF int conn_timeout;
GBLREF int history;
GBLREF int omi_pid;
GBLDEF omi_conn *curr_conn;
GBLDEF boolean_t servtime_expired;
GBLREF int per_conn_servtime;
void hang_handler(void);
void gcore_server(void);
error_def(ERR_OMISERVHANG);
void gtcm_loop(omi_conn_ll *cll)
{
extern int omi_exitp;
int nfds, res;
int now, rsp;
fd_set r_fds, e_fds;
omi_conn *cptr, *prev;
struct timeval timeout, *tp;
if (psock >= 0)
{
timeout.tv_sec = PING_TIMEOUT;
timeout.tv_usec = 0;
tp = &timeout;
}
else
tp = NULL;
curr_conn = NULL;
/* Loop forever accepting connections and transactions */
for (;;) {
FD_ZERO(&r_fds);
FD_ZERO(&e_fds);
/* Pay attention to the network visible end point */
if (INV_FD_P((nfds = cll->nve)))
break;
FD_SET(cll->nve, &r_fds);
FD_SET(cll->nve, &e_fds);
if (psock >= 0)
FD_SET(psock, &r_fds);
/* We will service transactions from any existing connection */
for (cptr = cll->head; cptr; cptr = cptr->next) {
FD_SET(cptr->fd, &r_fds);
FD_SET(cptr->fd, &e_fds);
if (cptr->fd > nfds)
nfds = cptr->fd;
}
if (omi_exitp)
break;
/* Block in the system waiting for network events */
nfds++;
if ((nfds = select(nfds, &r_fds, (fd_set *)0, (fd_set *)0, tp)) < 0)
{
if (errno == EINTR) {
if (!omi_exitp)
continue;
}
else if (errno == EAGAIN) /* temporary OS condition, retry */
{
continue;
}
else
gtcm_rep_err("select() call failed", errno);
break;
}
now = (int)time(0);
/* if we are doing pinging...check the ping socket */
if (psock >= 0 && FD_ISSET(psock, &r_fds))
rsp = get_ping_rsp();
else
rsp = -1;
/* Loop through the connections servicing transactions */
for (cptr = cll->head, prev = (omi_conn *)0; cptr; ) {
if (FD_ISSET(cptr->fd, &r_fds))
{
servtime_expired = FALSE; /* inside hang handler this is set TRUE */
start_timer((TID)gtcm_loop, per_conn_servtime * 1000, hang_handler, 0, NULL);
curr_conn = cptr;
res = omi_srvc_xact(cptr);
curr_conn = NULL;
cancel_timer((TID)gtcm_loop);
if (res >= 0)
{
cptr->timeout = now + conn_timeout;
cptr->ping_cnt = 0;
}
else
{
if (prev)
prev->next = cptr->next;
else
cll->head = cptr->next;
if (cll->tail == cptr)
cll->tail = prev;
gtcm_cn_disc(cptr, cll);
cptr = prev;
}
nfds--;
}
else if (cptr->fd == rsp) /* got a ping response for socket */
{
cptr->timeout = now + conn_timeout;
cptr->ping_cnt = 0;
}
else if (psock >= 0 && now >= cptr->timeout)
{
if (cptr->ping_cnt >= MAX_PING_CNT)
{
OMI_DBG((omi_debug, "%s: no response from connection %d, dropping...\n",
SRVR_NAME,cptr->stats.id));
if (prev)
prev->next = cptr->next;
else
cll->head = cptr->next;
if (cll->tail == cptr)
cll->tail = prev;
gtcm_cn_disc(cptr, cll);
cptr = prev;
}
else
{
if (cptr->ping_cnt)
OMI_DBG((omi_debug, "%s: no response from connection %d, checking...\n",
SRVR_NAME,cptr->stats.id));
else
OMI_DBG((omi_debug, "%s: checking connection %d.\n",
SRVR_NAME,cptr->stats.id));
icmp_ping(cptr->fd);
cptr->ping_cnt++;
cptr->timeout = now + PING_TIMEOUT;
}
}
if ((prev = cptr))
cptr = cptr->next;
}
/* If true, accept a new connection */
if (nfds > 0 && FD_ISSET(cll->nve, &r_fds)) {
if (gtcm_cn_acpt(cll,now) < 0) {
gtcm_rep_err("Unable to accept new connection", errno);
/* break; eliminated: it is acceptable to retry */
}
nfds--;
}
/* Sanity check: is nfds == 0? */
}
return;
}
void hang_handler(void)
{
OMI_DBG_STMP;
OMI_DBG((omi_debug, "%s: server appears to be hung...generating core file...\n",
SRVR_NAME));
gtcm_rep_err("", ERR_OMISERVHANG);
gcore_server();
wait(NULL); /* wait for a signal or the child to exit */
servtime_expired = TRUE;
}
void gcore_server(void)
{
int pid;
if (history)
{
OMI_DBG((omi_debug, "%s: dumping RC history\n", SRVR_NAME));
dump_rc_hist();
}
pid=fork(); /* BYPASSOK: we are dumping a core, so no FORK_CLEAN needed */
if (pid < 0) /* fork error */
{
OMI_DBG((omi_debug,
"%s: unable to start a new process to generate the core\n",
SRVR_NAME));
perror(SRVR_NAME);
} else if (!pid) /* child */
DUMP_CORE;
}