/* 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"
static
NTSTATUS
CreateServerConnection(
const char * pipename,
IO_FILE_HANDLE * pFileHandle
);
static
NTSTATUS
NtConnectNamedPipe(
IO_FILE_HANDLE FileHandle
);
static
PVOID
ServerPipeThread(
PIO_FILE_HANDLE pFileHandle
);
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
);
int
main(int argc,
char **argv
)
{
ULONG i = 0;
int nConnections = 0;
int nActiveConnections = 0;
NTSTATUS ntStatus = 0;
char *pipename = NULL;
IO_FILE_HANDLE FileHandles[100];
pthread_t* pThreadArray = NULL;
memset(FileHandles, 0, sizeof(FileHandles));
if (argc < 3)
{
printf("Usage: test_npserver \n");
exit(1);
}
pipename = argv[1];
nConnections = atoi(argv[2]);
if (nConnections < 0)
{
printf("Usage: test_npserver \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 = CreateServerConnection(
pipename,
&FileHandles[i]
);
BAIL_ON_NT_STATUS(ntStatus);
ntStatus = LwErrnoToNtStatus(pthread_create(pThread, NULL, (void *)&ServerPipeThread, &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
CreateServerConnection(
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 };
ULONG NamedPipeType = 0;
ULONG ReadMode = 0;
ULONG CompletionMode = 0;
ULONG MaximumInstances =0;
ULONG InboundQuota = 0;
ULONG OutboundQuota = 0;
LONG64 DefaultTimeOut = 0;
IO_FILE_HANDLE FileHandle = NULL;
if (!pipename || !*pipename)
{
ntStatus = STATUS_INVALID_PARAMETER_1;
}
BAIL_ON_NT_STATUS(ntStatus);
ntStatus = LwRtlCStringAllocatePrintf(
&smbpath,
"\\npfs\\%s",
(char*) pipename);
BAIL_ON_NT_STATUS(ntStatus);
ntStatus = LwRtlWC16StringAllocateFromCString(
&filename.FileName,
smbpath
);
BAIL_ON_NT_STATUS(ntStatus);
ntStatus = NtCreateNamedPipeFile(
&FileHandle,
NULL,
&io_status,
&filename,
NULL,
NULL,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
FILE_CREATE,
0,
NamedPipeType,
ReadMode,
CompletionMode,
MaximumInstances,
InboundQuota,
OutboundQuota,
&DefaultTimeOut
);
BAIL_ON_NT_STATUS(ntStatus);
ntStatus = NtConnectNamedPipe(
FileHandle
);
BAIL_ON_NT_STATUS(ntStatus);
*pFileHandle = FileHandle;
cleanup:
return(ntStatus);
error:
*pFileHandle = NULL;
goto cleanup;
}
static
PVOID
ServerPipeThread(
PIO_FILE_HANDLE pFileHandle
)
{
NTSTATUS ntStatus = 0;
BYTE InBuffer[2048];
ULONG InLength = 0;
ULONG InBytesRead = 0;
ULONG OutBytesWritten = 0;
IO_FILE_HANDLE FileHandle = {0};
IO_STATUS_BLOCK io_status;
FileHandle = *pFileHandle;
while (1) {
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;
ntStatus = NtWriteFile(
FileHandle,
NULL,
&io_status,
InBuffer,
InBytesRead,
NULL,
NULL
);
BAIL_ON_NT_STATUS(ntStatus);
OutBytesWritten = io_status.BytesTransferred;
}
cleanup:
printf("Server Thread While loop terminated with %x\n", ntStatus);
if (FileHandle)
{
NtCloseFile(FileHandle);
}
return NULL;
error:
goto cleanup;
}
static
NTSTATUS
NtConnectNamedPipe(
IO_FILE_HANDLE FileHandle
)
{
NTSTATUS ntStatus = 0;
IO_STATUS_BLOCK IoStatusBlock = {0};
ntStatus = NtFsControlFile(
FileHandle,
NULL,
&IoStatusBlock,
0x2,
NULL,
0,
NULL,
0
);
return(ntStatus);
}
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:
bDone = TRUE;
break;
default:
break;
}
}
error:
return ntStatus;
}
static
VOID
InterruptHandler(
int sig
)
{
if (sig == SIGINT)
{
raise(SIGTERM);
}
}
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);
}