/* 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:
*
* main.c
*
* Abstract:
*
* Likewise IO (LWIO)
*
* Test Program for exercising SMB Client API
*
* Authors: Sriram Nambakam (snambakam@likewisesoftware.com)
*
*/
#define _POSIX_PTHREAD_SEMANTICS 1
#include "config.h"
#include "lwiosys.h"
#include "lwio/lwio.h"
#include "lwiodef.h"
#include "lwioutils.h"
pthread_mutex_t gNpClientTestMutex = PTHREAD_MUTEX_INITIALIZER;
ULONG gNumIterations = 5;
BOOLEAN gbExitProcess = FALSE;
static
NTSTATUS
CreatePipeClient(
const char * pipename,
IO_FILE_HANDLE * pFileHandle
);
static
PVOID
ClientPipeThread(
PIO_FILE_HANDLE pFileHandle
);
static
NTSTATUS
HandleSignals(
VOID
);
static
VOID
InterruptHandler(
int sig
);
static
NTSTATUS
BlockSignals(
VOID
);
static
int
GetNextSignal(
VOID
);
static
VOID
GetBlockedSignals(
sigset_t* pBlockedSignals
);
static
VOID
GetBlockedSignalsSansInterrupt(
sigset_t* pBlockedSignals
);
static
BOOLEAN
ProcessMustExit(
VOID
);
static
VOID
SetProcessMustExit(
BOOLEAN bExit
);
int
main(
int argc,
char** argv
)
{
NTSTATUS ntStatus = 0;
ULONG i = 0;
int nConnections = 0;
int nActiveConnections = 0;
char *pipename = NULL;
IO_FILE_HANDLE FileHandles[100];
pthread_t* pThreadArray = NULL;
memset(FileHandles, 0, sizeof(FileHandles));
if (argc < 4)
{
printf("Usage: test_npclient2 \n");
exit(1);
}
pipename = argv[1];
nConnections = atoi(argv[2]);
gNumIterations = atoi(argv[3]);
if (nConnections < 0)
{
printf("Usage: test_npclient2 \n");
exit(1);
}
ntStatus = BlockSignals();
BAIL_ON_NT_STATUS(ntStatus);
ntStatus = SMBAllocateMemory(
sizeof(pthread_t) * nConnections,
(PVOID*)&pThreadArray);
BAIL_ON_NT_STATUS(ntStatus);
for (i = 0; i < nConnections; i++)
{
pthread_t* pThread = &pThreadArray[i];
ntStatus = 0;
do
{
ntStatus = CreatePipeClient(
pipename,
&FileHandles[i]
);
if (ntStatus == STATUS_PIPE_NOT_AVAILABLE)
{
printf("pipe not available. waiting...\n");
sleep(5);
}
else
{
BAIL_ON_NT_STATUS(ntStatus);
}
} while (!ProcessMustExit() && (ntStatus == STATUS_PIPE_NOT_AVAILABLE));
ntStatus = LwErrnoToNtStatus(pthread_create(pThread, NULL, (void *)&ClientPipeThread, &FileHandles[i]));
BAIL_ON_NT_STATUS(ntStatus);
nActiveConnections++;
}
ntStatus = HandleSignals();
BAIL_ON_NT_STATUS(ntStatus);
cleanup:
if (nActiveConnections)
{
int iConnection = 0;
for(; iConnection < nActiveConnections; iConnection++)
{
pthread_t* pThread = &pThreadArray[iConnection];
// TODO: Need these threads to be interruptible
pthread_join(*pThread, NULL);
}
SMBFreeMemory(pThreadArray);
}
return ntStatus;
error:
goto cleanup;
}
static
NTSTATUS
CreatePipeClient(
const char * pipename,
IO_FILE_HANDLE * pFileHandle
)
{
NTSTATUS ntStatus = 0;
PSTR smbpath = NULL;
//PIO_ACCESS_TOKEN acctoken = NULL;
IO_FILE_NAME filename = { 0 };
IO_STATUS_BLOCK io_status = { 0 };
IO_FILE_HANDLE FileHandle = NULL;
ntStatus = LwRtlCStringAllocatePrintf(
&smbpath,
"\\npfs\\%s",
(char*) pipename);
BAIL_ON_NT_STATUS(ntStatus);
filename.RootFileHandle = NULL;
filename.IoNameOptions = 0;
ntStatus = LwRtlWC16StringAllocateFromCString(
&filename.FileName,
smbpath
);
BAIL_ON_NT_STATUS(ntStatus);
ntStatus = NtCreateFile(
&FileHandle,
NULL,
&io_status,
&filename,
NULL,
NULL,
GENERIC_READ | GENERIC_WRITE,
0,
0,
FILE_SHARE_WRITE | FILE_SHARE_READ,
FILE_OPEN,
0,
NULL,
0,
NULL
);
BAIL_ON_NT_STATUS(ntStatus);
*pFileHandle = FileHandle;
return(ntStatus);
error:
*pFileHandle = NULL;
return ntStatus;
}
PVOID
ClientPipeThread(
PIO_FILE_HANDLE pFileHandle
)
{
NTSTATUS ntStatus = 0;
BYTE InBuffer[2048];
BYTE OutBuffer[2048];
ULONG InLength = 0;
ULONG InBytesRead = 0;
ULONG OutBytesWritten = 0;
IO_STATUS_BLOCK io_status = {0};
IO_FILE_HANDLE FileHandle = NULL;
ULONG i = 0;
printf("Client thread [%zd] starting\n", (size_t)pthread_self());
FileHandle = *pFileHandle;
while (!ProcessMustExit() && (i++ < gNumIterations)) {
memset(OutBuffer, 0, sizeof(OutBuffer));
sprintf((char *)OutBuffer,"The quick brown fox jumps over the lazy dog\n");
OutBytesWritten = strlen((char*)OutBuffer)+1;
ntStatus = NtWriteFile(
FileHandle,
NULL,
&io_status,
OutBuffer,
OutBytesWritten,
NULL,
NULL
);
BAIL_ON_NT_STATUS(ntStatus);
OutBytesWritten = io_status.BytesTransferred;
memset(&io_status, 0, sizeof(io_status));
memset(InBuffer, 0, sizeof(InBuffer));
InLength = sizeof(InBuffer);
ntStatus = NtReadFile(
FileHandle,
NULL,
&io_status,
InBuffer,
InLength,
NULL,
NULL
);
BAIL_ON_NT_STATUS(ntStatus);
InBytesRead = io_status.BytesTransferred;
if (InBytesRead == OutBytesWritten) {
printf("Successful echo [Thr:%zd]:%s\n", (size_t)pthread_self(), InBuffer);
}
}
cleanup:
if (FileHandle)
{
NtCloseFile(FileHandle);
}
printf("Client thread [%zd] ending\n", (size_t)pthread_self());
return NULL;
error:
goto cleanup;
}
static
NTSTATUS
HandleSignals(
VOID
)
{
NTSTATUS ntStatus = 0;
BOOLEAN bDone = FALSE;
struct sigaction action;
sigset_t catch_signal_mask;
// After starting up threads, we now want to handle SIGINT async
// instead of using sigwait() on it. The reason for this is so
// that a debugger (such as gdb) can break in properly.
// See http://sourceware.org/ml/gdb/2007-03/msg00145.html and
// http://bugzilla.kernel.org/show_bug.cgi?id=9039.
memset(&action, 0, sizeof(action));
action.sa_handler = InterruptHandler;
if (sigaction(SIGINT, &action, NULL) != 0)
{
ntStatus = LwErrnoToNtStatus(errno);
BAIL_ON_NT_STATUS(ntStatus);
}
// Unblock SIGINT
sigemptyset(&catch_signal_mask);
sigaddset(&catch_signal_mask, SIGINT);
ntStatus = LwErrnoToNtStatus(pthread_sigmask(SIG_UNBLOCK, &catch_signal_mask, NULL));
BAIL_ON_NT_STATUS(ntStatus);
while (!bDone)
{
switch (GetNextSignal())
{
case SIGINT:
case SIGTERM:
SetProcessMustExit(TRUE);
bDone = TRUE;
break;
default:
break;
}
}
error:
return ntStatus;
}
static
VOID
InterruptHandler(
int sig
)
{
if (sig == SIGINT)
{
raise(SIGTERM);
}
}
static
NTSTATUS
BlockSignals(
VOID
)
{
sigset_t blockedSignals;
GetBlockedSignals(&blockedSignals);
return LwErrnoToNtStatus(pthread_sigmask(SIG_BLOCK, &blockedSignals, NULL));
}
static
int
GetNextSignal(
VOID
)
{
sigset_t blockedSignals;
int sig = 0;
GetBlockedSignalsSansInterrupt(&blockedSignals);
sigwait(&blockedSignals, &sig);
return sig;
}
static
VOID
GetBlockedSignals(
sigset_t* pBlockedSignals
)
{
sigemptyset(pBlockedSignals);
sigaddset(pBlockedSignals, SIGTERM);
sigaddset(pBlockedSignals, SIGINT);
sigaddset(pBlockedSignals, SIGPIPE);
sigaddset(pBlockedSignals, SIGHUP);
}
static
VOID
GetBlockedSignalsSansInterrupt(
sigset_t* pBlockedSignals
)
{
sigemptyset(pBlockedSignals);
sigaddset(pBlockedSignals, SIGTERM);
sigaddset(pBlockedSignals, SIGPIPE);
sigaddset(pBlockedSignals, SIGHUP);
}
static
BOOLEAN
ProcessMustExit(
VOID
)
{
BOOLEAN bExit = FALSE;
pthread_mutex_lock(&gNpClientTestMutex);
bExit = gbExitProcess;
pthread_mutex_unlock(&gNpClientTestMutex);
return bExit;
}
static
VOID
SetProcessMustExit(
BOOLEAN bExit
)
{
pthread_mutex_lock(&gNpClientTestMutex);
gbExitProcess = bExit;
pthread_mutex_unlock(&gNpClientTestMutex);
}