NTSTATUS SrvSessionCreate( USHORT uid, PLWIO_SRV_SESSION* ppSession ) { NTSTATUS ntStatus = 0; PLWIO_SRV_SESSION pSession = NULL; LWIO_LOG_DEBUG("Creating session [uid:%u]", uid); ntStatus = SrvAllocateMemory( sizeof(LWIO_SRV_SESSION), (PVOID*)&pSession); BAIL_ON_NT_STATUS(ntStatus); pSession->refcount = 1; pthread_rwlock_init(&pSession->mutex, NULL); pSession->pMutex = &pSession->mutex; pSession->uid = uid; ntStatus = WireGetCurrentNTTime(&pSession->llBirthTime); BAIL_ON_NT_STATUS(ntStatus); pSession->llLastActivityTime = pSession->llBirthTime; LWIO_LOG_DEBUG("Associating session [object:0x%x][uid:%u]", pSession, uid); ntStatus = LwRtlRBTreeCreate( &SrvSessionTreeCompare, NULL, &SrvSessionTreeRelease, &pSession->pTreeCollection); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvFinderCreateRepository( &pSession->hFinderRepository); BAIL_ON_NT_STATUS(ntStatus); SRV_ELEMENTS_INCREMENT_SESSIONS; *ppSession = pSession; cleanup: return ntStatus; error: *ppSession = NULL; if (pSession) { SrvSessionRelease(pSession); } goto cleanup; }
static NTSTATUS SrvSession2UpdateLastActivityTime_inlock( PLWIO_SRV_SESSION_2 pSession ) { return WireGetCurrentNTTime(&pSession->llLastActivityTime); }
NTSTATUS SrvElementsInit( VOID ) { NTSTATUS ntStatus = STATUS_SUCCESS; int iIter = 0; pthread_mutex_init(&gSrvElements.mutex, NULL); gSrvElements.pMutex = &gSrvElements.mutex; mt_init_genrand(&gSrvElements.randGen, time(NULL)); ntStatus = SrvElementsConfigSetupInitial(); BAIL_ON_NT_STATUS(ntStatus); gSrvElements.ulGlobalCreditLimit = SrvElementsConfigGetGlobalCreditLimit(); ntStatus = SrvElementsResourcesInit(); BAIL_ON_NT_STATUS(ntStatus); ntStatus = WireGetCurrentNTTime(&gSrvElements.llBootTime); BAIL_ON_NT_STATUS(ntStatus); while (!RAND_status() && (iIter++ < 10)) { uuid_t uuid; CHAR szUUID[37]; memset(szUUID, 0, sizeof(szUUID)); uuid_generate(uuid); uuid_unparse(uuid, szUUID); RAND_seed(szUUID, sizeof(szUUID)); } ntStatus = SrvTimerInit(&gSrvElements.timer); BAIL_ON_NT_STATUS(ntStatus); pthread_rwlock_init(&gSrvElements.statsLock, NULL); gSrvElements.pStatsLock = &gSrvElements.statsLock; ntStatus = SrvAsyncCloseFileTrackerCreate(&gSrvElements.pAsyncCloseFileTracker); BAIL_ON_NT_STATUS(ntStatus); error: return ntStatus; }
NTSTATUS SrvElementsInit( VOID ) { NTSTATUS status = STATUS_SUCCESS; int iIter = 0; status = SrvElementsResourcesInit(); BAIL_ON_NT_STATUS(status); status = WireGetCurrentNTTime(&gSrvElements.llBootTime); BAIL_ON_NT_STATUS(status); while (!RAND_status() && (iIter++ < 10)) { uuid_t uuid; CHAR szUUID[37]; memset(szUUID, 0, sizeof(szUUID)); uuid_generate(uuid); uuid_unparse(uuid, szUUID); RAND_seed(szUUID, sizeof(szUUID)); } status = SrvTimerInit(&gSrvElements.timer); BAIL_ON_NT_STATUS(status); pthread_rwlock_init(&gSrvElements.statsLock, NULL); gSrvElements.pStatsLock = &gSrvElements.statsLock; error: return status; }
static PVOID SrvTimerMain( IN PVOID pData ) { NTSTATUS status = 0; PSRV_TIMER_CONTEXT pContext = (PSRV_TIMER_CONTEXT)pData; PSRV_TIMER_REQUEST pTimerRequest = NULL; LONG64 llCurTime = 0LL; BOOLEAN bInLock = FALSE; LWIO_LOG_DEBUG("Srv timer starting"); LWIO_LOCK_MUTEX(bInLock, &pContext->mutex); while (!SrvTimerMustStop_inlock(pContext)) { int errCode = 0; BOOLEAN bRetryWait = FALSE; // If we have a current timer request, check if it is time to service it if (pTimerRequest) { status = WireGetCurrentNTTime(&llCurTime); BAIL_ON_NT_STATUS(status); if (llCurTime >= pTimerRequest->llExpiry && !pTimerRequest->bCanceled) { SrvTimerDetachRequest_inlock(pContext, pTimerRequest); LWIO_UNLOCK_MUTEX(bInLock, &pContext->mutex); if (pTimerRequest->pfnTimerExpiredCB) { // Timer has not been canceled pTimerRequest->pfnTimerExpiredCB( pTimerRequest, pTimerRequest->pUserData); } LWIO_LOCK_MUTEX(bInLock, &pContext->mutex); } SrvTimerRelease(pTimerRequest); pTimerRequest = NULL; } // Get the next timer request in queue status = SrvTimerGetNextRequest_inlock(pContext, &pTimerRequest); if (status == STATUS_NOT_FOUND) { // If the queue is empty wait for a day or until a request arrives struct timespec tsLong = { .tv_sec = time(NULL) + 86400, .tv_nsec = 0 }; status = STATUS_SUCCESS; do { bRetryWait = FALSE; errCode = pthread_cond_timedwait( &pContext->event, &pContext->mutex, &tsLong); if (errCode == ETIMEDOUT) { if (time(NULL) < tsLong.tv_sec) { bRetryWait = TRUE; continue; } break; } status = LwErrnoToNtStatus(errCode); BAIL_ON_NT_STATUS(status); } while (bRetryWait && !SrvTimerMustStop_inlock(pContext)); continue; } BAIL_ON_NT_STATUS(status); // At this point, we have a timer request - wait for its specified time do { struct timespec ts = {.tv_sec = 0, .tv_nsec = 0}; bRetryWait = FALSE; status = WireNTTimeToTimeSpec(pTimerRequest->llExpiry, &ts); BAIL_ON_NT_STATUS(status); errCode = pthread_cond_timedwait( &pContext->event, &pContext->mutex, &ts); if (errCode == ETIMEDOUT) { status = WireGetCurrentNTTime(&llCurTime); BAIL_ON_NT_STATUS(status); if (llCurTime < pTimerRequest->llExpiry) { bRetryWait = TRUE; continue; } break; } status = LwErrnoToNtStatus(errCode); BAIL_ON_NT_STATUS(status); } while (bRetryWait && !SrvTimerMustStop_inlock(pContext)); } cleanup: LWIO_UNLOCK_MUTEX(bInLock, &pContext->mutex); if (pTimerRequest) { SrvTimerRelease(pTimerRequest); } LWIO_LOG_DEBUG("Srv timer stopping"); return NULL; error: LWIO_LOG_ERROR("Srv timer stopping due to error [%d]", status); goto cleanup; } static NTSTATUS SrvTimerGetNextRequest_inlock( IN PSRV_TIMER_CONTEXT pContext, OUT PSRV_TIMER_REQUEST* ppTimerRequest ) { NTSTATUS status = STATUS_SUCCESS; PSRV_TIMER_REQUEST pTimerRequest = NULL; if (!pContext->pRequests) { status = STATUS_NOT_FOUND; BAIL_ON_NT_STATUS(status); } pTimerRequest = pContext->pRequests; InterlockedIncrement(&pTimerRequest->refCount); *ppTimerRequest = pTimerRequest; cleanup: return status; error: *ppTimerRequest = NULL; goto cleanup; } static NTSTATUS SrvTimerDetachRequest_inlock( IN OUT PSRV_TIMER_CONTEXT pContext, IN OUT PSRV_TIMER_REQUEST pTimerRequest ) { if (pTimerRequest->pPrev) { pTimerRequest->pPrev->pNext = pTimerRequest->pNext; if (pTimerRequest->pNext) { pTimerRequest->pNext->pPrev = pTimerRequest->pPrev; } } else { pContext->pRequests = pTimerRequest->pNext; if (pTimerRequest->pNext) { pTimerRequest->pNext->pPrev = NULL; } } pTimerRequest->pPrev = NULL; pTimerRequest->pNext = NULL; // Removed from timer queue InterlockedDecrement(&pTimerRequest->refCount); return STATUS_SUCCESS; } NTSTATUS SrvTimerPostRequestSpecific( IN PSRV_TIMER pTimer, IN LONG64 llExpiry, IN PVOID pUserData, IN PFN_SRV_TIMER_CALLBACK pfnTimerExpiredCB, OUT PSRV_TIMER_REQUEST* ppTimerRequest ) { NTSTATUS status = STATUS_SUCCESS; PSRV_TIMER_REQUEST pTimerRequest = NULL; PSRV_TIMER_REQUEST pTimerIter = NULL; PSRV_TIMER_REQUEST pPrev = NULL; BOOLEAN bInLock = FALSE; if (!llExpiry) { status = STATUS_INVALID_PARAMETER_1; BAIL_ON_NT_STATUS(status); } if (!pfnTimerExpiredCB) { status = STATUS_INVALID_PARAMETER_3; BAIL_ON_NT_STATUS(status); } status = SrvAllocateMemory( sizeof(SRV_TIMER_REQUEST), (PVOID*)&pTimerRequest); BAIL_ON_NT_STATUS(status); pTimerRequest->refCount = 1; pTimerRequest->llExpiry = llExpiry; pTimerRequest->pUserData = pUserData; pTimerRequest->pfnTimerExpiredCB = pfnTimerExpiredCB; pTimerRequest->bCanceled = FALSE; LWIO_LOCK_MUTEX(bInLock, &pTimer->context.mutex); for (pTimerIter = pTimer->context.pRequests; pTimerIter && (pTimerIter->llExpiry <= llExpiry); pPrev = pTimerIter, pTimerIter = pTimerIter->pNext); if (!pPrev) { pTimerRequest->pNext = pTimer->context.pRequests; if (pTimer->context.pRequests) { pTimer->context.pRequests->pPrev = pTimerRequest; } pTimer->context.pRequests = pTimerRequest; } else { pTimerRequest->pNext = pPrev->pNext; pTimerRequest->pPrev = pPrev; pPrev->pNext = pTimerRequest; if (pTimerRequest->pNext) { pTimerRequest->pNext->pPrev = pTimerRequest; } } // +1 for timer queue InterlockedIncrement(&pTimerRequest->refCount); LWIO_UNLOCK_MUTEX(bInLock, &pTimer->context.mutex); pthread_cond_signal(&pTimer->context.event); // +1 for caller InterlockedIncrement(&pTimerRequest->refCount); *ppTimerRequest = pTimerRequest; cleanup: LWIO_UNLOCK_MUTEX(bInLock, &pTimer->context.mutex); if (pTimerRequest) { SrvTimerRelease(pTimerRequest); } return status; error: *ppTimerRequest = NULL; goto cleanup; }
static NTSTATUS SrvProtocolEnumCandidateConnections( PVOID pKey, PVOID pData, PVOID pUserData, PBOOLEAN pbContinue ) { NTSTATUS ntStatus = STATUS_SUCCESS; PLWIO_SRV_CONNECTION pConnection = (PLWIO_SRV_CONNECTION)pData; PSRV_PROTOCOL_CONNECTION_ENUM_QUERY pConnectionEnumQuery = (PSRV_PROTOCOL_CONNECTION_ENUM_QUERY)pUserData; BOOLEAN bInLock = FALSE; PWSTR pwszClientHost = NULL; if (pConnectionEnumQuery->pQueryAddress) { /* * Look for connections by computer address first in case * that was the qualifier string */ struct addrinfo* pCursor = pConnectionEnumQuery->pQueryAddress; BOOLEAN bMatch = FALSE; for (; !bMatch && (pCursor != NULL); pCursor = pCursor->ai_next) { ntStatus = SrvSocketCompareAddress( pConnection->pClientAddress, pConnection->clientAddrLen, pCursor->ai_addr, pCursor->ai_addrlen, &bMatch); BAIL_ON_NT_STATUS(ntStatus); } if (!bMatch) { pConnection = NULL; } } if (pConnection) { LWIO_LOCK_RWMUTEX_SHARED(bInLock, &pConnection->mutex); ntStatus = SrvSocketAddressToStringW(pConnection->pClientAddress, &pwszClientHost); BAIL_ON_NT_STATUS(ntStatus); pConnectionEnumQuery->pwszClientHost = pwszClientHost; pConnectionEnumQuery->pClientAddress = pConnection->pClientAddress; pConnectionEnumQuery->clientAddrLen = pConnection->clientAddrLen; pConnectionEnumQuery->ulConnectionResId = pConnection->resource.ulResourceId; ntStatus = WireGetCurrentNTTime(&pConnectionEnumQuery->llCurTime); BAIL_ON_NT_STATUS(ntStatus); switch (SrvConnectionGetProtocolVersion(pConnection)) { case SMB_PROTOCOL_VERSION_1: ntStatus = LwRtlRBTreeTraverse( pConnection->pSessionCollection, LWRTL_TREE_TRAVERSAL_TYPE_IN_ORDER, &SrvProtocolProcessCandidateConnection, pConnectionEnumQuery); break; case SMB_PROTOCOL_VERSION_2: ntStatus = LwRtlRBTreeTraverse( pConnection->pSessionCollection, LWRTL_TREE_TRAVERSAL_TYPE_IN_ORDER, &SrvProtocolProcessCandidateConnection2, pConnectionEnumQuery); break; case SMB_PROTOCOL_VERSION_UNKNOWN: /* Ignore connections that are still being established */ break; default: ntStatus = STATUS_INTERNAL_ERROR; break; } BAIL_ON_NT_STATUS(ntStatus); } *pbContinue = TRUE; cleanup: pConnectionEnumQuery->pClientAddress = NULL; pConnectionEnumQuery->clientAddrLen = 0; pConnectionEnumQuery->pwszClientHost = NULL; SRV_SAFE_FREE_MEMORY(pwszClientHost); LWIO_UNLOCK_RWMUTEX(bInLock, &pConnection->mutex); return ntStatus; error: *pbContinue = FALSE; goto cleanup; }