/* Editor Settings: expandtabs and use 4 spaces for indentation
* ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
* -*- mode: c, c-basic-offset: 4 -*- */
/*
* Copyright Likewise Software 2004-2008
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details. You should have received a copy of the GNU General
* Public License along with this program. If not, see
* .
*
* LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
* TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
* WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
* TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
* GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU
* HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
* TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
* license@likewisesoftware.com
*/
/*
* Copyright (C) Likewise Software. All rights reserved.
*
* Module Name:
*
* test_openldap.c
*
* Abstract:
*
* Likewise Security and Authentication Subsystem (LSASS)
*
* Test program
*
* Authors: Danilo Almeida (dalmeida@likewisesoftware.com)
*/
#include "config.h"
#include "lsasystem.h"
#include "lsadef.h"
#include "lsa/lsa.h"
#include "lwmem.h"
#include "lwstr.h"
#include "lwsecurityidentifier.h"
#include "lsautils.h"
#include "lsasrvutils.h"
#include "lwldap.h"
#define GOTO_CLEANUP_ON_ERROR(dwError) \
do { \
if (dwError) \
{ \
goto cleanup; \
} \
} while (0)
#define GOTO_CLEANUP_ON_ERROR_EE(dwError, EE) \
do { \
if (dwError) \
{ \
(EE) = __LINE__; \
goto cleanup; \
} \
} while (0)
DWORD
GetCurrentTime(
OUT time_t* pSeconds,
OUT USEC_T* pMicroSeconds
)
{
DWORD dwError = 0;
time_t seconds = 0;
USEC_T microSeconds = 0;
struct timeval now;
if (gettimeofday(&now, NULL) < 0)
{
dwError = errno;
GOTO_CLEANUP_ON_ERROR(dwError);
}
if (now.tv_sec <= 0)
{
dwError = LW_ERROR_INTERNAL;
GOTO_CLEANUP_ON_ERROR(dwError);
}
if (now.tv_usec <= 0)
{
dwError = LW_ERROR_INTERNAL;
GOTO_CLEANUP_ON_ERROR(dwError);
}
seconds = now.tv_sec;
microSeconds = now.tv_usec;
cleanup:
*pSeconds = seconds;
*pMicroSeconds = microSeconds;
return dwError;
}
static pthread_mutex_t LogMutex = PTHREAD_MUTEX_INITIALIZER;
VOID
LogV(
PCSTR pszFormat,
va_list args
)
{
time_t now = 0;
USEC_T microSeconds = 0;
struct tm nowLocal = { 0 };
char buffer[64];
FILE* fp = stdout;
pthread_mutex_lock(&LogMutex);
GetCurrentTime(&now, µSeconds);
localtime_r(&now, &nowLocal);
strftime(buffer, sizeof(buffer), "%Y/%m/%d-%H:%M:%S", &nowLocal);
fprintf(fp, "%s.%06d - ", buffer, (int) microSeconds);
vfprintf(fp, pszFormat, args);
if (pszFormat && pszFormat[0] && (pszFormat[strlen(pszFormat)-1] != '\n'))
{
fprintf(fp, "\n");
}
fflush(fp);
pthread_mutex_unlock(&LogMutex);
}
VOID
Log(
PCSTR pszFormat,
...
)
{
va_list args;
va_start(args, pszFormat);
LogV(pszFormat, args);
va_end(args);
}
#define LOG(Format, ...) \
Log("[0x%08x] %s() - " Format, \
(unsigned int)pthread_self(), \
__FUNCTION__, \
## __VA_ARGS__)
#define LOG_TID(Format, Id, ...) \
LOG("[%d] - " Format, Id, ## __VA_ARGS__)
DWORD
SearchTest(
IN HANDLE hDirectory,
IN PCSTR pszScopeDn,
IN PCSTR pszQuery,
IN OPTIONAL PDWORD pdwThreadId
)
{
DWORD dwError = 0;
int EE = 0;
LDAPMessage* pMessage = NULL;
LDAP* pLd = NULL;
int count = 0;
PSTR attributes[] = { "distinguishedName", NULL };
int tid = pdwThreadId ? (int) *pdwThreadId : -1;
LOG_TID("Searching scope '%s' for '%s'\n",
tid, pszScopeDn, pszQuery);
dwError = LwLdapDirectorySearch(
hDirectory,
pszScopeDn,
LDAP_SCOPE_SUBTREE,
pszQuery,
attributes,
&pMessage);
GOTO_CLEANUP_ON_ERROR_EE(dwError, EE);
pLd = LwLdapGetSession(hDirectory);
count = ldap_count_entries(pLd, pMessage);
LOG_TID("Got %d entries\n", tid, count);
if (count < 0)
{
dwError = -1;
GOTO_CLEANUP_ON_ERROR_EE(dwError, EE);
}
cleanup:
if (dwError)
{
LOG_TID("dwError = %d, EE = %d", tid, dwError, EE);
}
return dwError;
}
typedef struct _SEARCH_ARGS {
PCSTR pszScopeDn;
PCSTR pszQuery;
} SEARCH_ARGS, *PSEARCH_ARGS;
typedef struct _THREADS_CONTEXT {
HANDLE hDirectory;
DWORD dwRepeatCount;
pthread_mutex_t* pMutex;
pthread_cond_t* pCond;
} THREADS_CONTEXT, *PTHREADS_CONTEXT;
typedef struct _THREAD_CONTEXT {
pthread_t Thread;
pthread_t* pThread;
DWORD dwId;
PTHREADS_CONTEXT pContext;
PSEARCH_ARGS pSearchArgs;
} THREAD_CONTEXT, *PTHREAD_CONTEXT;
void*
SearchTestThread(
IN void* pContext
)
{
DWORD dwError = 0;
int EE = 0;
PTHREAD_CONTEXT pThreadContext = (PTHREAD_CONTEXT) pContext;
DWORD dwIndex = 0;
HANDLE hDirectory = 0;
DWORD dwRepeatCount = 0;
// Just to synchronize thread startup...
pthread_mutex_lock(pThreadContext->pContext->pMutex);
hDirectory = pThreadContext->pContext->hDirectory;
dwRepeatCount = pThreadContext->pContext->dwRepeatCount;
pthread_mutex_unlock(pThreadContext->pContext->pMutex);
for (dwIndex = 0; dwIndex < dwRepeatCount; dwIndex++)
{
dwError = SearchTest(hDirectory,
pThreadContext->pSearchArgs->pszScopeDn,
pThreadContext->pSearchArgs->pszQuery,
&pThreadContext->dwId);
GOTO_CLEANUP_ON_ERROR_EE(dwError, EE);
}
cleanup:
if (dwError)
{
LOG("dwError = %d, EE = %d", dwError, EE);
}
return NULL;
}
DWORD
SearchTestThreaded(
IN HANDLE hDirectory,
IN DWORD dwRepeatCount,
IN DWORD dwThreadCount,
IN DWORD dwSearchArgsCount,
IN PSEARCH_ARGS pSearchArgs
)
{
DWORD dwError = 0;
int EE = 0;
THREADS_CONTEXT ctx = { 0 };
pthread_mutex_t Mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t Cond = PTHREAD_COND_INITIALIZER;
DWORD dwIndex = 0;
PTHREAD_CONTEXT pThreadContext = NULL;
DWORD dwSearchIndex = 0;
BOOLEAN bIsAcquired = FALSE;
dwError = LwAllocateMemory(sizeof(pThreadContext[0]) * dwThreadCount,
(PVOID*) &pThreadContext);
GOTO_CLEANUP_ON_ERROR_EE(dwError, EE);
ctx.hDirectory = hDirectory;
ctx.dwRepeatCount = dwRepeatCount;
ctx.pMutex = &Mutex;
ctx.pCond = &Cond;
pthread_mutex_lock(ctx.pMutex);
bIsAcquired = TRUE;
for (dwIndex = 0; dwIndex < dwThreadCount; dwIndex++)
{
if (dwSearchIndex >= dwSearchArgsCount)
{
dwSearchIndex = 0;
}
pThreadContext[dwIndex].dwId = dwIndex + 1;
pThreadContext[dwIndex].pContext = &ctx;
pThreadContext[dwIndex].pSearchArgs = &pSearchArgs[dwSearchIndex++];
dwError = pthread_create(&pThreadContext[dwIndex].Thread, NULL, SearchTestThread, &pThreadContext[dwIndex]);
GOTO_CLEANUP_ON_ERROR_EE(dwError, EE);
pThreadContext[dwIndex].pThread = &pThreadContext[dwIndex].Thread;
}
pthread_mutex_unlock(ctx.pMutex);
bIsAcquired = FALSE;
cleanup:
if (dwError)
{
LOG("dwError = %d, EE = %d", dwError, EE);
}
if (bIsAcquired)
{
pthread_mutex_unlock(ctx.pMutex);
bIsAcquired = FALSE;
}
if (pThreadContext)
{
for (dwIndex = 0; dwIndex < dwThreadCount; dwIndex++)
{
if (pThreadContext[dwIndex].pThread)
{
void* result = NULL;
pthread_join(pThreadContext[dwIndex].Thread, &result);
}
}
LwFreeMemory(pThreadContext);
}
return dwError;
}
void
usage(
IN PCSTR pszProgram
)
{
printf("usage: %s [ [ ]\n", pszProgram);
exit(1);
}
int
main(
IN int argc,
IN const char* argv[]
)
{
DWORD dwError = 0;
int EE = 0;
int argIndex = 0;
PCSTR pszProgram = argv[argIndex++];
PCSTR pszServerAddress = NULL;
PCSTR pszServerName = NULL;
HANDLE hDirectory = 0;
DWORD dwSearchArgsCount = 0;
PSEARCH_ARGS pSearchArgs = NULL;
DWORD dwIndex = 0;
DWORD dwRepeatCount = 0;
DWORD dwThreadCount = 0;
if (argc < 2)
{
usage(pszProgram);
}
pszServerAddress = argv[argIndex++];
if (argc > argIndex)
{
pszServerName = argv[argIndex++];
}
if (argc > argIndex)
{
int count = atoi(argv[argIndex++]);
if (count <= 0)
{
printf("Invalid repeat count: %d\n", count);
usage(pszProgram);
}
dwRepeatCount = (DWORD) count;
}
if (argc > argIndex)
{
int count = atoi(argv[argIndex++]);
if (count <= 0)
{
printf("Invalid thread count: %d\n", count);
usage(pszProgram);
}
dwThreadCount = (DWORD) count;
}
if ((argc - argIndex) % 2)
{
printf("Invalid # of arguments\n");
usage(pszProgram);
}
dwSearchArgsCount = (argc - argIndex) / 2;
if (dwSearchArgsCount > 0)
{
dwError = LwAllocateMemory(sizeof(*pSearchArgs) * dwSearchArgsCount,
(PVOID*) &pSearchArgs);
GOTO_CLEANUP_ON_ERROR_EE(dwError, EE);
for (dwIndex = 0; dwIndex < dwSearchArgsCount; dwIndex++)
{
pSearchArgs[dwIndex].pszScopeDn = argv[argIndex++];
pSearchArgs[dwIndex].pszQuery = argv[argIndex++];
}
}
LOG("Pinging address '%s'\n", pszServerAddress);
dwError = LwLdapPingTcp(pszServerAddress, 5);
GOTO_CLEANUP_ON_ERROR_EE(dwError, EE);
if (!pszServerName)
{
goto cleanup;
}
LOG("Opening '%s'\n", pszServerName);
dwError = LwLdapOpenDirectoryServer(
pszServerAddress,
pszServerName,
0,
&hDirectory);
GOTO_CLEANUP_ON_ERROR_EE(dwError, EE);
if (dwSearchArgsCount > 0)
{
dwError = SearchTestThreaded(hDirectory, dwRepeatCount, dwThreadCount, dwSearchArgsCount, pSearchArgs);
GOTO_CLEANUP_ON_ERROR_EE(dwError, EE);
}
cleanup:
if (dwError)
{
LOG("dwError = %d (EE = %d)", dwError, EE);
printf("ERROR\n");
}
else
{
printf("SUCCESS\n");
}
return dwError;
}