ANSC_STATUS AnscDeuoStop ( ANSC_HANDLE hThisObject ) { ANSC_STATUS returnStatus = ANSC_STATUS_SUCCESS; PANSC_DAEMON_ENGINE_UDP_OBJECT pMyObject = (PANSC_DAEMON_ENGINE_UDP_OBJECT)hThisObject; if ( !pMyObject->bStarted ) { return ANSC_STATUS_SUCCESS; } else { pMyObject->bStarted = FALSE; } AnscWaitEvent(&pMyObject->RecvEvent, ANSC_DEUO_TASK_CLEANUP_TIME); AnscWaitEvent(&pMyObject->SendEvent, ANSC_DEUO_TASK_CLEANUP_TIME); pMyObject->Reset((ANSC_HANDLE)pMyObject); return ANSC_STATUS_SUCCESS; }
ANSC_STATUS AnscSctoInitTlsClient ( ANSC_HANDLE hThisObject ) { ANSC_STATUS returnStatus = ANSC_STATUS_SUCCESS; PANSC_SIMPLE_CLIENT_TCP_OBJECT pMyObject = (PANSC_SIMPLE_CLIENT_TCP_OBJECT)hThisObject; PANSC_SCTO_WORKER_OBJECT pWorker = (PANSC_SCTO_WORKER_OBJECT )pMyObject->hWorker; PTLS_SCS_INTERFACE pTlsScsIf = (PTLS_SCS_INTERFACE )pMyObject->hTlsScsIf; PTLS_TSA_INTERFACE pTlsTsaIf = (PTLS_TSA_INTERFACE )pMyObject->hTlsTsaIf; TLS_CONNECTION_PARAMS tlsConnParams; if ( !pMyObject->bTlsEnabled || !pTlsScsIf ) { return ANSC_STATUS_UNAPPLICABLE; } if ( TRUE ) { TlsInitConnParams((&tlsConnParams)); tlsConnParams.bSessionSharing = TRUE; tlsConnParams.bQuickHandshake = TRUE; tlsConnParams.bReqCertificate = FALSE; tlsConnParams.bTlsClient = TRUE; tlsConnParams.HostID = pMyObject->HostAddress.Value; tlsConnParams.PeerID = pMyObject->PeerAddress.Value; tlsConnParams.SessionIDSize = 0; tlsConnParams.CipherSuiteCount = 0; tlsConnParams.CompressionCount = 0; } pMyObject->hTlsConnection = pTlsScsIf->CreateConnection ( pTlsScsIf->hOwnerContext, (ANSC_HANDLE)pTlsTsaIf ); if ( !pMyObject->hTlsConnection ) { return ANSC_STATUS_UNAPPLICABLE; } else { returnStatus = pTlsScsIf->ConfigConnection ( pTlsScsIf->hOwnerContext, pMyObject->hTlsConnection, (ANSC_HANDLE)&tlsConnParams ); } AnscResetEvent(&pMyObject->TlsConnEvent); returnStatus = pTlsScsIf->StartConnection ( pTlsScsIf->hOwnerContext, pMyObject->hTlsConnection ); if ( returnStatus == ANSC_STATUS_SUCCESS ) { AnscWaitEvent(&pMyObject->TlsConnEvent, 0xFFFFFFFF); } if ( !pMyObject->bTlsConnected ) { returnStatus = pTlsScsIf->RemoveConnection ( pTlsScsIf->hOwnerContext, pMyObject->hTlsConnection ); pMyObject->hTlsConnection = (ANSC_HANDLE)NULL; returnStatus = ANSC_STATUS_FAILURE; } else { returnStatus = ANSC_STATUS_SUCCESS; } return returnStatus; }
ANSC_STATUS AnscDstoCancel ( ANSC_HANDLE hThisObject ) { ANSC_STATUS returnStatus = ANSC_STATUS_SUCCESS; PANSC_DAEMON_SERVER_TCP_OBJECT pMyObject = (PANSC_DAEMON_SERVER_TCP_OBJECT)hThisObject; PANSC_DSTO_WORKER_OBJECT pWorker = (PANSC_DSTO_WORKER_OBJECT )pMyObject->hWorker; if ( !pMyObject->bActive ) { return ANSC_STATUS_SUCCESS; } else if ( !pWorker ) { return ANSC_STATUS_UNAPPLICABLE; } else { pWorker->Unload(pWorker->hWorkerContext); pMyObject->bActive = FALSE; } if ( ((pMyObject->Socket != XSKT_SOCKET_INVALID_SOCKET) && (pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET)) || ((pMyObject->Socket != ANSC_SOCKET_INVALID_SOCKET) && !(pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET)) ) { if ( pMyObject->Mode & ANSC_DSTO_MODE_POLLING_ACCEPT ) { AnscWaitEvent(&pMyObject->AcceptEvent, ANSC_DSTO_TASK_CLEANUP_TIME); if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET ) { _xskt_shutdown (pMyObject->Socket, XSKT_SOCKET_SD_BOTH); _xskt_closesocket(pMyObject->Socket); } else { _ansc_shutdown (pMyObject->Socket, ANSC_SOCKET_SD_BOTH); _ansc_closesocket(pMyObject->Socket); } } else { if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET ) { _xskt_shutdown (pMyObject->Socket, XSKT_SOCKET_SD_BOTH); _xskt_closesocket(pMyObject->Socket); } else { _ansc_shutdown (pMyObject->Socket, ANSC_SOCKET_SD_BOTH); _ansc_closesocket(pMyObject->Socket); } AnscWaitEvent(&pMyObject->AcceptEvent, ANSC_DSTO_TASK_CLEANUP_TIME); } } pMyObject->StopEngines ((ANSC_HANDLE)pMyObject); pMyObject->DestroyEnginePool((ANSC_HANDLE)pMyObject); pMyObject->DestroySocketPool((ANSC_HANDLE)pMyObject); /* * The underlying socket wrapper may require an explicit cleanup() call, such is the case on * Microsoft windows platforms. The wrapper initialization has to done for each task. On most * real-time operating systems, this call is not required. */ if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET ) { AnscCleanupXsocketWrapper((ANSC_HANDLE)pMyObject); } else { AnscCleanupSocketWrapper((ANSC_HANDLE)pMyObject); } pMyObject->Reset((ANSC_HANDLE)pMyObject); return ANSC_STATUS_SUCCESS; }
ANSC_STATUS BbhmDiageoResultQueryTask ( ANSC_HANDLE hThisObject ) { ANSC_STATUS returnStatus = ANSC_STATUS_SUCCESS; PBBHM_DIAG_EXEC_OBJECT pMyObject = (PBBHM_DIAG_EXEC_OBJECT )hThisObject; PDSLH_DIAG_INFO_BASE pDiagInfo = NULL; BOOLEAN bQueryDone = FALSE; AnscTraceFlow(("BbhmDiageoResultQueryTask ...\n")); do { returnStatus = pMyObject->RetrieveResult((ANSC_HANDLE)pMyObject); if ( returnStatus == ANSC_STATUS_SUCCESS ) { pDiagInfo = (PDSLH_DIAG_INFO_BASE)pMyObject->hDslhDiagInfo; bQueryDone = TRUE; if ( (pDiagInfo->DiagnosticState != DSLH_DIAG_STATE_TYPE_Inprogress) && (pDiagInfo->DiagnosticState != DSLH_DIAG_STATE_TYPE_Requested) ) { pMyObject->ResultTimestamp = AnscGetTickInSeconds(); break; } } else { /* internal error occurs, quit immediatelly */ break; } AnscWaitEvent(&pMyObject->ResultQueryEvent, 1000); } while ( pMyObject->bResultQueryRunning ); if ( TRUE/*pDiagInfo->RequestType == DSLH_DIAGNOSTIC_REQUEST_TYPE_Acs*/ ) { /* Always notify the initiator */ CcspTraceInfo(("BbhmDiageoResultQueryTask -- notify initiator.....\n")); /* send out the notification */ if ( ANSC_STATUS_SUCCESS != CosaSendDiagCompleteSignal() ) { AnscTraceWarning(("Failed to send event for diagnostics completion.\n")); } } AnscAcquireLock(&pMyObject->AccessLock); AnscTraceFlow(("BbhmDiageoResultQueryTask -- quiting...\n")); /* * stop the diagnostic process */ pMyObject->bResultQueryRunning = FALSE; if ( !bQueryDone ) { pMyObject->StopDiag((ANSC_HANDLE)pMyObject); } AnscSetEvent(&pMyObject->ResultQueryExitEvent); AnscReleaseLock(&pMyObject->AccessLock); AnscTraceFlow(("BbhmDiageoStartDiag -- exit...\n")); return ANSC_STATUS_SUCCESS; }
ANSC_STATUS AnscDetoRecvTask ( ANSC_HANDLE hThisObject ) { ANSC_STATUS returnStatus = ANSC_STATUS_SUCCESS; PANSC_DAEMON_ENGINE_TCP_OBJECT pMyObject = (PANSC_DAEMON_ENGINE_TCP_OBJECT)hThisObject; PANSC_DAEMON_SERVER_TCP_OBJECT pServer = (PANSC_DAEMON_SERVER_TCP_OBJECT)pMyObject->hDaemonServer; PANSC_DSTO_WORKER_OBJECT pWorker = (PANSC_DSTO_WORKER_OBJECT )pServer->hWorker; #if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX) ansc_fd_set* pRecvSet1 = (ansc_fd_set* )pMyObject->RecvSocketSet; xskt_fd_set* pRecvSet2 = (xskt_fd_set* )pMyObject->RecvSocketSet; #endif PANSC_DAEMON_SOCKET_TCP_OBJECT pSocket = NULL; ULONG ulLastCleanAt = AnscGetTickInSecondsAbs(); ANSC_SOCKET s_socket = ANSC_SOCKET_INVALID_SOCKET; int s_result = 0; int s_result_excp = 0; int s_error = 0; int i = 0; #if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX) ansc_fd_set* read_fd_set1 = NULL; xskt_fd_set* read_fd_set2 = NULL; ansc_fd_set* excp_fd_set1 = NULL; xskt_fd_set* excp_fd_set2 = NULL; ansc_timeval timeval1; xskt_timeval timeval2; #endif AnscTrace("AnscDetoRecvTask is activated ...!\n"); #if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX) read_fd_set1 = (ansc_fd_set*)AnscAllocateMemory(sizeof(ansc_fd_set)); read_fd_set2 = (xskt_fd_set*)AnscAllocateMemory(sizeof(xskt_fd_set)); excp_fd_set1 = (ansc_fd_set*)AnscAllocateMemory(sizeof(ansc_fd_set)); excp_fd_set2 = (xskt_fd_set*)AnscAllocateMemory(sizeof(xskt_fd_set)); if ( !read_fd_set1 || !read_fd_set2 || !excp_fd_set1 || !excp_fd_set2 ) { goto EXIT1; } #endif /* * As a scalable server implemention, we shall accept as many incoming client connections as * possible and can only be limited by the system resources. Once the listening socket becomes * readable, which means an incoming connection attempt has arrived. We create a new socket * object and associate it with the client. This is a repeated process until the socket owner * closes the socket. */ while ( pMyObject->bStarted ) { ANSC_COMMIT_TASK(); /* * To avoid letting the old half-dead sockets hogging up the system resource, we need to * periodically invoke the cleaning routine. The default interval is 10 seconds, and the * idle timeout value is 90 seconds. */ #if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX) if ( pMyObject->bCleaningDemanded ) #else if ( FALSE ) /*if ( pMyObject->bCleaningDemanded )*/ #endif { pMyObject->Clean((ANSC_HANDLE)pMyObject); ulLastCleanAt = AnscGetTickInSecondsAbs(); pMyObject->bCleaningDemanded = FALSE; } else if ( (AnscGetTickInSecondsAbs() - ulLastCleanAt) >= ANSC_DETO_CLEAN_TASK_INTERVAL ) { pMyObject->Clean((ANSC_HANDLE)pMyObject); ulLastCleanAt = AnscGetTickInSecondsAbs(); pMyObject->bCleaningDemanded = FALSE; } /* * Since the original bsd compatible socket api doesn't support asynchronous operation, the * nonblocking status polling is the best we can get. As a matter of fact, the current unix * and linux actually still don't support asynchronous notification on any socket operation. */ #if defined(_ANSC_KERNEL) && defined(_ANSC_LINUX) if ( !pMyObject->CurSocketCount) { if ( pServer->Mode & ANSC_DSTO_MODE_EVENT_SYNC ) { AnscWaitEvent (&pMyObject->NewSocketEvent, ANSC_DETO_WAIT_EVENT_INTERVAL); AnscResetEvent(&pMyObject->NewSocketEvent); if (!pMyObject->CurSocketCount) { AnscTaskRelinquish(); continue; } } else { AnscSleep(ANSC_DETO_TASK_BREAK_INTERVAL); continue; } } #else if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET ) { AnscAcquireLock(&pMyObject->RecvSocketSetLock); *read_fd_set2 = *pRecvSet2; AnscReleaseLock(&pMyObject->RecvSocketSetLock); } else { AnscAcquireLock(&pMyObject->RecvSocketSetLock); *read_fd_set1 = *pRecvSet1; AnscReleaseLock(&pMyObject->RecvSocketSetLock); } if ( ( (pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && XSKT_SOCKET_FD_ISNUL(read_fd_set2)) || (!(pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && ANSC_SOCKET_FD_ISNUL(read_fd_set1)) ) { if ( pServer->Mode & ANSC_DSTO_MODE_EVENT_SYNC ) { AnscWaitEvent (&pMyObject->NewSocketEvent, ANSC_DETO_WAIT_EVENT_INTERVAL); AnscResetEvent(&pMyObject->NewSocketEvent); if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET ) { AnscAcquireLock(&pMyObject->RecvSocketSetLock); *read_fd_set2 = *pRecvSet2; AnscReleaseLock(&pMyObject->RecvSocketSetLock); } else { AnscAcquireLock(&pMyObject->RecvSocketSetLock); *read_fd_set1 = *pRecvSet1; AnscReleaseLock(&pMyObject->RecvSocketSetLock); } if ( ( (pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && XSKT_SOCKET_FD_ISNUL(read_fd_set2)) || (!(pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && ANSC_SOCKET_FD_ISNUL(read_fd_set1)) ) { AnscTaskRelinquish(); continue; } } else { AnscSleep(ANSC_DETO_TASK_BREAK_INTERVAL); continue; } } if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET ) { timeval2.tv_sec = (ANSC_DETO_POLL_INTERVAL_MS / 1000); /* number of seconds */ timeval2.tv_usec = (ANSC_DETO_POLL_INTERVAL_MS % 1000) * 1000; /* number of microseconds */ } else { timeval1.tv_sec = (ANSC_DETO_POLL_INTERVAL_MS / 1000); /* number of seconds */ timeval1.tv_usec = (ANSC_DETO_POLL_INTERVAL_MS % 1000) * 1000; /* number of microseconds */ } /* * The _ansc_select() function returns the total number of socket handles that are ready * and contained in the fd_set structures, zero if the time limit expired, or SOCKET_ERROR * if an error occurred. Upon return, the structures are updated to reflect the subset of * these sockets that meet the specified condition. */ if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET ) { s_result = _xskt_select(XSKT_SOCKET_FD_SETSIZE, read_fd_set2, NULL, NULL, &timeval2); } else { s_result = _ansc_select(ANSC_SOCKET_FD_SETSIZE, read_fd_set1, NULL, NULL, &timeval1); } if ( s_result == 0 ) { continue; } else if ( ( (pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && (s_result == XSKT_SOCKET_ERROR)) || (!(pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && (s_result == ANSC_SOCKET_ERROR)) ) { s_error = (pServer->Mode & ANSC_DSTO_MODE_XSOCKET)? _xskt_get_last_error() : _ansc_get_last_error(); /* * Previously we simply reset everything when _ansc_select() fails, which is not a good * solution: we shall notify the worker module and gracefully shutdown the socket(s) * that caused the error. */ /* pMyObject->Reset((ANSC_HANDLE)pMyObject); */ pMyObject->ExpAllSockets((ANSC_HANDLE)pMyObject); continue; } else if ( !pMyObject->bStarted ) { break; } #endif /* * If there're multiple sockets are receiving data, we loop through the returned fd_set * structure and process them one-by-one. However, we have a slight problem: the resulted * fd_set consists of only the native socket handles, not the associated Socket Objects. * We have to first retrieve the peer's IP address from the socket, and use it to find * the associated socket object. */ #if defined(_ANSC_KERNEL) && defined(_ANSC_LINUX) if (TRUE) { int i; PSINGLE_LINK_ENTRY pSLinkEntry; for ( i = 0; i < ANSC_DETO_SOCKET_TABLE_SIZE ; i++) { if (!AnscSListQueryDepth(&pMyObject->SocketTable[i])) { continue; } AnscAcquireLock(&pMyObject->SocketTableLock); pSLinkEntry = AnscSListGetFirstEntry(&pMyObject->SocketTable[i]); AnscReleaseLock(&pMyObject->SocketTableLock); while ( pSLinkEntry ) { pSocket = ACCESS_ANSC_DAEMON_SOCKET_TCP_OBJECT(pSLinkEntry); pSLinkEntry = AnscSListGetNextEntry(pSLinkEntry); if ( pSocket->bTlsEnabled ) { pMyObject->bBusy = TRUE; returnStatus = pMyObject->Recv2 ( (ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket ); pMyObject->bBusy = FALSE; } else { pMyObject->bBusy = TRUE; returnStatus = pMyObject->Recv ( (ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket ); pMyObject->bBusy = FALSE; } } if ( !pMyObject->bStarted ) { break; } } AnscSleep(10); } #else for ( i = 0; i < s_result; i++ ) { if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET ) { XSKT_SOCKET_FD_GET(read_fd_set2, s_socket, (ULONG)i); } else { ANSC_SOCKET_FD_GET(read_fd_set1, s_socket, (ULONG)i); } if ( ( (pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && (s_socket == XSKT_SOCKET_INVALID_SOCKET)) || (!(pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && (s_socket == ANSC_SOCKET_INVALID_SOCKET)) ) { break; } else { pSocket = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->GetSocketByOsocket ( (ANSC_HANDLE)pMyObject, s_socket ); /* * We should make sure this socket is still valid before proceeding with the socket * receive operations. For example, the peer may have already closed or reset the * TCP connection while we're serving the previous socket request. * * 10/06/04 - It's believed this modification is slowing down the GUI and we're not * seeing tangible evidence that GUI responsivenss has been improved. So we disable * it for now. */ /* if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET ) { XSKT_SOCKET_FD_ZERO(excp_fd_set2); XSKT_SOCKET_FD_SET ((XSKT_SOCKET)s_socket, excp_fd_set2); timeval2.tv_sec = 0; timeval2.tv_usec = 0; s_result_excp = _xskt_select(XSKT_SOCKET_FD_SETSIZE, NULL, NULL, excp_fd_set2, &timeval2); } else { ANSC_SOCKET_FD_ZERO(excp_fd_set1); ANSC_SOCKET_FD_SET (s_socket, excp_fd_set1); timeval1.tv_sec = 0; timeval1.tv_usec = 0; s_result_excp = _ansc_select(ANSC_SOCKET_FD_SETSIZE, NULL, NULL, excp_fd_set1, &timeval1); } */ } /* if ( ((s_result_excp == 1 ) ) || ((s_result_excp == XSKT_SOCKET_ERROR) && (pServer->Mode & ANSC_DSTO_MODE_XSOCKET)) || ((s_result_excp == ANSC_SOCKET_ERROR) && !(pServer->Mode & ANSC_DSTO_MODE_XSOCKET)) ) { if ( TRUE ) { pSocket->bBroken = TRUE; pMyObject->EnableRecv((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket, FALSE); pMyObject->EnableSend((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket, FALSE); } if ( pSocket->bTlsEnabled ) { if ( pSocket->bTlsEnabled && pSocket->bTlsConnected && !pSocket->bTlsInitializing ) { returnStatus = pWorker->Notify ( pWorker->hWorkerContext, (ANSC_HANDLE)pSocket, ANSC_DSTOWO_EVENT_SOCKET_ERROR, (ANSC_HANDLE)NULL ); } else { AnscSetEvent(&pSocket->TlsConnEvent); } } else { returnStatus = pWorker->Notify ( pWorker->hWorkerContext, (ANSC_HANDLE)pSocket, ANSC_DSTOWO_EVENT_SOCKET_ERROR, (ANSC_HANDLE)NULL ); } if ( pServer->Mode & ANSC_DSTO_MODE_AUTO_CLOSE ) { pMyObject->DelSocket((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket); } pMyObject->TrcCount++; continue; } else { pSocket = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->GetSocketByOsocket ( (ANSC_HANDLE)pMyObject, s_socket ); } */ if ( !pSocket ) { continue; } else if ( pSocket->bTlsEnabled ) { #ifdef _ANSC_USE_OPENSSL_ pMyObject->bBusy = TRUE; returnStatus = pMyObject->Recv ( (ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket ); pMyObject->bBusy = FALSE; #else pMyObject->bBusy = TRUE; returnStatus = pMyObject->Recv2 ( (ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket ); pMyObject->bBusy = FALSE; #endif } else { pMyObject->bBusy = TRUE; returnStatus = pMyObject->Recv ( (ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket ); pMyObject->bBusy = FALSE; } /* * Check whether 'bToBeCleaned' flag is set for this socket: if it is, we should close * this socket right away; otherwise, we continue the processing. WARNING!!! This new * change seems to incur instability in SLAP, we have to roll back to the initial * approach. */ /* if ( pSocket->bToBeCleaned ) { returnStatus = pMyObject->DelSocket ( (ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket ); } */ if ( !pMyObject->bStarted ) { break; } } #endif } /****************************************************************** GRACEFUL ROLLBACK PROCEDURES AND EXIT DOORS ******************************************************************/ EXIT1: AnscSetEvent(&pMyObject->RecvEvent); #if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX) if ( read_fd_set1 ) { AnscFreeMemory(read_fd_set1); } if ( read_fd_set2 ) { AnscFreeMemory(read_fd_set2); } if ( excp_fd_set1 ) { AnscFreeMemory(excp_fd_set1); } if ( excp_fd_set2 ) { AnscFreeMemory(excp_fd_set2); } #endif return ANSC_STATUS_SUCCESS; }
ANSC_STATUS AnscBetoRecvTask ( ANSC_HANDLE hThisObject ) { ANSC_STATUS returnStatus = ANSC_STATUS_SUCCESS; PANSC_BROKER_ENGINE_TCP_OBJECT pMyObject = (PANSC_BROKER_ENGINE_TCP_OBJECT)hThisObject; PANSC_BROKER_SERVER_TCP_OBJECT pServer = (PANSC_BROKER_SERVER_TCP_OBJECT)pMyObject->hBrokerServer; ansc_fd_set* pRecvSet1 = (ansc_fd_set* )pMyObject->RecvSocketSet; xskt_fd_set* pRecvSet2 = (xskt_fd_set* )pMyObject->RecvSocketSet; PANSC_BROKER_SOCKET_TCP_OBJECT pSocket = NULL; ULONG ulLastCleanAt = AnscGetTickInSeconds(); ANSC_SOCKET s_socket = ANSC_SOCKET_INVALID_SOCKET; int s_result = 0; int s_result_excp = 0; int s_error = 0; int i = 0; uni_fd_set read_fd_set; /*uni_fd_set excp_fd_set;*/ uni_timeval timeval; AnscTrace("AnscBetoRecvTask is activated ...!\n"); /* * As a scalable server implemention, we shall accept as many incoming client connections as * possible and can only be limited by the system resources. Once the listening socket becomes * readable, which means an incoming connection attempt has arrived. We create a new socket * object and associate it with the client. This is a repeated process until the socket owner * closes the socket. */ while ( pMyObject->bStarted ) { ANSC_COMMIT_TASK(); /* * To avoid letting the old half-dead sockets hogging up the system resource, we need to * periodically invoke the cleaning routine. The default interval is 10 seconds, and the * idle timeout value is 90 seconds. */ if ( pMyObject->bCleaningDemanded || (AnscGetTickInSeconds() - ulLastCleanAt) >= ANSC_BETO_CLEAN_TASK_INTERVAL ) { pMyObject->Clean((ANSC_HANDLE)pMyObject); ulLastCleanAt = AnscGetTickInSeconds(); pMyObject->bCleaningDemanded = FALSE; } /* * The _ansc_select() function returns the total number of socket handles that are ready * and contained in the fd_set structures, zero if the time limit expired, or SOCKET_ERROR * if an error occurred. Upon return, the structures are updated to reflect the subset of * these sockets that meet the specified condition. */ if ( pServer->Mode & ANSC_BSTO_MODE_XSOCKET ) { /* * no need to use lock for read_fd_set here, dirty read does not matter. */ read_fd_set.xset = *pRecvSet2; if( XSKT_SOCKET_FD_ISNUL(&read_fd_set.xset) ) { if ( pServer->Mode & ANSC_BSTO_MODE_EVENT_SYNC ) { AnscWaitEvent (&pMyObject->NewSocketEvent, ANSC_BETO_WAIT_EVENT_INTERVAL); AnscResetEvent(&pMyObject->NewSocketEvent); } else { AnscSleep(ANSC_BETO_TASK_BREAK_INTERVAL); } continue; } timeval.xtv.tv_sec = (ANSC_BETO_POLL_INTERVAL_MS / 1000); /* number of seconds */ timeval.xtv.tv_usec = (ANSC_BETO_POLL_INTERVAL_MS % 1000) * 1000; /* number of microseconds */ s_result = _xskt_select(XSKT_SOCKET_FD_SETSIZE, &read_fd_set.xset, NULL, NULL, &timeval.xtv); if ( s_result == 0 ) { continue; } if ( s_result == XSKT_SOCKET_ERROR ) { s_error = _xskt_get_last_error(); pMyObject->Reset((ANSC_HANDLE)pMyObject); continue; } } else { /* * no need to use lock for read_fd_set here, dirty read does not matter. */ read_fd_set.aset = *pRecvSet1; if( ANSC_SOCKET_FD_ISNUL(&read_fd_set.aset) ) { if ( pServer->Mode & ANSC_BSTO_MODE_EVENT_SYNC ) { AnscWaitEvent (&pMyObject->NewSocketEvent, ANSC_BETO_WAIT_EVENT_INTERVAL); AnscResetEvent(&pMyObject->NewSocketEvent); } else { AnscSleep(ANSC_BETO_TASK_BREAK_INTERVAL); } continue; } timeval.atv.tv_sec = (ANSC_BETO_POLL_INTERVAL_MS / 1000); /* number of seconds */ timeval.atv.tv_usec = (ANSC_BETO_POLL_INTERVAL_MS % 1000) * 1000; /* number of microseconds */ s_result = _ansc_select(ANSC_SOCKET_FD_SETSIZE, &read_fd_set.aset, NULL, NULL, &timeval.atv); if ( s_result == 0 ) { continue; } if ( s_result == ANSC_SOCKET_ERROR ) { s_error = _ansc_get_last_error(); pMyObject->Reset((ANSC_HANDLE)pMyObject); continue; } } /* * If there're multiple sockets are receiving data, we loop through the returned fd_set * structure and process them one-by-one. However, we have a slight problem: the resulted * fd_set consists of only the native socket handles, not the associated Socket Objects. * We have to first retrieve the peer's IP address from the socket, and use it to find * the associated socket object. */ for ( i = 0; i < s_result; i++ ) { if ( !pMyObject->bStarted ) { break; } if ( pServer->Mode & ANSC_BSTO_MODE_XSOCKET ) { XSKT_SOCKET_FD_GET(&read_fd_set.xset, s_socket, (ULONG)i); if( s_socket == XSKT_SOCKET_INVALID_SOCKET ) { break; } if( ! XSKT_SOCKET_FD_ISSET(s_socket, pRecvSet2) ) { AnscTraceError(("AnscBetoRecvTask: XSKT_SOCKET_FD_ISSET returned FALSE.\n")); continue; } } else { ANSC_SOCKET_FD_GET(&read_fd_set.aset, s_socket, (ULONG)i); if( s_socket == ANSC_SOCKET_INVALID_SOCKET ) { break; } if( ! ANSC_SOCKET_FD_ISSET(s_socket, pRecvSet1) ) { AnscTraceError(("AnscBetoRecvTask: XSKT_SOCKET_FD_ISSET returned FALSE.\n")); continue; } } pSocket = (PANSC_BROKER_SOCKET_TCP_OBJECT)pMyObject->GetSocketByOsocket ( (ANSC_HANDLE)pMyObject, s_socket ); if ( !pSocket ) { continue; } /* * We should make sure this socket is still valid before proceeding with the socket * receive operations. For example, the peer may have already closed or reset the * TCP connection while we're serving the previous socket request. * * 10/06/04 - It's believed this modification is slowing down the GUI and we're not * seeing tangible evidence that GUI responsivenss has been improved. So we disable * it for now. * * 11/20/09 - Re-activate the following code segment to validate the socket before * proceeding. */ /* if ( pServer->Mode & ANSC_BSTO_MODE_XSOCKET ) { XSKT_SOCKET_FD_ZERO((&excp_fd_set.xset)); XSKT_SOCKET_FD_SET ((XSKT_SOCKET)s_socket, (&excp_fd_set.xset)); timeval.xtv.tv_sec = 0; timeval.xtv.tv_usec = 0; s_result_excp = _xskt_select(XSKT_SOCKET_FD_SETSIZE, NULL, NULL, &excp_fd_set.xset, &timeval.xtv); } else { ANSC_SOCKET_FD_ZERO((&excp_fd_set.aset)); ANSC_SOCKET_FD_SET (s_socket, (&excp_fd_set.aset)); timeval.atv.tv_sec = 0; timeval.atv.tv_usec = 0; s_result_excp = _ansc_select(ANSC_SOCKET_FD_SETSIZE, NULL, NULL, &excp_fd_set.aset, &timeval.atv); } if ( ((s_result_excp == 1 ) ) || ((s_result_excp == XSKT_SOCKET_ERROR) && (pServer->Mode & ANSC_BSTO_MODE_XSOCKET)) || ((s_result_excp == ANSC_SOCKET_ERROR) && !(pServer->Mode & ANSC_BSTO_MODE_XSOCKET)) ) { if ( TRUE ) { pSocket->bBroken = TRUE; pSocket->bToBeCleaned = TRUE; pMyObject->EnableRecv((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket, FALSE); pMyObject->EnableSend((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket, FALSE); } if ( pServer->Mode & ANSC_BSTO_MODE_AUTO_CLOSE ) { pMyObject->DelSocket((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket); } continue; } */ returnStatus = pMyObject->Recv ( (ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket ); } } AnscSetEvent(&pMyObject->RecvEvent); return ANSC_STATUS_SUCCESS; }
ANSC_STATUS CcspCwmpAcscoRequest ( ANSC_HANDLE hThisObject, char* pSoapMessage, char* pMethodName, ULONG ulReqEnvCount, ULONG ulRepEnvCount ) { PCCSP_CWMP_ACS_CONNECTION_OBJECT pMyObject = (PCCSP_CWMP_ACS_CONNECTION_OBJECT)hThisObject; PHTTP_SIMPLE_CLIENT_OBJECT pHttpClient = (PHTTP_SIMPLE_CLIENT_OBJECT)pMyObject->hHttpSimpleClient; PCCSP_CWMP_SESSION_OBJECT pWmpSession = (PCCSP_CWMP_SESSION_OBJECT )pMyObject->hCcspCwmpSession; PCCSP_CWMP_CPE_CONTROLLER_OBJECT pCcspCwmpCpeController = (PCCSP_CWMP_CPE_CONTROLLER_OBJECT)pWmpSession->hCcspCwmpCpeController; PCCSP_CWMP_STAT_INTERFACE pCcspCwmpStatIf = (PCCSP_CWMP_STAT_INTERFACE)pCcspCwmpCpeController->hCcspCwmpStaIf; PCCSP_CWMP_CFG_INTERFACE pCcspCwmpCfgIf = (PCCSP_CWMP_CFG_INTERFACE)pCcspCwmpCpeController->hCcspCwmpCfgIf; PCCSP_CWMP_MCO_INTERFACE pCcspCwmpMcoIf = (PCCSP_CWMP_MCO_INTERFACE )pWmpSession->hCcspCwmpMcoIf; PHTTP_HFP_INTERFACE pHttpHfpIf = (PHTTP_HFP_INTERFACE)pHttpClient->GetHfpIf((ANSC_HANDLE)pHttpClient); PHTTP_CAS_INTERFACE pHttpCasIf = NULL; PHTTP_REQUEST_URI pHttpReqInfo = NULL; ANSC_STATUS returnStatus = ANSC_STATUS_SUCCESS; PANSC_ACS_INTERN_HTTP_CONTENT pHttpGetReq = &intHttpContent; BOOL bApplyTls = FALSE; PCHAR pRequestURL = NULL; PCHAR pTempString = NULL; PHTTP_AUTH_CLIENT_OBJECT pAuthClientObj = NULL; char pNewUrl[257] = { 0 }; ULONG uRedirect = 0; ULONG uMaxRedirect = 5; ULONG ulRpcCallTimeout= CCSP_CWMPSO_RPCCALL_TIMEOUT; /* If the response is 401 authentication required, we need to try again */ int nMaxAuthRetries = 2; if( pMyObject->AcsUrl == NULL || AnscSizeOfString(pMyObject->AcsUrl) <= 10 || pHttpHfpIf == NULL) { return ANSC_STATUS_NOT_READY; } AnscZeroMemory(pHttpGetReq, sizeof(ANSC_ACS_INTERN_HTTP_CONTENT)); CcspTr069PaTraceDebug(("CcspCwmpAcscoRequest -- AcsUrl = '%s'\n", pMyObject->AcsUrl)); pHttpCasIf = (PHTTP_CAS_INTERFACE)pHttpClient->GetCasIf((ANSC_HANDLE)pHttpClient); if ( pHttpCasIf != NULL) { if( pMyObject->Username == NULL || AnscSizeOfString(pMyObject->Username) == 0) { pHttpCasIf->EnableAuth(pHttpCasIf->hOwnerContext, FALSE); } else { pHttpCasIf->EnableAuth(pHttpCasIf->hOwnerContext, TRUE); pAuthClientObj = (PHTTP_AUTH_CLIENT_OBJECT)pHttpClient->GetClientAuthObj((ANSC_HANDLE)pHttpClient); if ( pAuthClientObj != NULL) { pAuthClientObj->SetAcmIf((ANSC_HANDLE)pAuthClientObj, (ANSC_HANDLE)pMyObject->hHttpAcmIf); } else { CcspTr069PaTraceError(("Failed to Get HttpAuthClient object.\n")); } } } #ifdef _DEBUG if ( !pSoapMessage ) { CcspTr069PaTraceDebug(("CPE Request:\n<EMPTY>\n")); } else if ( AnscSizeOfString(pSoapMessage) <= CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH ) { CcspTr069PaTraceDebug(("CPE Request:\n%s\n", pSoapMessage)); } else { char partSoap[CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH+1+8]; AnscCopyMemory(partSoap, pSoapMessage, CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH); partSoap[CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH] = '\n'; partSoap[CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH+1] = '.'; partSoap[CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH+2] = '.'; partSoap[CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH+3] = '.'; partSoap[CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH+4] = '\n'; partSoap[CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH+5] = 0; CcspTr069PaTraceDebug(("CPE Request:\n%s\n", partSoap)); } #endif START: pRequestURL = pMyObject->AcsUrl; pHttpReqInfo = (PHTTP_REQUEST_URI)pHttpHfpIf->ParseHttpUrl ( pHttpHfpIf->hOwnerContext, pRequestURL, AnscSizeOfString(pRequestURL) ); if ( !pHttpReqInfo ) { return ANSC_STATUS_INTERNAL_ERROR; } pHttpReqInfo->Type = HTTP_URI_TYPE_ABS_PATH; /* init the request */ AnscZeroMemory(pHttpGetReq, sizeof(ANSC_ACS_INTERN_HTTP_CONTENT)); pHttpGetReq->bIsRedirect = FALSE; pHttpGetReq->SoapMessage = pSoapMessage; /* When there is more than one envelope in a single HTTP Request, * when there is a SOAP response in an HTTP Request, or when there is a * SOAP Fault response in an HTTP Request, the SOAPAction header in the * HTTP Request MUST have no value (with no quotes), indicating that this * header provides no information as to the intent of the message." */ if( ulReqEnvCount == 1 && ulRepEnvCount == 0) { pHttpGetReq->MethodName = pMethodName; } AnscInitializeEvent(&pHttpGetReq->CompleteEvent); while ( nMaxAuthRetries > 0 ) { CcspTr069PaTraceInfo(("ACS Request now at: %u\n", (unsigned int)AnscGetTickInSeconds())); if ( AnscEqualString2(pRequestURL, "https", 5, FALSE) ) { bApplyTls = TRUE; } else if ( AnscEqualString2(pRequestURL, "http", 4, FALSE) ) { if ( bIsComcastImage() ){ #ifdef _SUPPORT_HTTP CcspTr069PaTraceInfo(("HTTP request from ACS is supported\n")); bApplyTls = FALSE; #else CcspTr069PaTraceInfo(("TR-069 blocked unsecured traffic from ACS\n")); pHttpGetReq->CompleteStatus = ANSC_STATUS_NOT_SUPPORTED; pHttpGetReq->bUnauthorized = TRUE; pHttpGetReq->bIsRedirect = FALSE; break; #endif } else { bApplyTls = FALSE; } } else { pHttpGetReq->CompleteStatus = ANSC_STATUS_NOT_SUPPORTED; pHttpGetReq->bUnauthorized = FALSE; pHttpGetReq->bIsRedirect = FALSE; break; } if(pHttpGetReq->pContent != NULL) { CcspTr069PaFreeMemory(pHttpGetReq->pContent); pHttpGetReq->pContent = NULL; } pHttpGetReq->CompleteStatus = ANSC_STATUS_FAILURE; pHttpGetReq->bUnauthorized = FALSE; AnscResetEvent (&pHttpGetReq->CompleteEvent); returnStatus = pHttpClient->Request ( (ANSC_HANDLE)pHttpClient, (ULONG )HTTP_METHOD_CODE_POST, (ANSC_HANDLE)pHttpReqInfo, (ANSC_HANDLE)pHttpGetReq, bApplyTls ); if( returnStatus != ANSC_STATUS_SUCCESS) { CcspTr069PaTraceError(("ACS Request failed: returnStatus = %.X\n", (unsigned int)returnStatus)); break; } if ( pCcspCwmpCfgIf && pCcspCwmpCfgIf->GetCwmpRpcTimeout ) { ulRpcCallTimeout = pCcspCwmpCfgIf->GetCwmpRpcTimeout(pCcspCwmpCfgIf->hOwnerContext); if ( ulRpcCallTimeout < CCSP_CWMPSO_RPCCALL_TIMEOUT ) { ulRpcCallTimeout = CCSP_CWMPSO_RPCCALL_TIMEOUT; } } AnscWaitEvent(&pHttpGetReq->CompleteEvent, ulRpcCallTimeout * 1000); if ( pHttpGetReq->CompleteStatus == ANSC_STATUS_SUCCESS && pHttpGetReq->bUnauthorized && nMaxAuthRetries > 0 ) { CcspTr069PaTraceError(("ACS Request is not authenticated, try again.\n")); nMaxAuthRetries --; #ifdef _ANSC_USE_OPENSSL_ if( bApplyTls ) { if ( ANSC_STATUS_SUCCESS == CcspTr069PaSsp_GetTr069CertificateLocationForSyndication( &openssl_client_ca_certificate_files ) ) { openssl_load_ca_certificates( SSL_CLIENT_CALLS ); } } #endif /* _ANSC_USE_OPENSSL_ */ } else { CcspTr069PaTraceInfo(("ACS Request has completed with status code %lu, at %lu\n", pHttpGetReq->CompleteStatus, AnscGetTickInSeconds())); break; } } /* AnscResetEvent (&pHttpGetReq->CompleteEvent); */ AnscFreeEvent(&pHttpGetReq->CompleteEvent); CcspTr069PaFreeMemory(pHttpReqInfo); if ( pHttpGetReq->CompleteStatus != ANSC_STATUS_SUCCESS ) { if ( pHttpGetReq->CompleteStatus == ANSC_STATUS_RESET_SESSION ) { goto REDIRECTED; } else { returnStatus = pHttpGetReq->CompleteStatus; goto EXIT; } } else if( pHttpGetReq->bUnauthorized) { returnStatus = ANSC_STATUS_FAILURE; if( pCcspCwmpStatIf) { pCcspCwmpStatIf->IncTcpFailure(pCcspCwmpStatIf->hOwnerContext); } goto EXIT; } REDIRECTED: if( pHttpGetReq->bIsRedirect) { if( _ansc_strstr((PCHAR)pHttpGetReq->pContent, "http") == pHttpGetReq->pContent) { if ( pMyObject->AcsUrl ) CcspTr069PaFreeMemory(pMyObject->AcsUrl); pMyObject->AcsUrl = CcspTr069PaCloneString(pHttpGetReq->pContent); } else { /* if it's partial path */ pTempString = _ansc_strstr(pRequestURL, "//"); if( pTempString == NULL) { returnStatus = ANSC_STATUS_FAILURE; goto EXIT; } pTempString += AnscSizeOfString("//"); pTempString = _ansc_strstr(pTempString, "/"); if( pTempString == NULL) { returnStatus = ANSC_STATUS_FAILURE; goto EXIT; } AnscCopyMemory(pNewUrl, pRequestURL, (ULONG)(pTempString - pRequestURL)); AnscCatString(pNewUrl, (PCHAR)pHttpGetReq->pContent); if ( pMyObject->AcsUrl ) CcspTr069PaFreeMemory(pMyObject->AcsUrl); pMyObject->AcsUrl = CcspTr069PaCloneString(pNewUrl); } uRedirect ++; if( uRedirect >= uMaxRedirect) { CcspTr069PaTraceDebug(("Maximum Redirection reached. Give up!\n")); returnStatus = ANSC_STATUS_FAILURE; goto EXIT; } else { CcspTr069PaTraceDebug(("Acs connection redirection #%u: '%s'\n", (unsigned int)uRedirect, pMyObject->AcsUrl)); /* in case redirected ACS challenges CPE again */ nMaxAuthRetries = 2; /* tear down current HTTP session before redirecting to new ACS, * otherwise, there might be case that ACS sends out redirection * response and immediately closes the socket, CWMP may be * confused by closing CWMP session prematurely. */ pHttpClient->DelAllWcsos((ANSC_HANDLE)pHttpClient); goto START; } } if(pWmpSession != NULL) { if( pHttpGetReq->ulContentSize > 0 && pHttpGetReq->pContent != NULL) { CcspTr069PaTraceDebug(("Response:\n%s\n", (char*)pHttpGetReq->pContent)); returnStatus = pWmpSession->RecvSoapMessage ( pWmpSession, (PCHAR)pHttpGetReq->pContent ); } else { CcspTr069PaTraceDebug(("Response: <EMPTY>\n")); returnStatus = pCcspCwmpMcoIf->NotifyAcsStatus ( pCcspCwmpMcoIf->hOwnerContext, TRUE, /* no more requests */ FALSE ); } } EXIT: if(pHttpGetReq->pContent != NULL) { CcspTr069PaFreeMemory(pHttpGetReq->pContent); pHttpGetReq->pContent = NULL; } /****************************************************************** GRACEFUL ROLLBACK PROCEDURES AND EXIT DOORS ******************************************************************/ return returnStatus; }