2815 lines
95 KiB
C
2815 lines
95 KiB
C
|
|
/************************************************************************/
|
|||
|
|
/* 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<EFBFBD><EFBFBD>ͼ<EFBFBD><EFBFBD><EFBFBD>ߵIJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD>
|
|||
|
|
ENETUNREACH<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݰ<EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><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 ();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|