Files
microser/mmslib/util/gensock2.c
2026-06-15 15:48:16 +08:00

2815 lines
95 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/************************************************************************/
/* SOFTWARE MODULE HEADER ***********************************************/
/************************************************************************/
/* (c) Copyright Systems Integration Specialists Company, Inc., */
/* 2002 - 2008, All Rights Reserved */
/* */
/* MODULE NAME : gensock2.c */
/* */
/* MODULE DESCRIPTION : */
/* general socket routines */
/* */
/* */
/* MODIFICATION LOG : */
/* Date Who Rev Comments */
/* -------- --- ------ ------------------------------------------- */
/* 10/15/08 EJV 63 sockCheckForIdleConns CORR: don't close */
/* listening socket. */
/* 10/08/08 MDE 62 Allow variable len header, sockEventQueueFlush*/
/* 10/06/08 JRB 61 Close socket on ANY _sockCheckRxData error */
/* & remove sockClose calls in _sockRecv. */
/* Del _sockCheckRxData call right after connect*/
/* completes (almost never gets data). */
/* 07/24/08 EJV 60 sockSelectResultProcess: check sockErrorDetected */
/* Fix on 11/26/07 (Rev 1.59.1.0 branch). */
/* 04/07/08 EJV 59 sockFree CORR: call sockTxQueueDestroy to */
/* prevent memory leaks. */
/* 02/27/08 EJV 58 sockEventGet: check before decrementing. */
/* 01/29/08 EJV 57 Use S_FMT_PTR macro to log pointers. */
/* sockInitCalling: added 2 return(SD_FAILURE). */
/* 12/04/07 EJV 56 sockUsrFun: check if con secured. */
/* Add sockCheckForIdleConns (SISCO KeepAlive). */
/* 11/28/07 EJV 55 _WIN32: changed to Winsock version 2. */
/* Added disconnectReason in few places. */
/* Added sockDisconnReasonStr for slogging. */
/* sockFree: reversed 'if' for more redability. */
/* 02/21/08 EJV 54 sockGetRemAddrInfo: corr portOut casting for */
/* 0x8000-0xFFFF ports. */
/* 11/28/07 EJV 53 sockSelectResultProcess corr: added continue.*/
/* sockClose: add pSock->hSock=INVALID_SOCKET; */
/* 10/04/07 MDE 52 Tweaked LOGCFG_VALUE_GROUP/LOGCFGX_VALUE_MAP */
/* 09/10/07 MDE 51 Added sockStartEx, log_disable */
/* 02/28/07 MDE 50 Handle 'send' returning 0 (full pipe) */
/* 02/08/07 JRB 49 Add sockEventPut, sockEventGet. */
/* Repl uSockConnect with 2 separate pointers */
/* uSockConnectInd, uSockConnectConf. */
/* 02/06/07 JRB 48 Call _sockServiceDiscardSock ONLY from sockClose.*/
/* Replace other ..DiscardSock calls w/ sockClose.*/
/* 01/30/07 JRB 47 Fix crash in sockFree by simplifying threads */
/* (eliminate Free thread & sockServiceFreeList).*/
/* Call _sockServiceDiscardSock from sockClose. */
/* Lock all access to sockList. */
/* 01/15/07 JRB 46 Del gs_poll_mode flag & poll_mode arg to */
/* sockStart (no longer supported). */
/* 01/03/07 EJV 45 Rpl gensock2 mutexes with S_LOCK_UTIL_RESOURCES */
/* to avoid potential deadlock in slogipc.c; */
/* Del create/destroy calls for gensock2 mutexes*/
/* 12/11/06 EJV 44 sockCreateWakeupSockets, _sockAllocSock: */
/* chg nonblock_on from ST_LONG to int. */
/* Needed on 64-bit UNIX, Linux systems. */
/* 11/17/06 EJV 43 socket funs: added (int) cast, the HP-UX */
/* ssize_t is long. */
/* 11/06/06 EJV 42 Rem static from sockCtxList (extern in H). */
/* 06/13/06 RKR 41 Incorporated porting changes */
/* 04/14/06 JRB 40 Close xCallingSock, xCalledSock in sockEnd. */
/* 02/17/06 EJV 39 __VMS: defined SOCK_OPTLEN and SOCK_ADDRLEN */
/* in gensock2.h. */
/* sockGetRemAddrInfo: chg len from ST_INT type */
/* to SOCK_ADDRLEN. */
/* 01/30/06 GLB 38 Integrated porting changes for VMS */
/* 12/19/05 EJV 37 sockUsrFun: chg args. */
/* 10/09/05 MDE 36 Changed connect errors NERR log to FLOW */
/* 09/28/05 EJV 35 Implemented GEN_SOCK_CTXT & other changes: */
/* Moved filio.h for sun to sysincs.h. */
/* Moved MUTEX macros from gensock2.h & renamed.*/
/* sockStart, sockEnd, _sockAddServiceThread: */
/* add cleanup code. */
/* _sockAddSock: chg return to ST_RET. */
/* Added handling when _sockAddSock fails. */
/* Protect all numActive operations. */
/* sockInitFds: mv init code out, for non-thread*/
/* 07/18/05 EJV 34 sockSelectResultProcess: corr UNIX,LINUX,QNX */
/* check if socket connection successful. */
/* 07/11/05 EJV 33 Added convertIPAddr. */
/* 07/05/05 EJV 32 sockInitCalling, sockInitListen, _sockAccept:*/
/* close hSock if hSock >= FD_SETSIZE */
/* 06/17/05 EJV 31 sockTx: clearer log. */
/* 06/10/05 JRB 30 "_sockClose" deleted. Use "sockClose". */
/* Don't close listen socket on accept error. */
/* 05/23/05 EJV 29 Add sockLogMaskMapCtrl for parsing logcfg.xml*/
/* Moved sock_debug_sel from slog.c. */
/* 05/12/05 EJV 28 MMSEASE_MOSI:listenSocket=NULL GS_ROLE_CALLED*/
/* 05/10/05 EJV Exposed _sockAllocSock, _sockAddSock protos. */
/* sockServiceWake: chg NERR to FLOW log. */
/* 05/04/05 MDE 27 Changed recv NERR log to FLOW */
/* 05/04/05 EJV 26 Corr sockGetRemAddrInfo (chg peer to pp) */
/* 05/03/05 MDE 25 OK to get EINPROGRESS & EINTR in select */
/* 04/15/05 ASK 24 Signed/unsigned warning cleanup. Comment chg.*/
/* 03/23/05 EJV 23 Exposed sockCreateWakeupSockets. */
/* 03/16/05 JRB 22 Disconnect socket if uSockHunt returns */
/* GENSOCK_HUNT_DISCONNECT. */
/* 02/14/05 MDE 21 _sockRecv now looks for SOCK_INPROGRESS too */
/* 02/10/05 MDE 20 Added sockGetRemAddrInfo */
/* 02/02/05 MDE 37 Allow header only receive (empty body) */
/* 12/20/04 ASK 36 Change gs_wakeup_port to 55050. */
/* _sockCreateWakeupSockets: try up to 100 ports*/
/* in range. Change XSocket logs to ERR. */
/* 09/22/04 JRB 35 Change "..Connect Failed.." logs to NERR. */
/* Change "expected" select err log to FLOW. */
/* 08/12/04 EJV 34 sockInitFds corr: do not use FD_SET directly!*/
/* 07/22/04 EJV 33 Added filio.h for sun. */
/* Moved _gUsrCount up (out of define). */
/* 06/21/04 EJV 32 sockInitListen: chg to return errno. */
/* 05/21/04 MDE 31 Added user count _gUsrCount */
/* 05/20/04 EJV 30 Log port number when unable to bind. */
/* 05/17/04 MDE 29 Removed send assert forcing data buffer to */
/* be allocated as part of GEN_SOCK_DATA */
/* 05/03/04 ASK 28 Log errno when unable to send */
/* 04/09/04 ASK 27 sockSelectResultProcess:log SOCK_INTR as NERR*/
/* 04/22/04 MDE 26 Minor logging cleanup */
/* 03/19/04 MDE 25 Added broken pipe handler for QNX */
/* 03/04/04 ASK 24 Switched code in _sockClose. */
/* 02/26/04 EJV 23 Switched code in sockClose. */
/* Use SOCK_OPTLEN and SOCK_ADDRLEN. */
/* 01/30/04 EJV 22 sockSelectResultProcess: fix previous change.*/
/* 01/27/04 EJV 21 sockSelectResultProcess: chg log to NERR. */
/* 01/23/04 EJV 20 sockLogState: added locking semaphore. */
/* sockTxQueueAdd: free the sockData if error. */
/* 01/22/04 EJV 19 Replaced time() calls with sGetMsTime(). */
/* 01/12/04 ASK 18 Don't use socket if closed in _sockAccept. */
/* Add log msg if select() fails. */
/* Sleep for a second if select() fails. */
/* EJV Moved sock_debug_sel to slog.c */
/* Add sockTxQueuedGroupCnt update. */
/* Add sockTxQueueGroupCntGet func. */
/* 11/04/03 JRB 17 Replace gs_sleep calls with sMsSleep. */
/* 07/07/03 JRB 16 Fix some log macros. */
/* 06/25/03 JRB 15 Chg log macros. Chg FLOW log to ERR. */
/* 06/23/03 EJV 14 Added 'first' param to sockTxQueueAdd. */
/* 06/23/03 ASK 13 Set rc to SD_SUCCESS in sockTxQueueProc */
/* 06/20/03 EJV 12 Added sockTxQueueDestroy. Log conn errors. */
/* 06/19/03 EJV 11 Chg some logs. Chg gSock to pSock in funs. */
/* Moved pSock->sockStats.numSend. */
/* 06/19/03 JRB 10 Make Rx/Tx names more consistent. */
/* 06/19/03 JRB 09 Fix ioctlsocket calls chging to non-blocking */
/* mode (last arg must point to non-zero ulong).*/
/* 06/18/03 JRB 08 Chk FD_SETSIZE if !(_WIN32). */
/* Add sockInitAllFds. */
/* Add sockTxMsg, sockTxQueue*: these */
/* use new txMutex & uSockTxBufFree func ptr. */
/* Set REUSEADDR option only on listen socket. */
/* Init totalfds,selectnfds=0 in sockInitFds. */
/* Chg some logging. Fix some ";". */
/* Chk for SOCK_INPROGRESS too. */
/* 06/03/03 MDE 07 More user poll featuresAdded sockGetFds */
/* 06/02/03 ASK 06 _sockRecv(): Log err before calling sockClose*/
/* 05/28/03 JRB 05 Fix setting of timeout for select call. */
/* Del unused code. */
/* 05/14/03 MDE 04 Added sockGetFds */
/* 05/09/03 JRB 03 Don't use SOCKET_ERROR (only defined on WIN32)*/
/* 04/07/03 EJV 02 Preset sock_debug_sel to SOCK_LOG_ERR */
/* 02/17/03 MDE 01 Created */
/************************************************************************/
#include "string.h"
#include "gensock2.h"
/*renxiaobao add*/
#ifndef WIN32
#include <netdb.h>
extern struct hostent *gethostbyname(const char *name);
#endif
#ifdef DEBUG_SISCO
SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__;
#endif
/************************************************************************/
/* Global logging variables */
#define GENSOCK_MAX_HEADER_SIZE 500
ST_UINT sock_debug_sel; /* init in sockStart() */
#ifdef DEBUG_SISCO
LOGCFGX_VALUE_MAP sockLogMaskMaps[] =
{
{"SOCK_LOG_ERR", SOCK_LOG_ERR, &sock_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, NULL, "Error"},
{"SOCK_LOG_NERR", SOCK_LOG_NERR, &sock_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, NULL, "Notice"},
{"SOCK_LOG_FLOW", SOCK_LOG_FLOW, &sock_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, NULL, "Flow"},
{"SOCK_LOG_RX", SOCK_LOG_RX, &sock_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, NULL, "Receive"},
{"SOCK_LOG_TX", SOCK_LOG_TX, &sock_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, NULL, "Transmit"}
};
LOGCFG_VALUE_GROUP sockLogMaskMapCtrl =
{
{NULL,NULL},
"SocketLogMasks", /* Parent Tag */
sizeof(sockLogMaskMaps)/sizeof(LOGCFGX_VALUE_MAP),
sockLogMaskMaps
};
#endif /* DEBUG_SISCO */
SD_CONST ST_CHAR *SD_CONST SOCK_LOG_FLOW_TEXT = "SOCK_LOG_FLOW";
SD_CONST ST_CHAR *SD_CONST SOCK_LOG_NERR_TEXT = "SOCK_LOG_NERR";
SD_CONST ST_CHAR *SD_CONST SOCK_LOG_ERR_TEXT = "SOCK_LOG_ERR";
SD_CONST ST_CHAR *SD_CONST SOCK_LOG_RX_TEXT = "SOCK_LOG_RX";
SD_CONST ST_CHAR *SD_CONST SOCK_LOG_TX_TEXT = "SOCK_LOG_TX";
/************************************************************************/
/* variables */
GEN_SOCK_CTXT *sockCtxList;
/* disconnectReason strings for logging */
ST_CHAR *sockDisconnReasonStr[] =
{
"DISCONNECT REASON: UNKNOWN", /* 0 */
"DISCONNECT REASON: CONNECT_FAILED", /* 1 */
"DISCONNECT REASON: USR_REFUSED", /* 2 */
"DISCONNECT REASON: SEND_FAILURE", /* 3 */
"DISCONNECT REASON: RECV_FAILED", /* 4 */
"DISCONNECT REASON: ACCEPT_FAILED", /* 5 */
"DISCONNECT REASON: SOCKET CLOSED", /* 6 */
"DISCONNECT REASON: TERMINATING", /* 7 */
"DISCONNECT REASON: RESOURCES_ERROR", /* 8 */
"DISCONNECT REASON: INTERNAL_ERROR", /* 9 */
"DISCONNECT REASON: NORMAL_DISCONNECT", /* 10 */
/* disconnectReason for SSL connection */
"DISCONNECT REASON: SSLE_LICENSE", /* 11 */
"DISCONNECT REASON: SSLE_INT_ERR", /* 12 */
"DISCONNECT REASON: REKEY_FAILED", /* 13 */
"DISCONNECT REASON: CERT_VERIFY_ERR", /* 14 */
"DISCONNECT REASON: CERT_ON_CRL", /* 15 */
"DISCONNECT REASON: SEC_PARAM_ERR", /* 16 */
};
ST_INT sockDisconnReasonStrCnt = sizeof (sockDisconnReasonStr)/sizeof (ST_CHAR *);
/************************************************************************/
/* Static functions and macros */
#if defined(GENSOCK_THREAD_SUPPORT)
static ST_THREAD_RET ST_THREAD_CALL_CONV _sockServiceThread (ST_THREAD_ARG pArg);
static ST_RET _sockAddServiceThread (GEN_SOCK_CTRL *serviceCtrl);
#endif
static GEN_SOCK_CTRL *_sockAddServiceCtrl (GEN_SOCK_CTXT *sockCtx);
static ST_RET _sockAccept (GEN_SOCK *pListenSock);
static ST_INT _sockCheckRxData (GEN_SOCK *pSock);
static ST_VOID _sockServiceDiscardSock (GEN_SOCK_CTRL *serviceCtrl, GEN_SOCK *pSock);
/************************************************************************/
/* sockStart */
/* This function initializes the gensock2 for use in new context and */
/* sets the sockCtxOut pointer if the initialization is successful. */
/* Returns: */
/* SD_SUCCESS (0) context initialized */
/* SD_FAILURE otherwise */
/************************************************************************/
ST_RET sockStart (ST_CHAR *ctxName, GEN_SOCK_CTXT **sockCtxOut)
{
ST_RET rc;
rc = sockStartEx (ctxName, sockCtxOut, SD_FALSE);
return (rc);
}
ST_RET sockStartEx (ST_CHAR *ctxName, GEN_SOCK_CTXT **sockCtxOut, ST_BOOLEAN log_disable)
{
static ST_UINT ctxId = 0;
GEN_SOCK_CTXT *sockCtx = NULL;
GEN_SOCK_CTRL *serviceCtrl = NULL;
ST_RET rc = SD_SUCCESS;
if (ctxId == 0)
{
/* do not put any logging above */
#if DEBUG_SISCO
sock_debug_sel |= SOCK_LOG_ERR;
#endif
#ifdef _WIN32
{
ST_INT wRet;
WSADATA wsaData; /* WinSock data */
/* init WinSock interface */
if (wRet = WSAStartup(0x0202, &wsaData))
{
SOCK_LOG_ERR2 (sockCtx, "Can't initialize WinSock interface to use version 2.2 (error=%d) for context '%s'",
(ctxName ? ctxName : ""), wRet);
return (SD_FAILURE);
}
}
#else /* UNIX,... */
signal (SIGPIPE, SIG_IGN);
#endif
++ctxId;
} /* if firstTime */
sockCtx = (GEN_SOCK_CTXT *)chk_calloc (1, sizeof (GEN_SOCK_CTXT));
sockCtx->log_disable = log_disable;
sockCtx->ctxId = ctxId++;
sprintf(sockCtx->ctxName, "%s(ctxId=%u)", (ctxName ? ctxName : ""), sockCtx->ctxId);
#if defined(GENSOCK_THREAD_SUPPORT)
sockCtx->gs_select_timeout = 100000; /* 10 seconds */
sockCtx->gs_wakeup_port = 55050; /* up to 100 ports will be tried starting with this one */
/* already false
sockCtx->gTerminateService = SD_FALSE;
sockCtx->gTerminateFree = SD_FALSE;
*/
#endif /* defined(GENSOCK_THREAD_SUPPORT) */
SOCK_LOG_FLOW1 (sockCtx, "%s: sockStart() initialization pending...", sockCtx->ctxName);
/* Start with one service control */
serviceCtrl = _sockAddServiceCtrl (sockCtx);
/*printf("GENSOCK_THREAD_SUPPORT...\n");*/
#if defined(GENSOCK_THREAD_SUPPORT)
/* Start the service control thread */
//printf("_sockAddServiceThread 1...\n");
rc = _sockAddServiceThread (serviceCtrl);
if (rc != SD_SUCCESS)
{
S_LOCK_UTIL_RESOURCES ();
list_unlink (&sockCtx->sockServiceList, serviceCtrl);
S_UNLOCK_UTIL_RESOURCES ();
chk_free (serviceCtrl);
chk_free (sockCtx);
return (rc);
}
#endif
S_LOCK_UTIL_RESOURCES ();
list_add_last (&sockCtxList, sockCtx);
S_UNLOCK_UTIL_RESOURCES ();
SOCK_LOG_FLOW1 (sockCtx, "%s: sockStart() successful", sockCtx->ctxName);
*sockCtxOut = sockCtx;
return (rc);
}
/************************************************************************/
/* sockEnd */
/* This function cleans up all resources aquired by the sockCtx and */
/* removes the sockCtx from the list. */
/* All context specific threads need to terminate before this function */
/* will return. */
/* Returns: */
/* SD_SUCCESS (0) context released */
/* SD_FAILURE otherwise */
/************************************************************************/
#if defined(_WIN32)
#define MAX_THREAD_END_WAIT INFINITE
#else /* UNIX, Linux,... */
#define MAX_THREAD_END_WAIT -1 /* gs_thread_wait ignores this param (waits indefinitely) */
#endif
ST_RET sockEnd (GEN_SOCK_CTXT *sockCtx)
{
GEN_SOCK_CTRL *serviceCtrl;
#if !defined(GENSOCK_THREAD_SUPPORT)
GEN_SOCK *pSock;
#endif
#if defined(GENSOCK_THREAD_SUPPORT)
ST_RET rc;
#endif
SOCK_LOG_FLOW1 (sockCtx, "%s: sockEnd() pending...", sockCtx->ctxName);
sockCtx->ctxStatus = GEN_SOCK_CTX_TERMINATING; /* prevent adding new sockets to serviceCtrl(s) */
/* First let's terminate terminate all service threads and the free thread */
#if defined(GENSOCK_THREAD_SUPPORT)
/* Set flag for service threads to terminate, then wake them */
sockCtx->gTerminateService = SD_TRUE;
sockServiceWakeAll (sockCtx);
/* Wait for all service threads to terminate */
serviceCtrl = sockCtx->sockServiceList;
while (serviceCtrl != NULL)
{
if (serviceCtrl->tIdService)
{
rc = gs_wait_thread (serviceCtrl->thService, serviceCtrl->tIdService, MAX_THREAD_END_WAIT);
rc = gs_close_thread (serviceCtrl->thService);
serviceCtrl->tIdService = 0;
}
S_LOCK_UTIL_RESOURCES ();
list_unlink (&sockCtx->sockServiceList, serviceCtrl);
S_UNLOCK_UTIL_RESOURCES ();
if (serviceCtrl->serviceEvent)
gs_free_event_sem (serviceCtrl->serviceEvent);
CLOSE_SOCKET (serviceCtrl->xCallingSock);
CLOSE_SOCKET (serviceCtrl->xCalledSock);
chk_free (serviceCtrl);
serviceCtrl = sockCtx->sockServiceList; /* remove from front */
}
#else /* !defined(GENSOCK_THREAD_SUPPORT) */
/* Polled mode */
/* Clean up the service controls */
serviceCtrl = sockCtx->sockServiceList;
while (serviceCtrl != NULL)
{
/* Close all sockets associated with the service control */
while (serviceCtrl->sockList)
{
pSock = serviceCtrl->sockList;
pSock->disconnectReason = GS_DISCONNECT_TERMINATING;
sockClose (pSock);
}
list_unlink (&sockCtx->sockServiceList, serviceCtrl);
chk_free (serviceCtrl);
serviceCtrl = sockCtx->sockServiceList; /* remove from front */
}
#endif /* !defined(GENSOCK_THREAD_SUPPORT) */
SOCK_LOG_FLOW1 (sockCtx, "%s: sockEnd() complete", sockCtx->ctxName);
/* delete the context */
S_LOCK_UTIL_RESOURCES ();
list_unlink (&sockCtxList, sockCtx);
S_UNLOCK_UTIL_RESOURCES ();
chk_free (sockCtx);
return (SD_SUCCESS);
}
/************************************************************************/
/************************************************************************/
/* sockInitCalling */
/************************************************************************/
ST_RET sockInitCalling (GEN_SOCK_CTXT *sockCtx, GEN_SOCK_CONFIG *sockCfg,
ST_UINT16 portNo, ST_CHAR *ipAddr,
GEN_SOCK **pSockOut)
{
GEN_SOCK *pSock;
SOCKET hSock;
struct hostent *pHost;
int sRet;
ST_RET rc;
int err;
SOCK_LOG_FLOW2 (sockCtx, "in sockInitCalling() to ipAddr=%s portNo=%u",
ipAddr, (ST_UINT) portNo);
if (sockCtx->ctxStatus == GEN_SOCK_CTX_TERMINATING)
{
/* prevent adding new sockets to serviceCtrl */
SOCK_LOG_NERR1 (sockCtx, "sockInitCalling failed in context '%s' is terminating", sockCtx->ctxName);
return (SD_FAILURE);
}
hSock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (hSock == INVALID_SOCKET)
{
err = SOCKET_ERRORNO;
SOCK_LOG_ERR1 (sockCtx, "socket() returned INVALID_SOCKET, errno=%d.", err);
return (err);
}
#if !defined(_WIN32)
if (hSock >= FD_SETSIZE)
{ /* Can't use this socket because illegal to use in "select" call*/
SOCK_LOG_ERR1 (sockCtx, "Socket: socket num %d >= FD_SETSIZE (can not be used in select),"
" closing socket.", hSock);
CLOSE_SOCKET (hSock);
return (SD_FAILURE);
}
#endif
pSock = _sockAllocSock (sockCtx, GS_ROLE_CALLING, GS_STATE_CONNECTING, hSock, sockCfg);
SOCK_LOG_FLOW1 (sockCtx, "%s: socket initialized", pSock->sockIdStr);
*pSockOut = pSock;
/* Set up the socket address */
if (strchr(ipAddr, '.') != NULL) /* dotted address format */
{
pSock->sockAddrIn.sin_family = AF_INET;
pSock->sockAddrIn.sin_addr.s_addr = inet_addr (ipAddr);
}
else /* host address format, get dotted address */
{
pHost = gethostbyname (ipAddr);
if (pHost == NULL)
{
err = SOCKET_ERRORNO;
SOCK_LOG_NERR2 (sockCtx, "%s: gethostbyname() failed for host='%s'", pSock->sockIdStr, ipAddr);
CLOSE_SOCKET (pSock->hSock);
chk_free (pSock);
return (err);
}
pSock->sockAddrIn.sin_family = pHost->h_addrtype;
pSock->sockAddrIn.sin_addr.s_addr = ((struct in_addr *)(pHost->h_addr))->s_addr;
}
pSock->sockAddrIn.sin_port = htons (portNo);
/* Do non-blocking connect */
sRet = connect (pSock->hSock, (struct sockaddr *)&pSock->sockAddrIn,
sizeof(pSock->sockAddrIn));
if (sRet >= 0)
{
/* DEBUG: This code probably never executes because socket is non-blocking. */
SOCK_LOG_FLOW1 (sockCtx, "%s: socket connected", pSock->sockIdStr);
pSock->sockState = GS_STATE_CONNECTED;
pSock->sockStats.activeTime = time (NULL);
/* add new socket to service list and then call uSockConnect fun, */
/* the sockAddSock may start new thread that will receive data before */
/* the uSockConnect is called, LOCK is needed to prevent this scenario */
S_LOCK_UTIL_RESOURCES ();
rc = _sockAddSock (pSock); /* Add to a service list */
if (rc == SD_SUCCESS)
{
if (pSock->sockCfg.secConnectProc == NULL)
rc = (*pSock->sockCfg.uSockConnectConf)(pSock);
else
rc = (*pSock->sockCfg.secConnectProc)(pSock);
if (rc != SD_SUCCESS)
{
/* user does not want this connection */
pSock->usrCloseCalled = SD_TRUE; /* don't call uSockDisconnect */
sockClose (pSock);
sockFree (pSock);
/* DEBUG EJV: added this return, otherwise SD_SUCCESS was returned */
return (SD_FAILURE);
}
}
else
{
SOCK_LOG_FLOW1 (sockCtx, "%s: closing socket connections", pSock->sockIdStr);
CLOSE_SOCKET (pSock->hSock);
chk_free (pSock);
/* DEBUG EJV: added this return, otherwise SD_SUCCESS was returned */
return (SD_FAILURE);
}
S_UNLOCK_UTIL_RESOURCES ();
}
else
{
err = SOCKET_ERRORNO;
if (err == SOCK_WOULDBLOCK || err == SOCK_INPROGRESS)
{
rc = _sockAddSock (pSock); /* Add to a service list */
if (rc != SD_SUCCESS)
{
/* since socket is not connected we can use the system socket close */
CLOSE_SOCKET (pSock->hSock);
chk_free (pSock);
return (SD_FAILURE);
}
}
else
{
SOCK_LOG_NERR4 (sockCtx, "%s: connect() to host=%s failed, port=%d, errno=%d",
pSock->sockIdStr, ipAddr, portNo, err);
CLOSE_SOCKET (pSock->hSock);
chk_free (pSock);
return (SD_FAILURE);
}
}
return (SD_SUCCESS);
}
/************************************************************************/
/************************************************************************/
/* sockInitListen */
/* Returns: */
/* SD_SUCCESS (0) listen socket initialized */
/* SD_FAILURE or errno otherwise */
/************************************************************************/
ST_RET sockInitListen (GEN_SOCK_CTXT *sockCtx, GEN_SOCK_CONFIG *sockCfg,
ST_UINT16 portNo, ST_INT maxActive,
GEN_SOCK **pListenSockOut)
{
ST_RET rc;
GEN_SOCK *pListenSock;
ST_INT listenBacklog;
int sRet;
SOCKET hSock;
struct sockaddr_in localAddr;
int err;
int sockopt_on = 1;
int keep_idle,keep_interval,keep_count;
struct timeval TimeOut;
if (sockCtx->ctxStatus == GEN_SOCK_CTX_TERMINATING)
{
/* prevent adding new sockets to serviceCtrl */
SOCK_LOG_NERR1 (sockCtx, "%s: sockInitListen() failed, context is terminating", sockCtx->ctxName);
return (SD_FAILURE);
}
hSock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (hSock == INVALID_SOCKET)
{
err = SOCKET_ERRORNO;
SOCK_LOG_ERR2 (sockCtx, "%s: socket() failed for listen socket, errno=%d", sockCtx->ctxName, err);
return (err);
}
/* renxiaobao <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1> */
sockopt_on = 1; /* <20>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD>KEEPALIVE */
keep_idle = 30; /* <20><>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD>ݰ<EFBFBD><DDB0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>󣬵ȶ<F3A3ACB5><C8B6><EFBFBD><EFBFBD>ʼKEEPALIVE */
keep_interval = 5; /* <20><><EFBFBD><EFBFBD>KEEPALIVE<56><45><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
keep_count = 5; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٸ<EFBFBD>KEEPALIVE<56><45>ûӦ<C3BB><D3A6><EFBFBD>ͶϿ<CDB6>TCP<43><50><EFBFBD><EFBFBD> */
if(setsockopt (hSock, SOL_SOCKET, SO_KEEPALIVE,(char *) &sockopt_on, sizeof (int)))
{
printf ("Error setting KEEPALIVE socket option");
}
#if defined(linux) ||defined(VXWORKS)
if(setsockopt(hSock, IPPROTO_TCP, TCP_KEEPIDLE, (char *)&keep_idle, sizeof(int))) /* IPPROTO_TCP <20><> SOL_TCP*/
{
printf ("Error setting KEEPIDLE socket option");
}
if(setsockopt(hSock, IPPROTO_TCP, TCP_KEEPCNT, (char *)&keep_count, sizeof(int)))
{
printf ("Error setting KEEPCNT socket option");
}
if(setsockopt(hSock, IPPROTO_TCP, TCP_KEEPINTVL,(char *)&keep_interval, sizeof(int)))
{
printf ("Error setting KEEPINTVL socket option");
}
#endif
#if !defined(_WIN32)
if (hSock >= FD_SETSIZE)
{ /* Can't use this socket because illegal to use in "select" call*/
SOCK_LOG_ERR2 (sockCtx, "%s: socket() returned socket num %d >= FD_SETSIZE "
"(can not be used in select), closing socket.", sockCtx->ctxName, hSock);
CLOSE_SOCKET (hSock);
return (SD_FAILURE);
}
#endif
pListenSock = _sockAllocSock (sockCtx, GS_ROLE_LISTENING, GS_STATE_LISTENING,
hSock, sockCfg);
SOCK_LOG_FLOW1 (sockCtx, "%s: initializing listen socket", pListenSock->sockIdStr);
*pListenSockOut = pListenSock;
pListenSock->maxActive = maxActive;
memset((char *)(&localAddr), 0, sizeof(localAddr));
localAddr.sin_family = AF_INET;
localAddr.sin_port = htons(portNo);
localAddr.sin_addr.s_addr = htonl (INADDR_ANY);
sRet = bind (pListenSock->hSock, (struct sockaddr *)&localAddr, sizeof(localAddr));
if (sRet != 0)
{
err = SOCKET_ERRORNO;
SOCK_LOG_NERR4 (sockCtx, "%s: listen socket bind() error on port=%u, errno=%d %s",
pListenSock->sockIdStr, (ST_UINT) portNo, err,
(err == SOCK_EADDRINUSE) ? "(port in use)" : " ");
CLOSE_SOCKET (pListenSock->hSock);
chk_free (pListenSock);
return (err);
}
SOCK_LOG_FLOW1 (sockCtx, "%s: listen socket bind() OK", pListenSock->sockIdStr);
if (pListenSock->sockCfg.listenBacklog == 0)
listenBacklog = SOMAXCONN;
else
listenBacklog = pListenSock->sockCfg.listenBacklog;
sRet = listen (pListenSock->hSock, listenBacklog);
if (sRet != 0)
{
err = SOCKET_ERRORNO;
SOCK_LOG_NERR2 (sockCtx, "%s: listen() failed, errno=%d", pListenSock->sockIdStr, err);
CLOSE_SOCKET (pListenSock->hSock);
chk_free (pListenSock);
return (err);
}
/* Add to a service list */
rc = _sockAddSock (pListenSock);
if (rc != SD_SUCCESS)
{
CLOSE_SOCKET (pListenSock->hSock);
chk_free (pListenSock);
}
else
SOCK_LOG_FLOW2 (sockCtx, "%s: listen started on port=%d", pListenSock->sockIdStr, portNo);
return (rc);
}
/************************************************************************/
/* sockTxMsg */
/* Send complete message. Some data may be queued for later delivery. */
/* "sockTxQueueProc" must be called periodically to send any data that */
/* has been queued up. */
/************************************************************************/
ST_RET sockTxMsg (GEN_SOCK *pSock, GEN_SOCK_DATA *sockData)
{
ST_RET retVal;
retVal = sockTxQueueAdd (pSock, sockData, SD_FALSE); /* queue data */
if (retVal==SD_SUCCESS)
retVal = sockTxQueueProc (pSock); /* send what we can from queue */
return (retVal);
}
/************************************************************************/
/* sockTxQueueAdd */
/* Queue data for later delivery. */
/* "sockTxQueueProc" must be called periodically to send any data that */
/* has been queued up. */
/************************************************************************/
ST_RET sockTxQueueAdd (GEN_SOCK *pSock, GEN_SOCK_DATA *sockData, ST_BOOLEAN first)
{
GEN_SOCK_CTXT *sockCtx;
ST_RET retVal;
sockCtx = pSock->sockCtx;
/* Put on our pending send list */
S_LOCK_UTIL_RESOURCES ();
if (first)
retVal = list_add_first (&pSock->sockTxPend, sockData);
else
retVal = list_add_last (&pSock->sockTxPend, sockData);
if (retVal == SD_SUCCESS)
{
if (sockData->eot)
++pSock->sockTxQueueGroupCnt;
}
else
/* user expects that sockTxMsg will free the sockData buff in any case */
(*pSock->sockCfg.uSockTxBufFree) (pSock, sockData);
S_UNLOCK_UTIL_RESOURCES ();
return (retVal);
}
/************************************************************************/
/* sockTxQueueDestroy */
/* Free all queued messages. */
/************************************************************************/
ST_RET sockTxQueueDestroy (GEN_SOCK *pSock)
{
GEN_SOCK_CTXT *sockCtx;
GEN_SOCK_DATA *sockData;
sockCtx = pSock->sockCtx;
/* Free all queued messages from list */
S_LOCK_UTIL_RESOURCES ();
while (pSock->sockTxPend != NULL)
{
sockData = pSock->sockTxPend;
list_unlink (&pSock->sockTxPend, sockData);
(*pSock->sockCfg.uSockTxBufFree) (pSock, sockData);
}
pSock->sockTxQueueGroupCnt = 0;
S_UNLOCK_UTIL_RESOURCES ();
return (SD_SUCCESS);
}
/************************************************************************/
/* sockTxQueueProc */
/* Must be called periodically to send any data queued up by calls to */
/* "sockTxQueueAdd". */
/************************************************************************/
ST_RET sockTxQueueProc (GEN_SOCK *pSock)
{
GEN_SOCK_CTXT *sockCtx;
GEN_SOCK_DATA *sockData;
ST_INT numSent;
ST_RET rc = SD_SUCCESS;
sockCtx = pSock->sockCtx;
S_LOCK_UTIL_RESOURCES ();
/* Send as much data as possible */
while (pSock->sockTxPend != NULL)
{
sockData = pSock->sockTxPend;
rc = sockTx (pSock, sockData, &numSent);
if (rc == SD_SUCCESS)
{
if (numSent == sockData->dataLen)
{
/* OK, we were able to send the rest of the buffer */
++pSock->sockStats.numSend; /* num of RFC1006 msgs sent */
list_unlink (&pSock->sockTxPend, sockData);
if (sockData->eot)
{
if (pSock->sockTxQueueGroupCnt > 0 )
--pSock->sockTxQueueGroupCnt; /* tx last msg from a group */
else
SOCK_LOG_ERR1 (sockCtx, "%s: tx queue count invalid.", pSock->sockIdStr);
}
(*pSock->sockCfg.uSockTxBufFree) (pSock, sockData);
}
else
{
/*printf("numSent(%d) != sockData->dataLen(%d)\n",numSent , sockData->dataLen);*/
/* Prepare for next send attempt */
sockData->data += numSent;
sockData->dataLen -= numSent;
/* Stop trying to send */
break;
}
}
else /* Send error */
{
SOCK_LOG_NERRC1 (sockCtx, "%s: sockTx() failed, emptying send queue.", pSock->sockIdStr);
/* printf(sockCtx, "%s: sockTx() failed, emptying send queue.", pSock->sockIdStr);*/
/* Free all queued send data ... */
sockTxQueueDestroy (pSock);
break;
}
}
S_UNLOCK_UTIL_RESOURCES ();
return (rc);
}
/************************************************************************/
/* sockTxQueueGroupCntGet */
/************************************************************************/
ST_UINT sockTxQueueGroupCntGet (GEN_SOCK *pSock)
{
GEN_SOCK_CTXT *sockCtx;
ST_UINT queCnt;
sockCtx = pSock->sockCtx;
S_LOCK_UTIL_RESOURCES ();
queCnt = pSock->sockTxQueueGroupCnt;
S_UNLOCK_UTIL_RESOURCES ();
return (queCnt);
}
/************************************************************************/
/************************************************************************/
/* sockTx */
/************************************************************************/
ST_RET sockTx (GEN_SOCK *pSock, GEN_SOCK_DATA *sockData, ST_INT *numSentOut)
{
GEN_SOCK_CTXT *sockCtx;
ST_RET ret;
sockCtx = pSock->sockCtx;
if (pSock->sockState != GS_STATE_CONNECTED)
{
SOCK_LOG_NERR2 (sockCtx, "%s: sockTx() failed, socket not connected sockState=%d",
pSock->sockIdStr, pSock->sockState);
return (SD_FAILURE);
}
if (pSock->sockCfg.secTxProc == NULL)
ret = _sockTx (pSock, sockData, numSentOut);
else
ret = (*pSock->sockCfg.secTxProc) (pSock, sockData, numSentOut);
return (ret);
}
/************************************************************************/
/* _sockTx */
/************************************************************************/
ST_RET _sockTx (GEN_SOCK *pSock, GEN_SOCK_DATA *sockData, ST_INT *numSentOut)
{
GEN_SOCK_CTXT *sockCtx;
ST_INT numSent;
ST_INT err;
sockCtx = pSock->sockCtx;
#ifdef SOCK_FLOW_PRINT /* DEBUG: enable this to see data flow. */
printf ("|");
#endif
SOCK_LOG_FLOW2 (sockCtx, "%s: _sockTx() request to send %d bytes",
pSock->sockIdStr, sockData->dataLen);
numSent = (ST_INT) send (pSock->hSock, sockData->data, sockData->dataLen, 0);
if (numSent >= 0) /* Success ? */
{
SOCK_LOG_FLOWC3 (sockCtx, "%s: _sockTx() sent %d vs. %d requested",
pSock->sockIdStr, numSent, sockData->dataLen);
if (numSent < sockData->dataLen)
{
pSock->sockCfg.chkWritable = SD_TRUE;
sockServiceWake (pSock->serviceCtrl);
}
*numSentOut = numSent;
/* save the time of last successful data transfer activity on the socket */
if (numSent > 0 && sockCtx->maxIdleTime > 0)
pSock->sockStats.lastActivityTime = sGetMsTime();
return (SD_SUCCESS);
}
else
{
err = SOCKET_ERRORNO;
switch (err)
{
case SOCK_WOULDBLOCK:
case SOCK_NOBUFS:
case SOCK_INTR:
case SOCK_INPROGRESS:
case SOCK_TIMEDOUT:
SOCK_LOG_FLOWC2 (sockCtx, "%s: _sockTx sent 0, error (%d), no send buffers?",
pSock->sockIdStr, err);
pSock->sockCfg.chkWritable = SD_TRUE;
sockServiceWake (pSock->serviceCtrl);
*numSentOut = 0;
return (SD_SUCCESS);
break;
default:
SOCK_LOG_NERR2 (sockCtx, "%s: socket send() error (%d)", pSock->sockIdStr, err);
break;
}
}
S_LOCK_UTIL_RESOURCES ();
if (pSock->sockState == GS_STATE_CONNECTED)
{
pSock->disconnectReason = GS_DISCONNECT_SEND_FAILURE;
sockClose (pSock); /* Close and wake the service thread */
}
S_UNLOCK_UTIL_RESOURCES ();
return (SD_FAILURE);
}
/************************************************************************/
/* sockClose */
/************************************************************************/
ST_RET sockClose (GEN_SOCK *pSock)
{
GEN_SOCK_CTXT *sockCtx;
sockCtx = pSock->sockCtx;
SOCK_LOG_FLOW1 (sockCtx, "%s: in sockClose()", pSock->sockIdStr);
S_LOCK_UTIL_RESOURCES ();
if (pSock->sockState != GS_STATE_CLOSED)
{
pSock->sockState = GS_STATE_CLOSED;
/* On AIX the close() will not return until select() returns. */
/* Wake the service thread (or terminate the select) */
if (pSock->serviceCtrl) /* sockClose maybe called when serviceCtrl=NULL */
sockServiceWake (pSock->serviceCtrl);
CLOSE_SOCKET (pSock->hSock);
pSock->hSock = INVALID_SOCKET; /* make sure handle not used anymore */
/* Discard all events for this socket */
sockEventQueueFlush (sockCtx, pSock);
/* Done with this socket. Remove it from service list. */
_sockServiceDiscardSock (pSock->serviceCtrl, pSock);
}
S_UNLOCK_UTIL_RESOURCES ();
return SD_SUCCESS;
}
/************************************************************************/
/* sockFree */
/************************************************************************/
/* Must be called after (or from) disconnect callback */
ST_RET sockFree (GEN_SOCK *pSock)
{
GEN_SOCK_CTXT *sockCtx;
sockCtx = pSock->sockCtx;
SOCK_LOG_FLOW1 (sockCtx, "%s: in sockFree()", pSock->sockIdStr);
if (pSock->sockState != GS_STATE_CLOSED)
{
SOCK_LOG_NERR1 (sockCtx, "%s: socket state not closed, can't free", pSock->sockIdStr);
return (SD_FAILURE);
}
if (pSock->sockCfg.secSockFree != NULL)
(*pSock->sockCfg.secSockFree) (pSock);
/* We can free this socket if: */
/* 1. It is not a listen socket, or */
/* 2. It is a listen socket with no called socket references */
/* protect numActive */
S_LOCK_UTIL_RESOURCES ();
/* release any queued data buffers */
sockTxQueueDestroy (pSock);
if (pSock->role == GS_ROLE_LISTENING && pSock->numActive != 0)
{
/* can happen when exiting */
SOCK_LOG_NERR2 (sockCtx, "%s: Can't free listening GEN_SOCK " S_FMT_PTR " (pointer still in use)",
pSock->sockIdStr, pSock);
}
else
{
SOCK_LOG_FLOW2 (sockCtx, "%s: freeing GEN_SOCK " S_FMT_PTR ".", pSock->sockIdStr, pSock);
chk_free (pSock);
}
S_UNLOCK_UTIL_RESOURCES ();
return SD_SUCCESS;
}
/************************************************************************/
/* _sockAddServiceCtrl */
/************************************************************************/
static GEN_SOCK_CTRL *_sockAddServiceCtrl (GEN_SOCK_CTXT *sockCtx)
{
GEN_SOCK_CTRL *serviceCtrl;
serviceCtrl = (GEN_SOCK_CTRL *) chk_calloc (1, sizeof (GEN_SOCK_CTRL));
serviceCtrl->sockCtx = sockCtx;
S_LOCK_UTIL_RESOURCES ();
list_add_last (&sockCtx->sockServiceList, serviceCtrl);
S_UNLOCK_UTIL_RESOURCES ();
return (serviceCtrl);
}
/************************************************************************/
/* sockServiceWakeAll */
/************************************************************************/
ST_VOID sockServiceWakeAll (GEN_SOCK_CTXT *sockCtx)
{
#if defined(GENSOCK_THREAD_SUPPORT)
GEN_SOCK_CTRL *serviceCtrl;
serviceCtrl = sockCtx->sockServiceList;
while (serviceCtrl != NULL)
{
sockServiceWake (serviceCtrl);
serviceCtrl = (GEN_SOCK_CTRL *) list_get_next (sockCtx->sockServiceList, serviceCtrl);
}
#endif
}
/************************************************************************/
/* sockServiceWake */
/************************************************************************/
ST_VOID sockServiceWake (GEN_SOCK_CTRL *serviceCtrl)
{
#if defined(GENSOCK_THREAD_SUPPORT)
GEN_SOCK_CTXT *sockCtx;
ST_INT numSent;
static ST_UCHAR wakeupData = 1;
if (!serviceCtrl)
return;
sockCtx = serviceCtrl->sockCtx;
/* Be sure it was not set NULL */
if (serviceCtrl == NULL)
return;
if (serviceCtrl->serviceEvent)
gs_signal_event_sem (serviceCtrl->serviceEvent);
if (serviceCtrl->xCalledSock == 0)
return;
/* OK, there is a wakeup port for this sock service */
numSent = (ST_INT) send (serviceCtrl->xCalledSock, &wakeupData, sizeof(wakeupData), 0);
if (numSent == sizeof (wakeupData))
{
SOCK_LOG_FLOW2 (sockCtx, "%s: XSocket sent %d wakeup bytes", sockCtx->ctxName, numSent);
}
else
{
/* when a lot of packets are received in short time, EWOULDBLOCK and EAGAIN */
/* errors could happen often with this 1-byte packets */
SOCK_LOG_FLOW3 (sockCtx, "%s: XSocket wakeup data send() error, errno=%d",
sockCtx->ctxName, numSent, SOCKET_ERRORNO);
}
++wakeupData;
#endif
}
/************************************************************************/
/* sockCheckForIdleConns */
/*----------------------------------------------------------------------*/
/* Check for idle connections if the tcpMaxIdleTime >0. */
/* Calling/called connections are closed if there is no activity tx/rx */
/* for this period of time. The checking will be performed with the */
/* frequency of 30 seconds. */
/************************************************************************/
#define GS_IDLE_CON_CHECK_FREQENCY ((ST_DOUBLE)(30*1000)) /* ms */
float sock_sts_lastCheckTimer=0;
static ST_RET sockCheckForIdleConns (GEN_SOCK_CTRL *serviceCtrl)
{
ST_DOUBLE currTime;
ST_UINT maxIdleTime;
int index=0;
GEN_SOCK *pSock;
GEN_SOCK *pSockNext;
GEN_SOCK_CTXT *sockCtx;
if (!serviceCtrl || !serviceCtrl->sockCtx)
return (SD_FAILURE);
sockCtx = serviceCtrl->sockCtx;
maxIdleTime = sockCtx->maxIdleTime;
if (maxIdleTime == 0)
/* user do not want to check for idle TCP connections */
return (SD_SUCCESS);
if (serviceCtrl->lastCheckIdleTime == 0)
{
/* starting, initialize the lastCheckedTime */
serviceCtrl->lastCheckIdleTime = sGetMsTime ();
return (SD_SUCCESS);
}
currTime = sGetMsTime ();
if ((currTime - serviceCtrl->lastCheckIdleTime) < GS_IDLE_CON_CHECK_FREQENCY)
return (SD_SUCCESS);
/* it is time to check the list of sockets for idle connections */
S_LOCK_UTIL_RESOURCES (); /* CRITICAL: lock all access to sockList*/
pSock = serviceCtrl->sockList;
while (pSock)
{
pSockNext = (GEN_SOCK *) list_get_next (serviceCtrl->sockList, pSock);
if (pSock->role != GS_ROLE_LISTENING)
{
if ((ST_UINT) (currTime - pSock->sockStats.lastActivityTime) >= maxIdleTime)
{
SOCK_LOG_NERR2 (sockCtx, "%s: closing idle socket, maxIdleTime=%u seconds reached.",
pSock->sockIdStr, maxIdleTime/1000);
printf("%s: closing idle socket, maxIdleTime=%u seconds reached.\r\n",
pSock->sockIdStr, maxIdleTime/1000);
sockClose (pSock);
}
}
pSock = pSockNext;
}
S_UNLOCK_UTIL_RESOURCES ();
serviceCtrl->lastCheckIdleTime = currTime;
return (SD_SUCCESS);
}
/************************************************************************/
/* sockCtrlService */
/************************************************************************/
int sockCtrlService_pri=0;
int test_sockClose =0; /*test_sockClose=1;*/
int ttt_t=0;
ST_INT sockCtrlService (GEN_SOCK_CTRL *serviceCtrl, ST_LONG timeOut)
{
GENSOCK_FD_SET sockFds;
struct timeval selectTimeout;
int nfds;
ST_INT retVal;
int index=0;
GEN_SOCK *pSock;
GEN_SOCK *pSockNext;
/* CRITICAL: start with clean sockFds. */
sockFds.totalfds = 0;
sockFds.selectnfds = 0;
sockFds.numReadfds = 0;
sockFds.numWritefds = 0;
sockFds.numExceptfds = 0;
FD_ZERO (&sockFds.readfds);
FD_ZERO (&sockFds.writefds);
FD_ZERO (&sockFds.exceptfds);
/* Build the set of sockets to listen to */
sockInitFds (serviceCtrl, &sockFds);
if (sockFds.totalfds == 0)
return (GS_SELECT_NO_ACTIVE_SOCK);
/* Now wait for some activity */
selectTimeout.tv_sec = timeOut / 1000;
selectTimeout.tv_usec = (timeOut % 1000) * 1000;
nfds = select (sockFds.selectnfds, &sockFds.readfds, &sockFds.writefds, &sockFds.exceptfds, &selectTimeout);
/*renxiaobao <20><><EFBFBD><EFBFBD>*/
if((test_sockClose)||(nfds<0))
{
test_sockClose=0;
S_LOCK_UTIL_RESOURCES ();
pSock = serviceCtrl->sockList;
while(pSock)
{
pSockNext=(GEN_SOCK *)list_get_next (serviceCtrl->sockList, pSock);
if(pSock->sockState!=GS_STATE_LISTENING)
{
SOCK_LOG_ERR3 (serviceCtrl->sockCtx, "sockClose(%d)(selectnfds=%d pSock->sockState=%d)", ++index,sockFds.selectnfds,pSock->sockState);
printf("sockClose(%d)(selectnfds=%d pSock->sockState=%d)\r\n", index,sockFds.selectnfds,pSock->sockState);
/* sockClose(pSock);*/
}
pSock=pSockNext;
}
S_UNLOCK_UTIL_RESOURCES ();
serviceCtrl->lastCheckIdleTime=sGetMsTime ();
return (GS_SELECT_ERROR);
}
/*end*/
if(sockCtrlService_pri)
{
sockCtrlService_pri--;
printf("sockCtrlService nfds=%d %d timeOut=%d \r\n",nfds,serviceCtrl->sockList->sockState,timeOut);
index=0;
pSock = serviceCtrl->sockList;
while(pSock)
{
pSockNext=(GEN_SOCK *)list_get_next (serviceCtrl->sockList, pSock);
printf("sockState(%d)(pSock->sockState=%d)\r\n", index,pSock->sockState);
pSock=pSockNext;
}
}
/*
#define GS_STATE_LISTENING 1
#define GS_STATE_STOPPING_LISTEN 2
#define GS_STATE_FAILED_LISTEN 3
#define GS_STATE_CONNECTING 4
#define GS_STATE_CONNECTED 5
#define GS_STATE_CLOSED 6
*/
#if (defined(GENSOCK_THREAD_SUPPORT) && defined(__VMS))
if (nfds > 0)
{
sys$cantim(10000, 0); /* that is sys$cantim(MICS_AST_WAITANYEVENT, 0); */
sys$setef (101); /* that is sys$setef (MICS_FLAG_ACTIVITY) */
}
#endif
#if defined(GENSOCK_THREAD_SUPPORT)
{
GEN_SOCK_CTXT *sockCtx = serviceCtrl->sockCtx;
/* Make sure we are not supposed to terminate .. */
if (sockCtx->gTerminateService == SD_TRUE)
return (GS_SELECT_TERMINATED);
}
#endif
retVal = sockSelectResultProcess (serviceCtrl, nfds, &sockFds);
/* check if there are idle sockets before we return */
sockCheckForIdleConns (serviceCtrl);
return (retVal);
}
#if !defined(GENSOCK_THREAD_SUPPORT)
/************************************************************************/
/* sockInitAllFds */
/* Initialize the GENSOCK_FD_SET struct for "all" sockets, so that */
/* "select" call can include all sockets. */
/* Assume there is only one entry on the linked list "sockCtx->sockServiceList" */
/* and just use it. */
/************************************************************************/
ST_VOID sockInitAllFds (GENSOCK_FD_SET *sockFds)
{
GEN_SOCK_CTXT *sockCtx;
/* CRITICAL: start with clean sockFds. */
sockFds->totalfds = 0;
sockFds->selectnfds = 0;
sockFds->numReadfds = 0;
sockFds->numWritefds = 0;
sockFds->numExceptfds = 0;
FD_ZERO (&sockFds->readfds);
FD_ZERO (&sockFds->writefds);
FD_ZERO (&sockFds->exceptfds);
sockCtx = sockCtxList;
while (sockCtx)
{
assert (sockCtx->sockServiceList->l.next == (DBL_LNK *) sockCtx->sockServiceList); /* make sure only one on list*/
sockInitFds (sockCtx->sockServiceList, sockFds);
sockCtx = (GEN_SOCK_CTXT *)list_get_next (sockCtxList, sockCtx);
}
}
#endif /* !defined(GENSOCK_THREAD_SUPPORT) */
/************************************************************************/
/* sockInitFds */
/************************************************************************/
ST_VOID sockInitFds (GEN_SOCK_CTRL *serviceCtrl, GENSOCK_FD_SET *sockFds)
{
GEN_SOCK *pSock;
GEN_SOCK *pNextSock;
GEN_SOCK_CONFIG *sockCfg;
GEN_SOCK_CTXT *sockCtx;
sockCtx = serviceCtrl->sockCtx;
#if defined(GENSOCK_THREAD_SUPPORT)
if (serviceCtrl->xCallingSock)
sockAddReadFds (sockFds, serviceCtrl->xCallingSock);
#endif
S_LOCK_UTIL_RESOURCES ();
pSock = serviceCtrl->sockList;
while (pSock)
{
pNextSock = (GEN_SOCK *) list_get_next (serviceCtrl->sockList, pSock);
if (pSock->sockState == GS_STATE_CONNECTED)
{
sockCfg = &pSock->sockCfg;
if (sockCfg->pauseRecv == SD_FALSE)
sockAddReadFds (sockFds, pSock->hSock);
if (sockCfg->chkWritable)
sockAddWriteFds (sockFds, pSock->hSock);
}
else if (pSock->sockState == GS_STATE_CONNECTING)
{
sockAddWriteFds (sockFds, pSock->hSock);
sockAddExceptFds (sockFds, pSock->hSock);
}
else if (pSock->sockState == GS_STATE_LISTENING)
sockAddReadFds (sockFds, pSock->hSock);
pSock = pNextSock;
}
S_UNLOCK_UTIL_RESOURCES ();
}
/************************************************************************/
/* sockAddReadFds */
/************************************************************************/
ST_VOID sockAddReadFds (GENSOCK_FD_SET *sockFds, SOCKET hSock)
{
#if !defined(_WIN32)
assert (hSock < FD_SETSIZE); /* FD_SET assumes this is true */
#endif
FD_SET (hSock, &sockFds->readfds);
if ((hSock+1) > (sockFds->selectnfds))
sockFds->selectnfds = (hSock+1);
++sockFds->numReadfds;
++sockFds->totalfds;
}
/************************************************************************/
/* sockAddWriteFds */
/************************************************************************/
ST_VOID sockAddWriteFds (GENSOCK_FD_SET *sockFds, SOCKET hSock)
{
#if !defined(_WIN32)
assert (hSock < FD_SETSIZE); /* FD_SET assumes this is true */
#endif
FD_SET (hSock, &sockFds->writefds);
if ((hSock+1) > (sockFds->selectnfds))
sockFds->selectnfds = (hSock+1);
++sockFds->numWritefds;
++sockFds->totalfds;
}
/************************************************************************/
/* sockAddExceptFds */
/************************************************************************/
ST_VOID sockAddExceptFds (GENSOCK_FD_SET *sockFds, SOCKET hSock)
{
#if !defined(_WIN32)
assert (hSock < FD_SETSIZE); /* FD_SET assumes this is true */
#endif
FD_SET (hSock, &sockFds->exceptfds);
if ((hSock+1) > (sockFds->selectnfds))
sockFds->selectnfds = (hSock+1);
++sockFds->numExceptfds;
++sockFds->totalfds;
}
/************************************************************************/
/* sockSelectResultProcess */
/* NOTE: this function closes the socket on any error. */
/************************************************************************/
ST_INT sockSelectResultProcess (GEN_SOCK_CTRL *serviceCtrl,
int nfds, GENSOCK_FD_SET *sockFds)
{
GEN_SOCK_CTXT *sockCtx;
GEN_SOCK *pSock;
GEN_SOCK *pNextSock;
GEN_SOCK_CONFIG *sockCfg;
ST_RET rc;
ST_INT startState;
ST_INT err;
ST_RET sockErrorDetected;
#if defined(GENSOCK_THREAD_SUPPORT)
ST_CHAR bitBucket[100];
ST_INT recvRet;
#endif
sockCtx = serviceCtrl->sockCtx;
/* Check for timeout */
if (nfds == 0)
return (GS_SELECT_TIMEOUT);
/* Check for error (may happen when sockets are closed while in select) */
if (nfds < 0)
{
/* error */
err = SOCKET_ERRORNO;
if (err == SOCK_INPROGRESS || err == SOCK_INTR)
return (GS_SELECT_ACTIVE);
#if defined(GENSOCK_THREAD_SUPPORT)
if ((err == SOCK_NOTSOCK || err == SOCK_INTR)) /* ? SOCK_INTR is above */
/* If one or more sockets were closed by another thread, this error is expected.*/
SOCK_LOG_FLOW2 (sockCtx, "%s: select() call failed."
" Expected if one or more sockets closed by another thread, errno=%d",
sockCtx->ctxName, err);
else
SOCK_LOG_ERR2 (sockCtx, "%s: select() call failed, errno=%d", sockCtx->ctxName, err);
#else
SOCK_LOG_ERR2 (sockCtx, "%s: select() call failed, errno=%d", sockCtx->ctxName, err);
#endif
return (GS_SELECT_ERROR);
}
/* OK now we have got some data to read from at least one of the sockets */
S_LOCK_UTIL_RESOURCES (); /* CRITICAL: lock all access to sockList*/
pSock = serviceCtrl->sockList;
while (pSock && nfds > 0)
{
pNextSock = (GEN_SOCK *) list_get_next (serviceCtrl->sockList, pSock);
sockErrorDetected = SD_FALSE;
sockCfg = &pSock->sockCfg;
if (pSock->sockState == GS_STATE_CONNECTED)
{
/* Check for data or disconnect on this socket ... */
if (FD_ISSET (pSock->hSock, &sockFds->readfds))
{ /* We have data or a disconnect */
--nfds;
startState = pSock->recvState;
if (_sockCheckRxData (pSock) != SD_SUCCESS)
sockErrorDetected = SD_TRUE;
}
/* See if we are checking for writability too */
if (!sockErrorDetected && sockCfg->chkWritable && FD_ISSET (pSock->hSock, &sockFds->writefds))
{
SOCK_LOG_FLOW1 (sockCtx, "%s: socket is Writable", pSock->sockIdStr);
sockCfg->chkWritable = SD_FALSE; /* one-shot */
if (sockCfg->secEnable == SD_FALSE)
(*sockCfg->uSockWritable)(pSock);
else
(*sockCfg->secWritable)(pSock);
}
}
else if (pSock->sockState == GS_STATE_CONNECTING)
{ /* Check for activity on this socket ... */
/* NOTE: On UNIX, LINUX, QNX the writefds is used to indicate that the */
/* connection completed or failed. Must call the getsocketopt() */
/* to check the connection status! */
/* On Windows writefds set indicates successful connection */
/* (exceptfds is used to indicate failed connection). */
if (FD_ISSET (pSock->hSock, &sockFds->writefds))
{
#if !defined(_WIN32)
SOCK_OPTLEN optlen;
ST_INT sRet;
ST_INT connError = 0;
optlen = sizeof(connError);
sRet = getsockopt (pSock->hSock, SOL_SOCKET, SO_ERROR, (ST_CHAR *) &connError, &optlen);
if (sRet == 0)
{
if (connError != 0)
{
SOCK_LOG_FLOW2 (sockCtx, "%s: socket Connect failed. Error = %d", pSock->sockIdStr, connError);
pSock->disconnectReason = GS_DISCONNECT_CONNECT_FAILED;
sockErrorDetected = SD_TRUE;
}
}
else
{
SOCK_LOG_ERR2 (sockCtx, "%s: getsockopt(...,SOL_SOCKET, SO_ERROR,...) failed, errno=%d.",
pSock->sockIdStr, SOCKET_ERRORNO);
pSock->disconnectReason = GS_DISCONNECT_CONNECT_FAILED;
sockErrorDetected = SD_TRUE;
}
#endif /* !defined(_WIN32) */
--nfds;
if (!sockErrorDetected)
{
SOCK_LOG_FLOW1 (sockCtx, "%s: socket connected", pSock->sockIdStr);
pSock->sockState = GS_STATE_CONNECTED;
pSock->sockStats.activeTime = time (NULL);
if (sockCfg->secConnectProc == NULL)
rc = (*sockCfg->uSockConnectConf)(pSock);
else
rc = (*sockCfg->secConnectProc)(pSock);
if (rc == SD_SUCCESS)
{
/* Do nothing. Receive data on next call. */
}
else /* User does not want */
{
if (!pSock->disconnectReason)
pSock->disconnectReason = GS_DISCONNECT_USR_REFUSED;
/* No need to lock, user will not free or access anymore */
sockClose (pSock);
sockFree (pSock); /* Allow it to be free'd */
}
}
}
else if (FD_ISSET (pSock->hSock, &sockFds->exceptfds))
{ /* Connect failed (WNIDOWS ONLY) */
SOCK_OPTLEN optlen;
ST_INT sRet;
ST_INT connError;
optlen = sizeof(connError);
sRet = getsockopt (pSock->hSock, SOL_SOCKET, SO_ERROR, (ST_CHAR *) &connError, &optlen);
if (sRet == 0)
SOCK_LOG_FLOW2 (sockCtx, "%s: socket Connect Failed. Error = %d", pSock->sockIdStr, connError);
else
SOCK_LOG_ERR2 (sockCtx, "%s: getsockopt(...,SOL_SOCKET, SO_ERROR,...) failed, errno=%d.",
pSock->sockIdStr, SOCKET_ERRORNO);
--nfds;
pSock->disconnectReason = GS_DISCONNECT_CONNECT_FAILED;
sockErrorDetected = SD_TRUE;
}
}
else if (pSock->sockState == GS_STATE_LISTENING)
{ /* Check for activity on this socket ... */
if (FD_ISSET (pSock->hSock, &sockFds->readfds))
{
--nfds;
_sockAccept (pSock);
}
}
else /* Not really interesting */
{
if (FD_ISSET (pSock->hSock, &sockFds->readfds))
--nfds;
}
if (sockErrorDetected == SD_TRUE)
sockClose (pSock); /* error on this socket, so close it */
pSock = pNextSock;
} /* While sockets and nfds */
S_UNLOCK_UTIL_RESOURCES (); /* CRITICAL: lock all access to sockList*/
#if defined(GENSOCK_THREAD_SUPPORT)
/* See if someone woke us by sending us data */
if (nfds > 0)
{
if (FD_ISSET (serviceCtrl->xCallingSock, &sockFds->readfds))
{
/* Non-blocking receive, dump data */
recvRet = (ST_INT) recv (serviceCtrl->xCallingSock, bitBucket, sizeof (bitBucket), 0);
/* log only if this is not an SLOGIPC xCallingSock (otherwise looping occurs) */
if (memcmp (sockCtx->ctxName, SLOGIPC_NAME, strlen(SLOGIPC_NAME)) != 0)
{
if (recvRet > 0)
{
SOCK_LOG_FLOW2 (sockCtx, "%s: XSocket received %d wakeup bytes", sockCtx->ctxName, recvRet);
}
else if (recvRet == 0)
{
SOCK_LOG_NERR1 (sockCtx, "%s: XSocket disconnected detected by recv()", sockCtx->ctxName);
}
}
}
}
#endif
return (GS_SELECT_ACTIVE);
}
/************************************************************************/
/* _sockServiceDiscardSock */
/* NOTE: this must be called ONLY from sockClose. */
/************************************************************************/
/* Remove a pSock from a service control and allow it to be free'd */
static ST_VOID _sockServiceDiscardSock (GEN_SOCK_CTRL *serviceCtrl,
GEN_SOCK *pSock)
{
GEN_SOCK_CTXT *sockCtx;
sockCtx = pSock->sockCtx;
SOCK_LOG_FLOW2 (sockCtx, "%s: preparing to free GEN_SOCK " S_FMT_PTR ".", pSock->sockIdStr, pSock);
/* The service control is done with this socket, clean it up */
/* See if we need to return a receive buffer to the user */
if (pSock->recvState == RECV_STATE_DATA)
{
pSock->sockData->result = SD_FAILURE;
(*pSock->sockCfg.uSockRx)(pSock, pSock->sockData);
}
/* If the socket has not been closed, time to do so */
/* protect numActive, numSock, sockList */
S_LOCK_UTIL_RESOURCES ();
/* Dec the active socket count for a called socket. Note that the */
/* listen socket will not be free'd until numActive = 0 */
if (pSock->role == GS_ROLE_CALLED && pSock->listenSocket)
--pSock->listenSocket->numActive;
list_unlink (&serviceCtrl->sockList, pSock);
pSock->serviceCtrl = NULL;
--serviceCtrl->numSock;
/* See if the user needs to be told that the socket is closed */
if (pSock->usrCloseCalled == SD_FALSE)
{
pSock->usrCloseCalled = SD_TRUE;
if (pSock->sockCfg.secDisconnectProc == NULL)
{
SOCK_LOG_FLOW1 (sockCtx, "%s: calling uSockDisconnect()",pSock->sockIdStr);
(*pSock->sockCfg.uSockDisconnect)(pSock);
}
else
{
SOCK_LOG_FLOW1 (sockCtx, "%s: calling secDisconnectProc()", pSock->sockIdStr);
(*pSock->sockCfg.secDisconnectProc)(pSock);
}
}
S_UNLOCK_UTIL_RESOURCES ();
}
/************************************************************************/
/* _sockAccept */
/************************************************************************/
static ST_RET _sockAccept (GEN_SOCK *pListenSock)
{
GEN_SOCK_CTXT *sockCtx = pListenSock->sockCtx;
GEN_SOCK *pSock;
SOCKET hNewSock;
ST_BOOLEAN okToAccept;
ST_INT rc = SD_SUCCESS;
SOCK_ADDRLEN callingAddrLen;
SOCKADDR_IN callingAddr;
int err;
/* This accept should succeed immediately */
callingAddrLen = sizeof (callingAddr);
hNewSock = accept (pListenSock->hSock,
(SOCKADDR *) &callingAddr, &callingAddrLen);
if (hNewSock == INVALID_SOCKET)
{
err = SOCKET_ERRORNO;
SOCK_LOG_NERR2 (sockCtx, "%s: socket accept() error (errno=%d)", pListenSock->sockIdStr, err);
if (pListenSock->sockState == GS_STATE_LISTENING)
{
pListenSock->disconnectReason = GS_DISCONNECT_ACCEPT_FAILED;
}
return (SD_FAILURE);
}
#if !defined(_WIN32)
if (hNewSock >= FD_SETSIZE)
{ /* Can't use this socket because illegal to use in "select" call*/
SOCK_LOG_ERR2 (sockCtx, "%s: accept returned socket num %d >= FD_SETSIZE "
"(can not be used in select), closing socket.", pListenSock->sockIdStr, hNewSock);
CLOSE_SOCKET (hNewSock);
return (SD_FAILURE);
}
#endif
if (sockCtx->ctxStatus == GEN_SOCK_CTX_TERMINATING)
{
/* prevent adding new sockets to serviceCtrl */
SOCK_LOG_FLOW1 (sockCtx, "%s: can't accept socket connection, context is terminating", pListenSock->sockIdStr);
CLOSE_SOCKET (hNewSock);
return (SD_FAILURE);
}
/* Got a connection, see if we are still listening ... */
SOCK_LOG_FLOW4 (sockCtx, "%s: accepted connection (socket=%d) from IP Address=%s Port=%u",
pListenSock->sockIdStr, hNewSock,
inet_ntoa (callingAddr.sin_addr), (ST_UINT) ntohs (callingAddr.sin_port));
/* protect numActive */
S_LOCK_UTIL_RESOURCES ();
if (pListenSock->maxActive != 0 && (pListenSock->numActive >= pListenSock->maxActive))
okToAccept = SD_FALSE;
else
okToAccept = SD_TRUE;
S_UNLOCK_UTIL_RESOURCES ();
if (okToAccept == SD_FALSE)
{
SOCK_LOG_FLOW2 (sockCtx, "%s: cannot process new socket connection, reached maxActive=%d socket connections",
pListenSock->sockIdStr, pListenSock->maxActive);
CLOSE_SOCKET (hNewSock);
return (SD_FAILURE);
}
/* OK, we have a go ... */
pSock = _sockAllocSock (sockCtx, GS_ROLE_CALLED, GS_STATE_CONNECTED,
hNewSock, &pListenSock->sockCfg);
pSock->listenSocket = pListenSock;
pSock->callingAddrLen = callingAddrLen;
pSock->callingAddr = callingAddr;
/* add new socket to service list and then call uSockConnect fun, */
/* the sockAddSock may start new thread that will receive data before */
/* the uSockConnect is called, LOCK is needed to prevent this scenario */
S_LOCK_UTIL_RESOURCES ();
rc = _sockAddSock (pSock); /* Add to a service list */
if (rc == SD_SUCCESS)
{
if (pSock->sockCfg.secConnectProc == NULL)
rc = (*pSock->sockCfg.uSockConnectInd)(pSock);
else
rc = (*pSock->sockCfg.secConnectProc)(pSock);
if (rc != SD_SUCCESS)
{
/* user does not want this connection */
pSock->usrCloseCalled = SD_TRUE; /* don't call uSockDisconnect */
sockClose (pSock);
sockFree (pSock);
}
}
else
{
SOCK_LOG_FLOW1 (sockCtx, "%s: closing socket connections", pSock->sockIdStr);
CLOSE_SOCKET (hNewSock);
chk_free (pSock);
}
S_UNLOCK_UTIL_RESOURCES ();
return (SD_SUCCESS);
}
/************************************************************************/
/* _sockCheckRxData */
/* Receive data from the socket and check its validity. */
/* NOTE: caller should close the socket if this function returns error. */
/************************************************************************/
static ST_INT _sockCheckRxData (GEN_SOCK *pSock)
{
ST_INT numRxd;
ST_INT totalSize;
ST_INT bodySize;
ST_INT huntState;
ST_RET rc;
ST_CHAR *rxDest;
ST_INT rxBufSize;
ST_BOOLEAN secDataLeft;
ST_BOOLEAN foundHeader;
GEN_SOCK_CTXT *sockCtx;
sockCtx = pSock->sockCtx;
secDataLeft = SD_FALSE;
do
{
foundHeader = SD_FALSE;
rxDest = pSock->recvBuf+pSock->recvCurrCount;
rxBufSize = pSock->recvDoneCount - pSock->recvCurrCount;
/* Use a non-blocking recv to get what's there */
/* See if we need to pass it to a receive processing subsystem */
if (pSock->sockCfg.secRxProc == NULL)
rc = _sockRecv (pSock, rxDest, rxBufSize, 0, &numRxd);
else
rc = (*pSock->sockCfg.secRxProc) (pSock, rxDest, rxBufSize, 0,
&numRxd, &secDataLeft);
if (rc == SD_SUCCESS)
{
if (numRxd)
{
#ifdef SOCK_FLOW_PRINT /* DEBUG: enable this to see data flow. */
printf (".");
#endif
SOCK_LOG_FLOW2 (sockCtx, "%s: received %d bytes", pSock->sockIdStr, numRxd);
pSock->recvCurrCount += numRxd;
if (pSock->recvDoneCount == pSock->recvCurrCount)
{
/* We got all the data we wanted, see if it is the header or data */
if (pSock->recvState == RECV_STATE_HUNT)
{
huntState = GENSOCK_HUNT_UNDERWAY;
(*pSock->sockCfg.uSockHunt) (pSock, &huntState,
pSock->recvBuf, pSock->recvCurrCount, &bodySize);
if (huntState == GENSOCK_HUNT_DONE)
{
/* OK, the hunt is over and we have the length of the buffer to read */
totalSize = pSock->sockCfg.hdrSize + bodySize;
SOCK_LOG_FLOWC2 (sockCtx, "%s: hunt complete, expecting %d more bytes", pSock->sockIdStr, bodySize);
(*pSock->sockCfg.uSockRxBufAlloc) (pSock, totalSize, &pSock->sockData);
pSock->sockData->dataLen = totalSize;
memcpy (pSock->sockData->data, pSock->recvBuf, pSock->sockCfg.hdrSize);
if (bodySize)
{
pSock->recvState = RECV_STATE_DATA;
pSock->recvBuf = (ST_CHAR *) pSock->sockData->data + pSock->sockCfg.hdrSize;
pSock->recvCurrCount = 0;
pSock->recvDoneCount = bodySize;
foundHeader = SD_TRUE;
}
else /* No body, just header */
{
++pSock->sockStats.numRecv;
/* Give the data to the user... */
pSock->sockData->result = SD_SUCCESS;
(*pSock->sockCfg.uSockRx)(pSock, pSock->sockData);
/* Now hunt for the next */
pSock->recvState = RECV_STATE_HUNT;
pSock->recvDoneCount = pSock->sockCfg.hdrSize;
pSock->recvCurrCount = 0;
pSock->recvBuf = pSock->hdrBuf;
}
}
else if (huntState == GENSOCK_HUNT_RESET)
{
huntState = GENSOCK_HUNT_UNDERWAY;
pSock->recvCurrCount = 0;
}
else if (huntState == GENSOCK_HUNT_DISCONNECT)
{ /* beginning of packet is invalid */
pSock->recvCurrCount = 0;
rc = SD_FAILURE; /* this should cause an immediate disconnect*/
}
}
else /* Not hunting, state is RECV_STATE_DATA */
{
SOCK_LOG_FLOWC1 (sockCtx, "%s: got body", pSock->sockIdStr);
++pSock->sockStats.numRecv;
/* Give the data to the user... */
pSock->sockData->result = SD_SUCCESS;
(*pSock->sockCfg.uSockRx)(pSock, pSock->sockData);
/* Now hunt for the next */
pSock->recvState = RECV_STATE_HUNT;
pSock->recvDoneCount = pSock->sockCfg.hdrSize;
pSock->recvCurrCount = 0;
pSock->recvBuf = pSock->hdrBuf;
}
} /* Got all expected data */
} /* Got some data */
}
} while (rc == SD_SUCCESS && (secDataLeft == SD_TRUE || foundHeader == SD_TRUE));
return (rc);
}
/************************************************************************/
/* _sockRecv */
/* Receive up to "maxRx" bytes from the socket. */
/* NOTE: caller should close the socket if this function returns error. */
/************************************************************************/
ST_RET _sockRecv (GEN_SOCK *pSock, ST_CHAR *dest,
ST_INT maxRx, ST_INT flags, ST_INT *rxCountOut)
{
ST_INT recvRet;
ST_RET retVal;
int err;
GEN_SOCK_CTXT *sockCtx;
sockCtx = pSock->sockCtx;
/* All socketa are non-blocking, so recv will NOT block. */
recvRet = (ST_INT) recv (pSock->hSock, dest, maxRx, flags);
if (recvRet > 0)
{
*rxCountOut = recvRet;
/* save the time of last successful data transfer activity on the socket */
if (sockCtx->maxIdleTime > 0)
pSock->sockStats.lastActivityTime = sGetMsTime();
return (SD_SUCCESS);
}
/* Not a clean receive, see if we have a disconnect */
if (recvRet == 0)
{
pSock->disconnectReason = GS_DISCONNECT_CLOSED;
SOCK_LOG_FLOW1 (sockCtx, "%s: Socket disconnect detected by recv()", pSock->sockIdStr);
return (SD_FAILURE);
}
/* Some kind of error */
err = SOCKET_ERRORNO;
switch (err) /* See if recoverable */
{
case SOCK_WOULDBLOCK:
case SOCK_INTR:
/* case SOCK_TIMEDOUT: RRRRRRRRRRRRRRRRRRRRRRRRR*/
case SOCK_INPROGRESS: /* Seen for Solaris 8 */
*rxCountOut = 0;
retVal = SD_SUCCESS;
break;
default:
/* if(err==SOCK_TIMEDOUT) ͨѶ<CDA8><D1B6>ʱ 20160617 */
//logprint("SOCK RECV FAILED ERRORNO=%d(IP:%s)",err,inet_ntoa(pSock->callingAddr.sin_addr));
/*
ETIMEDOUT<55><54>ͼ<EFBFBD><CDBC><EFBFBD>ߵIJ<DFB5><C4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>޶<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>δ<EFBFBD><CEB4><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6>
ENETUNREACH<43>޷<EFBFBD><DEB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݰ<EFBFBD><DDB0><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
SOCK_LOG_FLOW2 (sockCtx, "%s: Socket error detected by recv() errno=%d", pSock->sockIdStr, err);
pSock->disconnectReason = GS_DISCONNECT_RECV_FAILED;
retVal = SD_FAILURE;
break;
}
return (retVal);
}
/************************************************************************/
/* _sockAllocSock */
/************************************************************************/
GEN_SOCK *_sockAllocSock (GEN_SOCK_CTXT *sockCtx,
ST_INT role, ST_INT sockState,
SOCKET hSock, GEN_SOCK_CONFIG *sockCfg)
{
static ST_UINT sockId = 0; /* give diff id to each socket */
GEN_SOCK *pSock;
#if defined(__hpux) || defined(_AIX) || defined(sun) || defined(linux)
int nonblock_on=1; /* CRITICAL: must be non-zero to enable non-blocking*/
#else
/* _WIN32 */
ST_ULONG nonblock_on=1; /* CRITICAL: must be non-zero to enable non-blocking*/
#endif
int sRet;
#if !defined(_WIN32)
assert (hSock < FD_SETSIZE); /* this should have already been checked*/
#endif
/* Allocate enough room for the header too */
/* 0 is OK for backward compatability */
if (sockCfg->hdrAllocSize < sockCfg->hdrSize)
{
SOCK_LOG_FLOW1 (sockCtx, "Setting hdrAllocSize = %d", sockCfg->hdrSize);
sockCfg->hdrAllocSize = sockCfg->hdrSize;
}
/* Sanity checks */
if ((sockCfg->hdrAllocSize > GENSOCK_MAX_HEADER_SIZE) ||
(sockCfg->hdrAllocSize < 0) ||
(sockCfg->hdrSize < 0))
{
assert (0); /* these must be set correctly before now. */
}
pSock = (GEN_SOCK *) chk_calloc (1, sizeof (GEN_SOCK) + sockCfg->hdrAllocSize);
pSock->hdrBuf = (ST_CHAR *) (pSock+1);
pSock->sockId = ++sockId; /* assign different gensock2 Id number to each socket */
if (pSock->sockId == 0)
++sockId;
sprintf (pSock->sockIdStr, "%s sockId=%5.5u%s", sockCtx->ctxName, pSock->sockId, (role == GS_ROLE_LISTENING ? "L" : ""));
pSock->sockCtx = sockCtx;
pSock->hSock = hSock;
pSock->role = role;
pSock->sockCfg = *sockCfg; /* Copy socket config */
if (sockCfg->setSockOpts)
{
if (role == GS_ROLE_LISTENING)
{ /* set REUSEADDR option ONLY if Listen socket */
sRet = setsockopt (hSock, SOL_SOCKET, SO_REUSEADDR,
(ST_CHAR *) &sockCfg->reuseAddr, sizeof(sockCfg->reuseAddr));
}
else
{ /* set all other options ONLY if NOT Listen socket */
sRet = setsockopt (hSock, IPPROTO_TCP, TCP_NODELAY,
(ST_CHAR *) &sockCfg->noDelay, sizeof(sockCfg->noDelay));
sRet = setsockopt (hSock, SOL_SOCKET, SO_KEEPALIVE,
(ST_CHAR *) &sockCfg->keepAlive, sizeof(sockCfg->keepAlive));
if (sockCfg->rcvBufSize > 0)
{
sRet = setsockopt (hSock, SOL_SOCKET, SO_RCVBUF,
(ST_CHAR *) &sockCfg->rcvBufSize, sizeof(sockCfg->rcvBufSize));
}
if (sockCfg->sndBufSize > 0)
{
sRet = setsockopt (hSock, SOL_SOCKET, SO_SNDBUF,
(ST_CHAR *) &sockCfg->sndBufSize, sizeof(sockCfg->sndBufSize));
}
}
}
pSock->sockState = sockState;
/* Make the socket non-blocking */
sRet = ioctlsocket (pSock->hSock, FIONBIO, &nonblock_on);
pSock->sockStats.createdTime = time (NULL);
pSock->sockStats.lastActivityTime = sGetMsTime();
SOCK_LOG_FLOW3 (sockCtx, "%s: allocated GEN_SOCK " S_FMT_PTR ", socket=%d.",
pSock->sockIdStr, pSock, pSock->hSock);
return (pSock);
}
/************************************************************************/
/* _sockAddSock */
/************************************************************************/
ST_RET _sockAddSock (GEN_SOCK *pSock)
{
GEN_SOCK_CTXT *sockCtx = pSock->sockCtx;
GEN_SOCK_CTRL *serviceCtrl;
ST_RET rc = SD_SUCCESS;
/* protect numActive, sockServiceList, numSock, sockList */
S_LOCK_UTIL_RESOURCES ();
/* Set receive mode to start hunting ... not needed for listen socks */
pSock->recvState = RECV_STATE_HUNT;
pSock->recvDoneCount = pSock->sockCfg.hdrSize;
pSock->recvCurrCount = 0;
pSock->recvBuf = pSock->hdrBuf;
/* Find a service thread with capacity */
serviceCtrl = sockCtx->sockServiceList;
while (serviceCtrl != NULL)
{
if (serviceCtrl->numSock < GS_MAX_SOCK_PER_SERVICE)
break;
serviceCtrl = (GEN_SOCK_CTRL *) list_get_next (sockCtx->sockServiceList, serviceCtrl);
}
#if defined(GENSOCK_THREAD_SUPPORT)
if (serviceCtrl == NULL)
{
/* UNIX/Linux note: theoretically we should never need to add new */
/* thread when GS_MAX_SOCK_PER_SERVICE is (FD_SETSIZE - 1) */
/* add new service control (it will exist until the sockEnd() is called) */
serviceCtrl = _sockAddServiceCtrl (sockCtx);
//printf("_sockAddServiceThread 2...\n");
rc = _sockAddServiceThread (serviceCtrl);
if (rc != SD_SUCCESS)
{
list_unlink (&sockCtx->sockServiceList, serviceCtrl);
chk_free (serviceCtrl);
pSock->disconnectReason = GS_DISCONNECT_INTERNAL_ERROR;
}
}
#else /* !defined(GENSOCK_THREAD_SUPPORT) */
if (serviceCtrl == NULL)
{
/* list empty or we reached max numSock */
SOCK_LOG_NERR2 (sockCtx, "%s: Can't add GEN_SOCK to list (limit reached %d sockets)",
pSock->sockIdStr, GS_MAX_SOCK_PER_SERVICE);
rc = SD_FAILURE;
pSock->disconnectReason = GS_DISCONNECT_RESOURCES_ERROR;
}
#endif
if (rc == SD_SUCCESS)
{
if (pSock->role == GS_ROLE_CALLED && pSock->listenSocket)
++pSock->listenSocket->numActive;
/* Add to the tracking list */
list_add_last (&serviceCtrl->sockList, pSock);
pSock->serviceCtrl = serviceCtrl;
++serviceCtrl->numSock;
sockServiceWake (serviceCtrl);
SOCK_LOG_FLOW1 (sockCtx, "%s: Added GEN_SOCK to service list", pSock->sockIdStr);
}
else
SOCK_LOG_FLOW2 (sockCtx, "%s: Add GEN_SOCK to service list failed (error=%d)", pSock->sockIdStr, rc);
S_UNLOCK_UTIL_RESOURCES ();
return (rc);
}
/************************************************************************/
/************************************************************************/
/* POLLING MODEL SPECIFIC */
/************************************************************************/
/* sockServiceAll */
/************************************************************************/
#if !defined(GENSOCK_THREAD_SUPPORT)
/* For use in polled environment */
ST_VOID sockServiceAll (GEN_SOCK_CTXT *sockCtx, ST_LONG timeOut)
{
GEN_SOCK_CTRL *serviceCtrl;
serviceCtrl = sockCtx->sockServiceList;
while (serviceCtrl != NULL)
{
sockCtrlService (serviceCtrl, timeOut);
serviceCtrl = (GEN_SOCK_CTRL *) list_get_next (sockCtx->sockServiceList, serviceCtrl);
}
}
#endif /* !defined(GENSOCK_THREAD_SUPPORT) */
/************************************************************************/
/* End of polling specific functions */
/************************************************************************/
/****************************************/
/* THREAD MODEL SPECIFIC */
/****************************************/
#if defined(GENSOCK_THREAD_SUPPORT)
/************************************************************************/
/* _sockAddServiceThread */
/************************************************************************/
static ST_RET _sockAddServiceThread (GEN_SOCK_CTRL *serviceCtrl)
{
ST_RET rc = SD_SUCCESS;
GEN_SOCK_CTXT *sockCtx = serviceCtrl->sockCtx;
SOCK_LOG_FLOW1 (sockCtx, "%s: in sockAddServiceThread()", sockCtx->ctxName);
serviceCtrl->serviceEvent = gs_get_event_sem (SD_FALSE);
if (!serviceCtrl->serviceEvent)
{
SOCK_LOG_ERR1 (sockCtx, "%s: could not get service event", sockCtx->ctxName);
return (SD_FAILURE);
}
/* Create a set of wakeup sockets for this service control */
rc = sockCreateWakeupSockets (sockCtx, sockCtx->gs_wakeup_port, 100,
&serviceCtrl->wakeupPort,
&serviceCtrl->xCallingSock, &serviceCtrl->xCalledSock);
if (rc != SD_SUCCESS)
{
gs_free_event_sem (serviceCtrl->serviceEvent);
serviceCtrl->serviceEvent = NULL;
return (rc);
}
/* start Service thread */
rc = gs_start_thread (_sockServiceThread, serviceCtrl,
&serviceCtrl->thService,
&serviceCtrl->tIdService);
if (rc != SD_SUCCESS)
{
SOCK_LOG_ERR2 (sockCtx, "%s: could not start Service thread error=%d", sockCtx->ctxName, rc);
gs_free_event_sem (serviceCtrl->serviceEvent);
serviceCtrl->serviceEvent = NULL;
if (serviceCtrl->xCallingSock)
{
CLOSE_SOCKET (serviceCtrl->xCallingSock);
serviceCtrl->xCallingSock = 0;
}
if (serviceCtrl->xCalledSock)
{
CLOSE_SOCKET (serviceCtrl->xCalledSock);
serviceCtrl->xCalledSock = 0;
}
rc = SD_FAILURE;
}
return (rc);
}
/************************************************************************/
/* _sockServiceThread */
/************************************************************************/
static ST_THREAD_RET ST_THREAD_CALL_CONV _sockServiceThread (ST_THREAD_ARG pArg)
{
GEN_SOCK_CTRL *serviceCtrl = (GEN_SOCK_CTRL *) pArg;
GEN_SOCK_CTXT *sockCtx = serviceCtrl->sockCtx;
GEN_SOCK *pSock;
ST_INT ret;
SOCK_LOG_FLOW1 (sockCtx, "%s: sockServiceThread started", sockCtx->ctxName);
while (sockCtx->gTerminateService == SD_FALSE)
{
ret = sockCtrlService (serviceCtrl, sockCtx->gs_select_timeout);
switch (ret)
{
case GS_SELECT_NO_ACTIVE_SOCK: /* Nothing on our list */
gs_wait_event_sem (serviceCtrl->serviceEvent, 10000);
break;
case GS_SELECT_ACTIVE: /* Action! */
break;
case GS_SELECT_TIMEOUT: /* No action */
break;
case GS_SELECT_ERROR: /* Error */
gs_wait_event_sem (serviceCtrl->serviceEvent, 1000);
break;
case GS_SELECT_TERMINATED: /* Terminating */
break;
default:
break;
}
} /* While not terminate */
/* Close all sockets associated with the service control */
S_LOCK_UTIL_RESOURCES (); /* CRITICAL: lock all access to sockList*/
while (serviceCtrl->sockList)
{
pSock = serviceCtrl->sockList;
pSock->disconnectReason = GS_DISCONNECT_TERMINATING;
sockClose (pSock);
}
S_UNLOCK_UTIL_RESOURCES (); /* CRITICAL: lock all access to sockList*/
SOCK_LOG_FLOW1 (sockCtx, "%s: sockServiceThread ended", sockCtx->ctxName);
return (0);
// return (ST_THREAD_RET_VAL);
}
/************************************************************************/
/************************************************************************/
/* sockCreateWakeupSockets */
/* This function will create pair of sockets that can be used for */
/* signaling an event. */
/************************************************************************/
ST_RET sockCreateWakeupSockets (GEN_SOCK_CTXT *sockCtx,
ST_UINT16 basePort, ST_UINT portRange,
ST_UINT16 *usedPort,
SOCKET *callingSock, SOCKET *calledSock)
{
ST_UINT16 wakeupPort = basePort;
SOCKET xCallingSock, xCalledSock;
SOCKET hListenSock;
SOCK_ADDRLEN callingAddrLen;
SOCKADDR_IN callingAddr;
#if defined(__hpux) || defined(_AIX) || defined(sun) || defined(linux)
int nonblock_on=1; /* CRITICAL: must be non-zero to enable non-blocking*/
#else
/* _WIN32 */
ST_ULONG nonblock_on=1; /* CRITICAL: must be non-zero to enable non-blocking*/
#endif
struct sockaddr_in localAddr;
ST_INT noDelay;
ST_INT keepAlive;
ST_INT reuseAddr;
ST_UINT i;
int sRet;
int err;
SOCK_LOG_FLOW1 (sockCtx, "%s: in sockCreateWakeupSockets()", sockCtx->ctxName);
/* Step 1: Make a non-blocking listen socket */
hListenSock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (hListenSock == INVALID_SOCKET)
{
SOCK_LOG_ERR1 (sockCtx, "%s: XSocket socket() failed", sockCtx->ctxName);
return (SD_FAILURE);
}
sRet = ioctlsocket (hListenSock, FIONBIO, &nonblock_on);
reuseAddr = 0;
sRet = setsockopt (hListenSock, SOL_SOCKET, SO_REUSEADDR,
(ST_CHAR *) &reuseAddr, sizeof(reuseAddr));
memset((char *)(&localAddr), 0, sizeof(localAddr));
localAddr.sin_family = AF_INET;
localAddr.sin_port = htons (wakeupPort);
localAddr.sin_addr.s_addr = htonl (INADDR_ANY);
/* Try up to the next <portRange> ports in this range */
for (i = 0; i < portRange; ++i)
{
sRet = bind (hListenSock, (struct sockaddr *)&localAddr, sizeof(localAddr));
if (sRet == 0)
{
SOCK_LOG_FLOW2 (sockCtx, "%s: XSocket bind on port=%d", sockCtx->ctxName, (ST_UINT) wakeupPort);
break;
}
err = SOCKET_ERRORNO;
SOCK_LOG_FLOW4 (sockCtx, "%s: XSocket bind() failure on port=%d, errno=%d %s",
sockCtx->ctxName, (ST_UINT) wakeupPort, err,
(err == SOCK_EADDRINUSE) ? "(port in use)" : " ");
wakeupPort++;
localAddr.sin_port = htons(wakeupPort);
sMsSleep (2);
}
/* App may still function if unable to create Wakeup Socket, but let user know with ERR log */
if (sRet != 0)
{
SOCK_LOG_ERR2 (sockCtx, "%s: XSocket bind() failed, errno=%d", sockCtx->ctxName, SOCKET_ERRORNO);
CLOSE_SOCKET (hListenSock);
return (SD_FAILURE);
}
sRet = listen (hListenSock, SOMAXCONN);
if (sRet != 0)
{
SOCK_LOG_ERR2 (sockCtx, "%s: XSocket listen() failed, errno=%d", sockCtx->ctxName, SOCKET_ERRORNO);
CLOSE_SOCKET (hListenSock);
return (SD_FAILURE);
}
/* Step 2: Do a non-blocking connect */
xCallingSock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (xCallingSock == INVALID_SOCKET)
{
SOCK_LOG_ERR1 (sockCtx, "%s: XSocket socket() failed", sockCtx->ctxName);
CLOSE_SOCKET (hListenSock);
return (SD_FAILURE);
}
noDelay = 1;
keepAlive = 0;
sRet = setsockopt (xCallingSock, IPPROTO_TCP, TCP_NODELAY,
(ST_CHAR *) &noDelay, sizeof(noDelay));
sRet = setsockopt (xCallingSock, SOL_SOCKET, SO_KEEPALIVE,
(ST_CHAR *) &keepAlive, sizeof(keepAlive));
/* Set up the socket address */
memset((char *)(&localAddr), 0, sizeof(localAddr));
localAddr.sin_family = AF_INET;
localAddr.sin_addr.s_addr = inet_addr ("127.0.0.1");
localAddr.sin_port = htons (wakeupPort);
/* Make the calling socket non-blocking */
sRet = ioctlsocket (xCallingSock, FIONBIO, &nonblock_on);
/* Do non-blocking connect */
sRet = connect (xCallingSock, (struct sockaddr *)&localAddr, sizeof(localAddr));
if (sRet >= 0)
{
SOCK_LOG_FLOW2 (sockCtx, "%s: XSocket connected on port=%d", sockCtx->ctxName, (ST_UINT) wakeupPort);
}
else
{
sRet = SOCKET_ERRORNO;
if (sRet == SOCK_WOULDBLOCK || sRet == SOCK_INPROGRESS)
{
SOCK_LOG_FLOW1 (sockCtx, "%s: XSocket connection pending", sockCtx->ctxName);
}
else
{
CLOSE_SOCKET (hListenSock);
CLOSE_SOCKET (xCallingSock);
SOCK_LOG_ERR2 (sockCtx, "%s: XSocket connect() failed, errno=%d", sockCtx->ctxName, sRet);
return (SD_FAILURE);
}
}
/* Step 3: Do non-blocking accept */
callingAddrLen = sizeof (callingAddr);
for (i = 0; i < 50; ++i)
{
callingAddrLen = sizeof (callingAddr); /* set for each accept call */
xCalledSock = accept (hListenSock, (SOCKADDR *) &callingAddr, &callingAddrLen);
if (xCalledSock != INVALID_SOCKET)
break;
sMsSleep (2);
}
if (xCalledSock == INVALID_SOCKET)
{
sRet = SOCKET_ERRORNO;
CLOSE_SOCKET (xCallingSock);
CLOSE_SOCKET (hListenSock);
SOCK_LOG_ERR2 (sockCtx, "%s: XSocket accept() failed, errno=%d", sockCtx->ctxName, sRet);
return (SD_FAILURE);
}
SOCK_LOG_FLOW2 (sockCtx, "%s: XSocket accept() successful on port=%d", sockCtx->ctxName, wakeupPort);
noDelay = 1;
keepAlive = 0;
sRet = setsockopt (xCalledSock, IPPROTO_TCP, TCP_NODELAY,
(ST_CHAR *) &noDelay, sizeof(noDelay));
sRet = setsockopt (xCalledSock, SOL_SOCKET, SO_KEEPALIVE,
(ST_CHAR *) &keepAlive, sizeof(keepAlive));
/* Make the called socket non-blocking */
sRet = ioctlsocket (xCalledSock, FIONBIO, &nonblock_on);
CLOSE_SOCKET (hListenSock);
/* wakeup sockets pair connected */
*usedPort = wakeupPort;
*callingSock = xCallingSock;
*calledSock = xCalledSock;
return (SD_SUCCESS);
}
/************************************************************************/
/* End of thread specific functions */
#endif /* #if defined(GENSOCK_THREAD_SUPPORT */
/************************************************************************/
/************************************************************************/
/************************************************************************/
/* sockLogState */
/************************************************************************/
ST_VOID sockLogState (GEN_SOCK_CTXT *sockCtx)
{
GEN_SOCK_CTRL *serviceCtrl;
GEN_SOCK *pSock;
ST_INT serviceCount;
ST_INT sockCount;
S_LOCK_UTIL_RESOURCES ();
SLOGALWAYS1 ("GEN_SOCK STATE for context '%s':", sockCtx->ctxName);
SLOGCALWAYS1 (" Service Control List (%d)", list_get_sizeof (sockCtx->sockServiceList));
serviceCtrl = sockCtx->sockServiceList;
serviceCount = 1;
while (serviceCtrl != NULL)
{
SLOGCALWAYS1 (" %d) Service Control", serviceCount++);
SLOGCALWAYS1 (" %d sockets", serviceCtrl->numSock);
#if defined(GENSOCK_THREAD_SUPPORT)
SLOGCALWAYS3 (" Wakeup Port: %d, xCalledSock: %d xCallingSock: %d",
serviceCtrl->wakeupPort,
serviceCtrl->xCalledSock,
serviceCtrl->xCallingSock);
#endif
sockCount = 1;
pSock = serviceCtrl->sockList;
while (pSock != NULL)
{
SLOGCALWAYS1 (" %d) Socket Control", sockCount++);
sockLogSockState (pSock," ");
pSock = (GEN_SOCK *) list_get_next (serviceCtrl->sockList, pSock);
}
serviceCtrl = (GEN_SOCK_CTRL *) list_get_next (sockCtx->sockServiceList, serviceCtrl);
}
S_UNLOCK_UTIL_RESOURCES ();
}
/************************************************************************/
/* sockLogSockState */
/************************************************************************/
ST_VOID sockLogSockState (GEN_SOCK *pSock, ST_CHAR *prefix)
{
ST_CHAR *str;
if (prefix == NULL)
prefix = "";
switch (pSock->role)
{
case GS_ROLE_CALLED:
str = "Called";
break;
case GS_ROLE_CALLING:
str = "Calling";
break;
case GS_ROLE_LISTENING: /* Not valid */
str = "Lisening";
break;
default:
str = "Invalid";
break;
}
SLOGCALWAYS2 ("%sRole : %s", prefix, str);
switch (pSock->sockState)
{
case GS_STATE_LISTENING :
str = "LISTENING";
break;
case GS_STATE_FAILED_LISTEN :
str = "FAILED LISTEN";
break;
case GS_STATE_STOPPING_LISTEN :
str = "STOPPING_LISTEN";
case GS_STATE_CONNECTING :
str = "CONNECTING";
break;
case GS_STATE_CONNECTED :
str = "CONNECTED";
break;
case GS_STATE_CLOSED :
str = "CLOSED";
break;
default:
str = "Invalid";
break;
}
SLOGCALWAYS2 ("%sState: %s", prefix, str);
str = ctime (&pSock->sockStats.createdTime);
str[24] = 0;
SLOGCALWAYS2 ("%sTime Created: %s", prefix, str);
if (pSock->sockStats.activeTime)
{
str = ctime (&pSock->sockStats.activeTime);
str[24] = 0;
SLOGCALWAYS2 ("%sTime Active: %s", prefix, str);
}
SLOGCALWAYS2 ("%sNum Group Msgs Queued: %d", prefix, pSock->sockTxQueueGroupCnt);
SLOGCALWAYS2 ("%sNum Msgs (RFC1006) Sent: %ld", prefix, pSock->sockStats.numSend);
SLOGCALWAYS2 ("%sNum Msgs (RFC1006) Recv: %ld", prefix, pSock->sockStats.numRecv);
}
/************************************************************************/
/* sockGetRemAddrInfo */
/************************************************************************/
ST_RET sockGetRemAddrInfo (GEN_SOCK *pSock, SOCKADDR_IN *remSockAddrDest,
ST_CHAR **remAddrTxtOut, ST_INT *portOut)
{
SOCKADDR_IN peer;
SOCKADDR_IN *pp;
SOCK_ADDRLEN len;
ST_RET ret;
if (remSockAddrDest)
pp = remSockAddrDest;
else
pp = &peer;
len = sizeof (SOCKADDR_IN);
ret = getpeername (pSock->hSock, (struct sockaddr *) pp, &len);
if (ret == SD_SUCCESS)
{
if (remAddrTxtOut != NULL)
*remAddrTxtOut = inet_ntoa (pp->sin_addr);
if (portOut != NULL)
/* first cast to ST_UINT to prevent sign extension for 0x8000-0xFFFF ports */
*portOut = (ST_INT) ((ST_UINT) ntohs (pp->sin_port));
}
return (ret);
}
/* -------------------------------------------- */
/* User misc */
/* -------------------------------------------- */
/************************************************************************/
/* sockUsrFun */
/*----------------------------------------------------------------------*/
/* This function will call user function for all connections and close */
/* the connection if the user function does not return SD_SUCCESS. */
/* The secCtrl parameter is passed to the user function. */
/************************************************************************/
ST_VOID sockUsrFun (ST_RET (*usrFun)(ST_VOID *secCtrl), ST_CHAR *errMsg)
{
GEN_SOCK_CTXT *sockCtx;
GEN_SOCK_CTRL *serviceCtrl;
GEN_SOCK *pSock;
ST_RET ret;
if (!usrFun)
return;
sockCtx = sockCtxList;
while (sockCtx)
{
SOCK_LOG_FLOW0 (sockCtx, "sockUsrFun");
S_LOCK_UTIL_RESOURCES ();
serviceCtrl = sockCtx->sockServiceList;
while (serviceCtrl != NULL)
{
/* Check all sockets associated with the service control */
pSock = serviceCtrl->sockList;
while (pSock)
{
/* applies only to secured connections */
if (pSock->sockCfg.secCtrl)
{
ret = (*usrFun) (pSock->sockCfg.secCtrl);
if (ret != SD_SUCCESS)
{
SOCK_LOG_ERR2 (sockCtx, "%s: %s, closing socket.", pSock->sockIdStr, errMsg);
sockClose(pSock);
}
}
pSock = (GEN_SOCK *)list_get_next (serviceCtrl->sockList, pSock);
}
serviceCtrl = (GEN_SOCK_CTRL *)list_get_next (sockCtx->sockServiceList, serviceCtrl);
}
S_UNLOCK_UTIL_RESOURCES ();
sockCtx = (GEN_SOCK_CTXT *)list_get_next (sockCtxList, sockCtx);
}
}
/* -------------------------------------------- */
/* Misc socket related functions */
/* -------------------------------------------- */
/************************************************************************/
/* convertIpAddr */
/*----------------------------------------------------------------------*/
/* This function will take pointer to IP address (host string or dotted */
/* notation string) and convert it to unsigned long value. */
/* If the useGetHostByName is SD_TRUE the gethostbyname() function will */
/* be called when the inet_addr(ipAddrStr) produced INADDR_NONE return. */
/* (host name was used or dotted notation was invalid). */
/* RETURN: */
/* ULONG != 0 converted IP Addr to ST_ULONG value or */
/* 0 if function failed */
/* Note: 0.0.0.0 would be invalid because we */
/* return 0 for conversion error. */
/************************************************************************/
ST_ULONG convertIPAddr (ST_CHAR *ipAddrStr, ST_BOOLEAN useGetHostByName)
{
ST_ULONG ipAddr = 0;
ST_CHAR *dotPtr;
#ifdef _WIN32
/* init WinSock interface */
static ST_BOOLEAN bWSAStarted = SD_FALSE;
WSADATA wsaData;
ST_INT wRet;
/* make sure sockets initialized before we call any socket functions */
if (!bWSAStarted)
{
if (wRet = WSAStartup(0x0202, &wsaData))
{
SLOGALWAYS1 ("convertIPAddr: unable to initialize WinSock interface to use version 2.2 (error=%d)", wRet);
return (ipAddr);
}
bWSAStarted = SD_TRUE;
}
#endif /* _WIN32 */
if (ipAddrStr == NULL || strlen(ipAddrStr) == 0)
{
SLOGALWAYS0 ("convertIPAddr: conversion failed, ipAddrStr=NULL or ipAddrStr is empty");
return (ipAddr);
}
/* Since inet_addr() considers following addresses valid:
a.b.c.d (Internet addr)
a.b.c (Class B addr)
a.b (Class A addr)
a stored directly
we will pass to inet_addr only valid ipAddrStr in form of Internet Addr */
/* call inet_addr if we find 3 '.' in the ipAddrStr (and do not use strtok) */
if ((dotPtr = strstr(ipAddrStr, ".")) != NULL)
if ((dotPtr+1 < ipAddrStr+strlen(ipAddrStr)) && (dotPtr = strstr(dotPtr+1, ".")) != NULL)
if ((dotPtr+1 < ipAddrStr+strlen(ipAddrStr)) && (dotPtr = strstr(dotPtr+1, ".")) != NULL)
{
ipAddr = (ST_ULONG) inet_addr (ipAddrStr);
/* NOTE: some systems return from the inet_addr() unsigned int (LINUX) */
/* and some return unsigned long (Windows). */
}
if (ipAddr == 0 || ipAddr == htonl(INADDR_NONE))
{
#if !defined (VXWORKS) /* gethostbyname not supported */
if (useGetHostByName)
{
struct hostent *pHostEnt = NULL; /* host database entry for remote host */
/* UNIX IEEE: the behavior of gethostbyname() when passed a numeric */
/* address string is unspecified */
/* DEBUG: should we check for it? */
pHostEnt = gethostbyname(ipAddrStr);
if (pHostEnt != NULL)
ipAddr = (ST_ULONG) (*(ST_UINT32 *)(pHostEnt->h_addr));
else
{
ipAddr = 0;
SLOGALWAYS2 ("convertIPAddr : gethostbyname IPAddr='%s'conversion errno=%d",
ipAddrStr, SOCKET_ERRORNO);
}
}
else
#endif /* !defined (VXWORKS) */
{
ipAddr = 0;
SLOGALWAYS1 ("convertIPAddr : IPAddr='%s'conversion error", ipAddrStr);
}
}
return (ipAddr);
}
/************************************************************************/
/* sockEventPut */
/* Put socket event on list. This should be called from callback */
/* functions to save events on the list and return immediately. Other */
/* threads can get events from the list later and process them. */
/************************************************************************/
ST_VOID sockEventPut (GEN_SOCK_CTXT *sockCtx, GEN_SOCK_EVENT *sockEvent)
{
S_LOCK_UTIL_RESOURCES ();
list_add_last (&sockCtx->sockEventList, sockEvent);
sockCtx->sockEventCount++;
S_UNLOCK_UTIL_RESOURCES ();
}
/************************************************************************/
/* sockEventGet */
/* Get next socket event from list (to process the event). */
/************************************************************************/
int sockEventGet_pri=0;
GEN_SOCK_EVENT *sockEventGet (GEN_SOCK_CTXT *sockCtx)
{
GEN_SOCK_EVENT *sockEvent;
S_LOCK_UTIL_RESOURCES ();
sockEvent = (GEN_SOCK_EVENT *)list_get_first (&sockCtx->sockEventList);
if (sockEvent)
{
if(sockEventGet_pri)
printf("sockEvent->eventType=%d sockEventCount=%d\r\n",sockEvent->eventType,sockCtx->sockEventCount);
sockCtx->sockEventCount--;
}
S_UNLOCK_UTIL_RESOURCES ();
return (sockEvent);
}
/************************************************************************/
/* sockEventQueueFlush */
/************************************************************************/
ST_VOID sockEventQueueFlush (GEN_SOCK_CTXT *sockCtx, GEN_SOCK *pSock)
{
GEN_SOCK_EVENT *sockEvent;
GEN_SOCK_EVENT *nextSockEvent;
S_LOCK_UTIL_RESOURCES ();
sockEvent = (GEN_SOCK_EVENT *) sockCtx->sockEventList;
while (sockEvent)
{
nextSockEvent = (GEN_SOCK_EVENT *) list_get_next (sockCtx->sockEventList, sockEvent);
if (sockEvent->pSock == pSock)
{
list_unlink (&sockCtx->sockEventList, sockEvent);
chk_free (sockEvent);
}
sockEvent = nextSockEvent;
}
S_UNLOCK_UTIL_RESOURCES ();
}