/************************************************************************/ /* 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 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 网络存活时间 */ sockopt_on = 1; /* 是否启用KEEPALIVE */ keep_idle = 30; /* 当没有数据包传输后,等多少秒开始KEEPALIVE */ keep_interval = 5; /* 发送KEEPALIVE包的时间间隔 */ keep_count = 5; /* 连续多少个KEEPALIVE包没应答就断开TCP连接 */ 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 或 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 测试*/ 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) 通讯超时 20160617 */ //logprint("SOCK RECV FAILED ERRORNO=%d(IP:%s)",err,inet_ntoa(pSock->callingAddr.sin_addr)); /* ETIMEDOUT企图连线的操作超过限定时间仍未有响应。 ENETUNREACH无法传送数据包至指定的主机。 */ 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 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 (); }