DWORD VmDirQueueDequeue( BOOL bInLock, PVDIR_QUEUE pQueue, int64_t iTimeoutMs, PVOID* ppElement ) { DWORD dwError = 0; PVDIR_QUEUE_NODE pTemp= NULL; if (!pQueue || !ppElement) { BAIL_WITH_VMDIR_ERROR(dwError, ERROR_INVALID_PARAMETER); } VMDIR_LOCK_MUTEX(bInLock, pQueue->pMutex); if (!pQueue->pHead) { if (iTimeoutMs < 0) // Blocking { while (!pQueue->pHead) { dwError = VmDirConditionWait(pQueue->pCond, pQueue->pMutex); BAIL_ON_VMDIR_ERROR(dwError); } } else if (iTimeoutMs > 0) // Waiting { VmDirConditionTimedWait(pQueue->pCond, pQueue->pMutex, iTimeoutMs); if (!pQueue->pHead) { dwError = VMDIR_ERROR_QUEUE_EMPTY; } } else // Non Blocking { dwError = VMDIR_ERROR_QUEUE_EMPTY; } BAIL_ON_VMDIR_ERROR(dwError); } pQueue->iSize--; pTemp = pQueue->pHead; pQueue->pHead = pQueue->pHead->pNext; *ppElement = pTemp->pElement; VMDIR_SAFE_FREE_MEMORY(pTemp); cleanup: VMDIR_UNLOCK_MUTEX(bInLock, pQueue->pMutex); return dwError; error: VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "%s failed, error (%d)", __FUNCTION__, dwError); goto cleanup; }
static DWORD vmdirConnAccept( Sockbuf_IO* pSockbuf_IO, DWORD dwPort, BOOLEAN bIsLdaps ) { ber_socket_t newsockfd = -1; int retVal = LDAP_SUCCESS; ber_socket_t ip4_fd = -1; ber_socket_t ip6_fd = -1; ber_socket_t max_fd = -1; VMDIR_THREAD threadId; BOOLEAN bInLock = FALSE; int iLocalLogMask = 0; PVDIR_CONNECTION_CTX pConnCtx = NULL; fd_set event_fd_set; fd_set poll_fd_set; struct timeval timeout = {0}; // Wait for ***1st*** replication cycle to be over. if (gVmdirServerGlobals.serverId == 0) // instance has not been initialized { VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "Connection accept thread: Have NOT yet started listening on LDAP port (%u)," " waiting for the 1st replication cycle to be over.", dwPort); VMDIR_LOCK_MUTEX(bInLock, gVmdirGlobals.replCycleDoneMutex); // wait till 1st replication cycle is over if (VmDirConditionWait( gVmdirGlobals.replCycleDoneCondition, gVmdirGlobals.replCycleDoneMutex ) != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "Connection accept thread: VmDirConditionWait failed." ); retVal = LDAP_OPERATIONS_ERROR; goto cleanup; } // also wake up the other (normal LDAP port/SSL LDAP port listner) LDAP connection accept thread, // waiting on 1st replication cycle to be over // BUGBUG Does not handle spurious wake up VmDirConditionSignal(gVmdirGlobals.replCycleDoneCondition); VMDIR_UNLOCK_MUTEX(bInLock, gVmdirGlobals.replCycleDoneMutex); if (VmDirdState() == VMDIRD_STATE_SHUTDOWN) // Asked to shutdown before we started accepting { goto cleanup; } VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Connection accept thread: listening on LDAP port (%u).", dwPort); } iLocalLogMask = VmDirLogGetMask(); ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &iLocalLogMask); SetupLdapPort(dwPort, &ip4_fd, &ip6_fd); if (ip4_fd < 0 && ip6_fd < 0) { VmDirSleep(1000); goto cleanup; } FD_ZERO(&event_fd_set); if (ip4_fd >= 0) { FD_SET (ip4_fd, &event_fd_set); if (ip4_fd > max_fd) { max_fd = ip4_fd; } } if (ip6_fd >= 0) { FD_SET (ip6_fd, &event_fd_set); if (ip6_fd > max_fd) { max_fd = ip6_fd; } } retVal = VmDirSyncCounterIncrement(gVmdirGlobals.pPortListenSyncCounter); if (retVal != 0 ) { VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "%s: VmDirSyncCounterIncrement(gVmdirGlobals.pPortListenSyncCounter) returned error", __func__); BAIL_ON_VMDIR_ERROR(retVal); } while (TRUE) { if (VmDirdState() == VMDIRD_STATE_SHUTDOWN) { goto cleanup; } poll_fd_set = event_fd_set; timeout.tv_sec = 3; timeout.tv_usec = 0; retVal = select ((int)max_fd+1, &poll_fd_set, NULL, NULL, &timeout); if (retVal < 0 ) { #ifdef _WIN32 errno = WSAGetLastError(); #endif VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: select() (port %d) call failed: %d.", __func__, dwPort, errno); VmDirSleep( 1000 ); continue; } else if (retVal == 0) { //VMDIR_LOG_INFO( LDAP_DEBUG_CONNS, "%s: select() timeout (port %d)", __func__, dwPort); continue; } if (ip4_fd >= 0 && FD_ISSET(ip4_fd, &poll_fd_set)) { newsockfd = accept(ip4_fd, (struct sockaddr *) NULL, NULL); } else if (ip6_fd >= 0 && FD_ISSET(ip6_fd, &poll_fd_set)) { newsockfd = accept(ip6_fd, (struct sockaddr *) NULL, NULL); } else { VMDIR_LOG_INFO( LDAP_DEBUG_CONNS, "%s: select() returned with no data (port %d), return: %d", __func__, dwPort, retVal); continue; } if (newsockfd < 0) { #ifdef _WIN32 errno = WSAGetLastError(); #endif if (errno != EAGAIN && errno != EWOULDBLOCK ) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: accept() (port %d) failed with errno: %d.", __func__, dwPort, errno ); } continue; } if ( _VmDirFlowCtrlThrEnter() == TRUE ) { tcp_close(newsockfd); newsockfd = -1; VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "Maxmimum number of concurrent LDAP threads reached. Blocking new connection" ); continue; } retVal = VmDirAllocateMemory( sizeof(VDIR_CONNECTION_CTX), (PVOID*)&pConnCtx); BAIL_ON_VMDIR_ERROR(retVal); pConnCtx->sockFd = newsockfd; newsockfd = -1; pConnCtx->pSockbuf_IO = pSockbuf_IO; retVal = VmDirCreateThread(&threadId, TRUE, ProcessAConnection, (PVOID)pConnCtx); if (retVal != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: VmDirCreateThread() (port) failed with errno: %d", __func__, dwPort, errno ); tcp_close(pConnCtx->sockFd); _VmDirFlowCtrlThrExit(); VMDIR_SAFE_FREE_MEMORY(pConnCtx); continue; } else { pConnCtx = NULL; //thread take ownership on pConnCtx VmDirFreeVmDirThread(&threadId); } } cleanup: VMDIR_UNLOCK_MUTEX(bInLock, gVmdirGlobals.replCycleDoneMutex); if (ip4_fd >= 0) { tcp_close(ip4_fd); } if (ip6_fd >= 0) { tcp_close(ip6_fd); } if (newsockfd >= 0) { tcp_close(newsockfd); } #ifndef _WIN32 raise(SIGTERM); #endif VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "%s: Connection accept thread: stop (port %d)", __func__, dwPort); return retVal; error: goto cleanup; }
DWORD VmDirIndexingThreadFun( PVOID pArg ) { DWORD dwError = 0; BOOLEAN bInLock = FALSE; BOOLEAN bResume = FALSE; VDIR_SERVER_STATE vmdirState = VMDIRD_STATE_UNDEFINED; PVDIR_INDEXING_TASK pTask = NULL; VmDirDropThreadPriority(DEFAULT_THREAD_PRIORITY_DELTA); resume: while (1) { vmdirState = VmDirdState(); if (vmdirState == VMDIRD_STATE_SHUTDOWN) { break; } else if (vmdirState != VMDIRD_STATE_NORMAL) { VmDirSleep(1000); continue; } VMDIR_LOCK_MUTEX(bInLock, gVdirIndexGlobals.mutex); if (!bResume) { PVDIR_INDEX_UPD pIndexUpd = gVdirIndexGlobals.pIndexUpd; // record current progress dwError = VmDirIndexingTaskRecordProgress(pTask, pIndexUpd); BAIL_ON_VMDIR_ERROR(dwError); // apply index updates dwError = VmDirIndexUpdApply(pIndexUpd); BAIL_ON_VMDIR_ERROR(dwError); VmDirIndexUpdFree(pIndexUpd); gVdirIndexGlobals.pIndexUpd = NULL; // compute new task VmDirFreeIndexingTask(pTask); dwError = VmDirIndexingTaskCompute(&pTask); BAIL_ON_VMDIR_ERROR(dwError); } if (VmDirIndexingTaskIsNoop(pTask)) { dwError = VmDirConditionWait( gVdirIndexGlobals.cond, gVdirIndexGlobals.mutex); BAIL_ON_VMDIR_ERROR(dwError); continue; } VMDIR_UNLOCK_MUTEX(bInLock, gVdirIndexGlobals.mutex); dwError = VmDirIndexingTaskPopulateIndices(pTask); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirIndexingTaskValidateScopes(pTask); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirIndexingTaskDeleteIndices(pTask); BAIL_ON_VMDIR_ERROR(dwError); bResume = FALSE; } cleanup: VMDIR_UNLOCK_MUTEX(bInLock, gVdirIndexGlobals.mutex); VmDirFreeIndexingTask(pTask); return dwError; error: if (dwError == ERROR_INVALID_STATE) { bResume = TRUE; goto resume; } else { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s failed, error (%d)", __FUNCTION__, dwError ); } goto cleanup; }
/* * This thread waits on gVdirAttrIndexGlobals.condition and spawns worker thread * to perform indexing in the back ground. */ static DWORD vdirIndexingThrFun( PVOID pArg ) { DWORD dwError = 0; BOOLEAN bInLock = FALSE; PVDIR_CFG_ATTR_INDEX_DESC* ppIndexDesc = NULL; PVDIR_THREAD_INFO pThrInfo = (PVDIR_THREAD_INFO)pArg; while (1) { DWORD dwCnt = 0; DWORD dwSize = 0; VMDIR_THREAD tid = {0}; PVDIR_ATTR_INDEX_INSTANCE pCache = NULL; memset(&tid, 0, sizeof(tid)); // wait till new indices are created VMDIR_LOCK_MUTEX(bInLock, gVdirAttrIndexGlobals.mutex); dwError = VmDirConditionWait( pThrInfo->conditionUsed, pThrInfo->mutexUsed); BAIL_ON_VMDIR_ERROR(dwError); // get new cache we want to enable pCache = gVdirAttrIndexGlobals.pNewCache; VMDIR_UNLOCK_MUTEX(bInLock, gVdirAttrIndexGlobals.mutex); if (VmDirdState() == VMDIRD_STATE_SHUTDOWN) { break; } if (!pCache) { continue; } // get number of indices in building status for (dwCnt = 0, dwSize = 0; dwCnt < pCache->usNumIndex; dwCnt++) { if (pCache->pSortName[dwCnt].status == VDIR_CFG_ATTR_INDEX_BUILDING) { dwSize++; } } if (dwSize == 0) { continue; } dwError = VmDirAllocateMemory( sizeof(PVDIR_CFG_ATTR_INDEX_DESC) * (dwSize + 1), // +1 for NULL ending (PVOID)&ppIndexDesc); BAIL_ON_VMDIR_ERROR(dwError); // fill ppIndexDesc with building index // NOTE, ppIndexDesc does NOT own them; pCache does. for (dwCnt = 0, dwSize = 0; dwCnt < pCache->usNumIndex; dwCnt++) { if (pCache->pSortName[dwCnt].status == VDIR_CFG_ATTR_INDEX_BUILDING) { ppIndexDesc[dwSize] = &pCache->pSortName[dwCnt]; dwSize++; } } // TODO, detach thr now, need to join to safely finish bdb io... dwError = VmDirCreateThread( &tid, TRUE, vdirIndexingWorkerThrFun, (PVOID)ppIndexDesc); BAIL_ON_VMDIR_ERROR(dwError); // worker takes over ppIndexDesc. ppIndexDesc = NULL; VmDirFreeVmDirThread(&tid); } cleanup: VMDIR_UNLOCK_MUTEX(bInLock, gVdirAttrIndexGlobals.mutex); // TODO: should be dwError? return 0; error: VMDIR_SAFE_FREE_MEMORY(ppIndexDesc); //TODO, should we stop vmdird? VmDirLog( LDAP_DEBUG_ANY, "VmdirIndexingThr: error stop" ); goto cleanup; }