mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1280 lines
29 KiB
1280 lines
29 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
tlpipe.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code for the named pipe transport layer
|
|
which explicitly deals with the machanics of doing named pipes.
|
|
|
|
Author:
|
|
|
|
Jim Schaad (jimsch) 11-Jun-93
|
|
Wesley Witt (wesw) 25-Nov-93
|
|
|
|
Environment:
|
|
|
|
Win32 User
|
|
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#ifndef OSDEBUG4
|
|
#include "defs.h"
|
|
#endif
|
|
|
|
|
|
#include "od.h"
|
|
#include "dbgver.h"
|
|
|
|
#include "xport.h"
|
|
#include "tlpipe.h"
|
|
|
|
#ifdef OSDEBUG4
|
|
TLIS Tlis = {
|
|
TRUE, // fCanSetup
|
|
0xffffffff, // dwMaxPacket
|
|
0xffffffff, // dwOptPacket
|
|
TLISINFOSIZE, // dwInfoSize ?? what is this for ??
|
|
TRUE, // fRemote
|
|
#if defined(_M_IX86)
|
|
mptix86, // mpt
|
|
mptix86, // mptRemote
|
|
#elif defined(_M_MRX000)
|
|
mptmips, // mpt
|
|
mptmips, // mptRemote
|
|
#elif defined(_M_ALPHA)
|
|
mptdaxp, // mpt
|
|
mptdaxp, // mptRemote
|
|
#else
|
|
#error( "unknown target machine" );
|
|
#endif
|
|
{ "Named Pipe Transport Layer (PIPE:)" } // rgchInfo
|
|
};
|
|
|
|
LPTLIS
|
|
TlGetInfo(
|
|
VOID
|
|
)
|
|
{
|
|
return &Tlis;
|
|
}
|
|
#endif
|
|
|
|
#ifdef DEBUGVER
|
|
DEBUG_VERSION('T','L',"Named Pipe Transport Layer (Debug)")
|
|
#else
|
|
RELEASE_VERSION('T','L',"Named Pipe Transport Layer")
|
|
#endif
|
|
|
|
DBGVERSIONCHECK()
|
|
|
|
|
|
extern CRITICAL_SECTION csExpecting;
|
|
|
|
BOOL FVerbose = FALSE;
|
|
BOOL FPipeConnected = FALSE;
|
|
HANDLE HandleNamedPipe = INVALID_HANDLE_VALUE;
|
|
HANDLE HReadThread;
|
|
HANDLE HControlReadThread;
|
|
OVERLAPPED OverlappedPipe;
|
|
OVERLAPPED OverlappedRead;
|
|
OVERLAPPED OverlappedWrite;
|
|
CRITICAL_SECTION CsWritePipe;
|
|
CHAR RgchPipeName[MAX_PATH];
|
|
BOOL FDMSide = FALSE;
|
|
struct {
|
|
char * lpb;
|
|
int cb;
|
|
} RgQueue[SIZE_OF_QUEUE];
|
|
int IQueueFront = 0;
|
|
int IQueueBack = 0;
|
|
CRITICAL_SECTION CsQueue = {0};
|
|
HANDLE HQueueEvent;
|
|
HANDLE HCallbackThread;
|
|
CHAR SzRemoteHostName[MAX_PATH];
|
|
CHAR SzRemotePipeName[MAX_PATH];
|
|
|
|
REPLY RgReplys[SIZE_OF_REPLYS];
|
|
CRITICAL_SECTION CsReplys;
|
|
int IReplys;
|
|
|
|
char * RgSzTypes[] = {"FirstAsync", "Async", "FirstReply", "Reply",
|
|
"Disconnect", "VersionRequest", "VersionReply"};
|
|
char * SzTypes(unsigned int i)
|
|
{
|
|
static char rgch[20];
|
|
if (i > sizeof(RgSzTypes)/sizeof(RgSzTypes[0])) {
|
|
sprintf(rgch, "Type %x", i);
|
|
return rgch;
|
|
} else {
|
|
return RgSzTypes[i];
|
|
}
|
|
}
|
|
|
|
|
|
//#define TL_ERROR_LOGGING 1
|
|
|
|
|
|
#ifdef TL_ERROR_LOGGING
|
|
|
|
typedef struct {
|
|
DWORD ty;
|
|
DWORD ec;
|
|
DWORD cb;
|
|
DWORD ln;
|
|
DWORD td;
|
|
LPDWORD ob;
|
|
LPDWORD p;
|
|
} ERRLOG;
|
|
|
|
#define LOGIT(x,y,z,q) {el[ei].ty=x;el[ei].ec=y;el[ei].cb=z;el[ei].ln=__LINE__; \
|
|
el[ei].td=GetCurrentThreadId(); \
|
|
el[ei].ob=(LPDWORD)q; \
|
|
el[ei].p=(LPDWORD)malloc(z);memcpy(el[ei].p,q,z); \
|
|
printel2(ei); \
|
|
ei++; \
|
|
if (ei==99) ei=0;}
|
|
#define LGREAD 1
|
|
#define LGWRITE 2
|
|
ERRLOG el[100];
|
|
DWORD ei=0;
|
|
|
|
void printel( void )
|
|
{
|
|
DWORD i;
|
|
|
|
for (i=0; i<ei; i++) {
|
|
DebugPrint( "%d\t%d\t%x\t%d\t%08x\t%08x\t%x\n",
|
|
el[i].ty,
|
|
el[i].ec,
|
|
el[i].cb,
|
|
el[i].ln,
|
|
el[i].p,
|
|
el[i].ob,
|
|
el[i].td
|
|
);
|
|
}
|
|
}
|
|
|
|
void printel2( int i )
|
|
{
|
|
DebugPrint( "%d\t%d\t%x\t%d\t%08x\t%08x\t%x\n",
|
|
el[i].ty,
|
|
el[i].ec,
|
|
el[i].cb,
|
|
el[i].ln,
|
|
el[i].p,
|
|
el[i].ob,
|
|
el[i].td
|
|
);
|
|
}
|
|
|
|
#else
|
|
|
|
#define LOGIT(x,y,z,q)
|
|
#define LGREAD 1
|
|
#define LGWRITE 2
|
|
|
|
#endif
|
|
|
|
XOSD PipeConnect(HANDLE,DWORD);
|
|
BOOL PipeClose(void);
|
|
DWORD ReadFromPipe(PUCHAR,DWORD);
|
|
DWORD ReaderThread(LPVOID arg);
|
|
DWORD ControlReaderThread(LPVOID arg);
|
|
DWORD CallbackThread(LPVOID lpvArg);
|
|
|
|
int FAR PASCAL
|
|
CopyString(
|
|
LPSTR * lplps,
|
|
LPSTR lpT,
|
|
char chEscape,
|
|
BOOL fQuote
|
|
);
|
|
|
|
BOOL
|
|
CreateStuff(
|
|
VOID
|
|
)
|
|
{
|
|
int i = 0;
|
|
|
|
if (FDMSide && HReadThread) {
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef TL_ERROR_LOGGING
|
|
if (i=1) printel();
|
|
#endif
|
|
|
|
TlControlInitialization();
|
|
|
|
//
|
|
// Create random data strutures needed internally
|
|
//
|
|
|
|
OverlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (OverlappedRead.hEvent == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
OverlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (OverlappedWrite.hEvent == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
InitializeCriticalSection( &CsQueue );
|
|
HQueueEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
InitializeCriticalSection( &CsReplys );
|
|
for (i=0; i<SIZE_OF_REPLYS; i++) {
|
|
RgReplys[i].hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
}
|
|
|
|
InitializeCriticalSection(&CsWritePipe);
|
|
|
|
#if DBG
|
|
InitializeCriticalSection(&csExpecting);
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
StartWorkerThreads(
|
|
BOOL fStartControlReader
|
|
)
|
|
{
|
|
DWORD id;
|
|
|
|
|
|
|
|
//
|
|
// start the debugger pipe reader thread
|
|
//
|
|
HReadThread = CreateThread(NULL, 0, ReaderThread, 0, 0, &id);
|
|
if (!HReadThread) {
|
|
return FALSE;
|
|
}
|
|
SetThreadPriority( HReadThread, THREAD_PRIORITY_ABOVE_NORMAL );
|
|
|
|
if (fStartControlReader) {
|
|
//
|
|
// start the control pipe reader thread, << ONLY FOR CLIENTS >>
|
|
//
|
|
HControlReadThread = CreateThread(NULL, 0, ControlReaderThread, 0, 0, &id);
|
|
if (!HControlReadThread) {
|
|
TerminateThread( HReadThread, 0 );
|
|
return FALSE;
|
|
}
|
|
SetThreadPriority( HControlReadThread, THREAD_PRIORITY_ABOVE_NORMAL );
|
|
}
|
|
|
|
//
|
|
// start the callback thread
|
|
//
|
|
HCallbackThread = CreateThread(NULL, 0, CallbackThread, 0, 0, &id);
|
|
if (!HCallbackThread) {
|
|
TerminateThread( HControlReadThread, 0 );
|
|
TerminateThread( HReadThread, 0 );
|
|
return FALSE;
|
|
}
|
|
SetThreadPriority( HCallbackThread, THREAD_PRIORITY_ABOVE_NORMAL );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
DestroyStuff(
|
|
VOID
|
|
)
|
|
{
|
|
int i;
|
|
|
|
//
|
|
// If there is a reader thread -- then wait for it to be termianted
|
|
// and close the handle
|
|
//
|
|
if (HReadThread) {
|
|
TerminateThread( HReadThread, 0 );
|
|
WaitForSingleObject(HReadThread, INFINITE);
|
|
CloseHandle(HReadThread);
|
|
HReadThread = NULL;
|
|
}
|
|
|
|
//
|
|
// If there is a control thread -- then wait for it to be termianted
|
|
// and close the handle
|
|
//
|
|
if (HControlReadThread) {
|
|
TerminateThread( HControlReadThread, 0 );
|
|
WaitForSingleObject(HControlReadThread, INFINITE);
|
|
CloseHandle(HControlReadThread);
|
|
HControlReadThread = NULL;
|
|
}
|
|
|
|
if (HCallbackThread) {
|
|
TerminateThread( HCallbackThread, 0 );
|
|
WaitForSingleObject(HCallbackThread, INFINITE);
|
|
CloseHandle(HCallbackThread);
|
|
HCallbackThread = NULL;
|
|
}
|
|
|
|
//
|
|
// Now delete all of the objects
|
|
//
|
|
CloseHandle(HQueueEvent);
|
|
CloseHandle(OverlappedRead.hEvent);
|
|
CloseHandle(OverlappedWrite.hEvent);
|
|
DeleteCriticalSection(&CsQueue);
|
|
DeleteCriticalSection(&CsReplys);
|
|
DeleteCriticalSection(&CsWritePipe);
|
|
for (i=0; i<SIZE_OF_REPLYS; i++) {
|
|
CloseHandle(RgReplys[i].hEvent);
|
|
}
|
|
|
|
#if DBG
|
|
DeleteCriticalSection(&csExpecting);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
TlPipeFailure(
|
|
VOID
|
|
)
|
|
{
|
|
int i;
|
|
static int f = FALSE;
|
|
|
|
if (f) {
|
|
return;
|
|
}
|
|
f = TRUE;
|
|
EnterCriticalSection(&CsReplys);
|
|
for (i=0; i<IReplys; i++) {
|
|
SetEvent(RgReplys[i].hEvent);
|
|
}
|
|
LeaveCriticalSection(&CsReplys);
|
|
ControlPipeFailure();
|
|
f = FALSE;
|
|
return;
|
|
}
|
|
|
|
|
|
XOSD
|
|
TlCreateTransport(
|
|
LPSTR szName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates the pipe which will be connected to windbgrm (server).
|
|
|
|
Arguments:
|
|
|
|
szName - Supplies the name of the pipe to create
|
|
|
|
Return Value:
|
|
|
|
XOSD error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
SECURITY_DESCRIPTOR securityDescriptor;
|
|
SECURITY_ATTRIBUTES lsa;
|
|
DWORD error;
|
|
|
|
|
|
if (!CreateStuff()) {
|
|
return xosdUnknown;
|
|
}
|
|
|
|
if (TlCreateControlPipe( szName ) != xosdNone) {
|
|
return xosdBadPipeName;
|
|
}
|
|
|
|
DEBUG_OUT(("TlCreateTransport: Create ServerPipe\n"));
|
|
|
|
//
|
|
// create the event used for overlapped io
|
|
//
|
|
OverlappedPipe.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (OverlappedPipe.hEvent == NULL) {
|
|
return xosdUnknown;
|
|
}
|
|
|
|
//
|
|
// Set a security descriptor
|
|
//
|
|
InitializeSecurityDescriptor( &securityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION );
|
|
SetSecurityDescriptorDacl( &securityDescriptor, TRUE, NULL, FALSE );
|
|
lsa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
lsa.lpSecurityDescriptor = &securityDescriptor;
|
|
lsa.bInheritHandle = TRUE;
|
|
|
|
_snprintf(RgchPipeName, sizeof(RgchPipeName), PIPE_NAME_FORMAT,
|
|
".", szName ? szName : DEFAULT_PIPE);
|
|
|
|
HandleNamedPipe = CreateNamedPipe( RgchPipeName,
|
|
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
|
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE |
|
|
PIPE_WAIT,
|
|
1,
|
|
PIPE_BUFFER_SIZE,
|
|
PIPE_BUFFER_SIZE,
|
|
1000,
|
|
&lsa
|
|
);
|
|
|
|
if (HandleNamedPipe == INVALID_HANDLE_VALUE) {
|
|
error = GetLastError();
|
|
DEBUG_OUT1("TLCreateTransport: failed Error %u\n", error);
|
|
return xosdBadPipeName;
|
|
}
|
|
|
|
FPipeConnected = FALSE;
|
|
|
|
StartWorkerThreads( FALSE );
|
|
|
|
return xosdNone;
|
|
}
|
|
|
|
|
|
XOSD
|
|
TlConnectTransport(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function attempts to connect the server pipe to a client.
|
|
|
|
Arguments:
|
|
|
|
szName - Supplies the name of the pipe to create
|
|
|
|
Return Value:
|
|
|
|
XOSD error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD ec;
|
|
DWORD status;
|
|
|
|
|
|
if (TlConnectControlPipe() != xosdNone) {
|
|
return xosdCannotConnect;
|
|
}
|
|
|
|
if (FPipeConnected) {
|
|
return xosdNone;
|
|
}
|
|
|
|
FPipeConnected = ConnectNamedPipe( HandleNamedPipe, &OverlappedPipe);
|
|
|
|
if (!FPipeConnected) {
|
|
ec = GetLastError();
|
|
switch( ec ) {
|
|
case ERROR_PIPE_CONNECTED:
|
|
goto connected;
|
|
|
|
case ERROR_IO_PENDING:
|
|
break;
|
|
|
|
default:
|
|
DEBUG_OUT1("PLPIPE: ConnectNamedPipe failed, Error %u\n", ec);
|
|
//DebugPrint("ConnectNamedPipe failed, Error=%u\n", ec);
|
|
return xosdCannotConnect;
|
|
}
|
|
|
|
status = WaitForSingleObject( OverlappedPipe.hEvent,
|
|
MAX_CONNECT_WAIT * 1000 );
|
|
switch ( status ) {
|
|
case WAIT_OBJECT_0:
|
|
goto connected;
|
|
|
|
case WAIT_TIMEOUT:
|
|
//DebugPrint("ConnectNamedPipe timed out\n");
|
|
return xosdCannotConnect;
|
|
break;
|
|
|
|
default:
|
|
ec = GetLastError();
|
|
DEBUG_OUT2(
|
|
"PLPIPE: ConnectNamedPipe failed, Status %u, ec=%u\n",
|
|
status, ec);
|
|
//DebugPrint("ConnectNamedPipe failed, Error=%u\n", ec);
|
|
return xosdCannotConnect;
|
|
}
|
|
}
|
|
|
|
connected:
|
|
FPipeConnected = TRUE;
|
|
|
|
return xosdNone;
|
|
}
|
|
|
|
XOSD
|
|
TlCreateClient(
|
|
LPSTR szName
|
|
)
|
|
{
|
|
HANDLE handle = INVALID_HANDLE_VALUE;
|
|
DWORD timeOut;
|
|
DWORD mode;
|
|
XOSD xosd = xosdNone;
|
|
DWORD error;
|
|
char * lpsz;
|
|
|
|
|
|
if (!CreateStuff()) {
|
|
return xosdUnknown;
|
|
}
|
|
|
|
if (szName) {
|
|
lpsz = szName;
|
|
while (*lpsz && isspace(*lpsz)) {
|
|
lpsz++;
|
|
}
|
|
|
|
*SzRemoteHostName = 0;
|
|
*SzRemotePipeName = 0;
|
|
|
|
if (CopyString(&lpsz, SzRemoteHostName, '\\', *lpsz == '"') > 0) {
|
|
while (*lpsz && isspace(*lpsz)) {
|
|
lpsz++;
|
|
}
|
|
CopyString(&lpsz, SzRemotePipeName, '\\', *lpsz == '"');
|
|
}
|
|
|
|
if ((xosd = TlCreateClientControlPipe(SzRemoteHostName,
|
|
SzRemotePipeName)) != xosdNone) {
|
|
return xosd;
|
|
}
|
|
|
|
if (HandleNamedPipe != INVALID_HANDLE_VALUE) {
|
|
DEBUG_OUT(("Named pipe is already open\n"));
|
|
return xosdNone;
|
|
}
|
|
|
|
DEBUG_OUT(("PLPIPE: OpenClientPipe\n"));
|
|
}
|
|
|
|
if ( (szName == NULL) || (*SzRemoteHostName == 0) ) {
|
|
_snprintf( RgchPipeName, sizeof(RgchPipeName), PIPE_NAME_FORMAT,
|
|
DEFAULT_SERVER, DEFAULT_PIPE );
|
|
} else {
|
|
_snprintf(RgchPipeName, sizeof(RgchPipeName), PIPE_NAME_FORMAT,
|
|
SzRemoteHostName, SzRemotePipeName);
|
|
}
|
|
|
|
timeOut = TlUtilTime() + 10;
|
|
while ((handle == INVALID_HANDLE_VALUE) && (TlUtilTime() < timeOut)) {
|
|
|
|
WaitNamedPipe( RgchPipeName, 10000 );
|
|
|
|
handle = CreateFile( RgchPipeName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
|
NULL );
|
|
|
|
if (handle == INVALID_HANDLE_VALUE) {
|
|
//
|
|
// server doesn't exist, don't wait around.
|
|
//
|
|
|
|
if (GetLastError() == ERROR_BAD_NETPATH) {
|
|
break;
|
|
}
|
|
Sleep(500);
|
|
}
|
|
}
|
|
|
|
if ( handle == INVALID_HANDLE_VALUE ) {
|
|
|
|
error = GetLastError();
|
|
DEBUG_OUT1("PLPIPE: CreateFile failed Error %u\n", error);
|
|
switch (error) {
|
|
case ERROR_BAD_NETPATH:
|
|
xosd = xosdBadPipeServer;
|
|
break;
|
|
|
|
case ERROR_FILE_NOT_FOUND:
|
|
xosd = xosdBadPipeName;
|
|
break;
|
|
|
|
default:
|
|
xosd = xosdBadPipeServer;
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
|
|
mode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
|
|
|
|
if ( !SetNamedPipeHandleState( handle, &mode, NULL, NULL ) ) {
|
|
DEBUG_OUT1("PLPIPE: SetNamedPipeHandleState failed, Error %u\n",
|
|
GetLastError());
|
|
xosd = xosdBadPipeName;
|
|
}
|
|
|
|
DEBUG_OUT(( "PLPIPE: Opened client side of pipe\n" ));
|
|
DEBUG_OUT(( "PLPIPE: Connected\n" ));
|
|
|
|
HandleNamedPipe = handle;
|
|
FPipeConnected = TRUE;
|
|
|
|
StartWorkerThreads( TRUE );
|
|
}
|
|
|
|
return(xosd);
|
|
}
|
|
|
|
|
|
XOSD
|
|
TlDestroyTransport(
|
|
VOID
|
|
)
|
|
{
|
|
if (FPipeConnected) {
|
|
FPipeConnected = FALSE;
|
|
if (!FDMSide) {
|
|
DestroyStuff();
|
|
}
|
|
TlDisconnectTransport();
|
|
if (!FDMSide) {
|
|
PipeClose();
|
|
CloseHandle(OverlappedPipe.hEvent);
|
|
}
|
|
}
|
|
return xosdNone;
|
|
}
|
|
|
|
|
|
BOOL
|
|
TlDisconnectTransport(
|
|
VOID
|
|
)
|
|
{
|
|
BOOL Ok = TRUE;
|
|
DWORD Error;
|
|
|
|
DEBUG_OUT("PipeDisconnect\n");
|
|
|
|
Ok = DisconnectNamedPipe( HandleNamedPipe );
|
|
|
|
if ( !Ok ) {
|
|
|
|
Error = GetLastError();
|
|
|
|
switch( Error ) {
|
|
|
|
case ERROR_PIPE_NOT_CONNECTED:
|
|
Ok = TRUE;
|
|
break;
|
|
|
|
default:
|
|
DEBUG_OUT1("DisconnectNamedPipe failed, Error %u\n", Error);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( Ok ) {
|
|
DEBUG_OUT(( "PLPIPE: Disconnected\n" ));
|
|
FPipeConnected = FALSE;
|
|
}
|
|
|
|
return Ok;
|
|
}
|
|
|
|
|
|
BOOL
|
|
PipeClose(
|
|
void
|
|
)
|
|
{
|
|
BOOL Ok = TRUE;
|
|
|
|
DEBUG_OUT(("PLPIPE: PipeClose\n"));
|
|
|
|
if ( HandleNamedPipe != INVALID_HANDLE_VALUE ) {
|
|
|
|
if ( FDMSide && FPipeConnected ) {
|
|
|
|
DEBUG_OUT( ("PLPIPE: Pipe being closed without disconnecting\n") );
|
|
Ok = FALSE;
|
|
|
|
} else {
|
|
|
|
CloseHandle( HandleNamedPipe );
|
|
HandleNamedPipe = INVALID_HANDLE_VALUE;
|
|
FPipeConnected = FALSE;
|
|
DEBUG_OUT( ("PLPIPE: Named Pipe now closed\n") );
|
|
}
|
|
}
|
|
|
|
return Ok;
|
|
}
|
|
|
|
|
|
DWORD
|
|
TlUtilTime(VOID)
|
|
{
|
|
DWORD time;
|
|
static DWORD lTickCount = 0;
|
|
|
|
time = GetCurrentTime();
|
|
|
|
time = time / 1000; // Convert from millisecs to secs
|
|
|
|
if (time < lTickCount) // Take care of day wrap
|
|
time += (24L * 3600);
|
|
|
|
lTickCount = time;
|
|
|
|
return(time);
|
|
}
|
|
|
|
|
|
BOOL
|
|
TlWriteTransport(
|
|
PUCHAR pch,
|
|
DWORD cch
|
|
)
|
|
{
|
|
DWORD dwBytesWritten;
|
|
DWORD ec;
|
|
|
|
if ( !FPipeConnected ) {
|
|
return FALSE;
|
|
}
|
|
|
|
DEBUG_OUT1("PLPIPE: Writing... (Count %u)\n",cch);
|
|
|
|
EnterCriticalSection(&CsWritePipe);
|
|
if (WriteFile(HandleNamedPipe, pch, cch, &dwBytesWritten, &OverlappedWrite )) {
|
|
//
|
|
// Write was successful and finished
|
|
//
|
|
LeaveCriticalSection(&CsWritePipe);
|
|
|
|
if ( dwBytesWritten != cch ) {
|
|
DEBUG_OUT2("PLPIPE: Wrote %u but asked for %u\n", dwBytesWritten, cch);
|
|
LOGIT(LGWRITE,cch,dwBytesWritten,pch);
|
|
goto errorWrite;
|
|
}
|
|
|
|
DEBUG_OUT1( "PLPIPE: Wrote (%u)\n", dwBytesWritten);
|
|
|
|
LOGIT(LGWRITE,0,dwBytesWritten,pch);
|
|
return TRUE;
|
|
}
|
|
|
|
ec = GetLastError();
|
|
if (ec != ERROR_IO_PENDING) {
|
|
LeaveCriticalSection(&CsWritePipe);
|
|
goto errorWrite;
|
|
}
|
|
|
|
if (GetOverlappedResult(HandleNamedPipe, &OverlappedWrite, &dwBytesWritten, TRUE)) {
|
|
//
|
|
// Write was successful and finished
|
|
//
|
|
LeaveCriticalSection(&CsWritePipe);
|
|
|
|
if ( dwBytesWritten != cch ) {
|
|
DEBUG_OUT2("PLPIPE: Wrote %u but asked for %u\n", dwBytesWritten, cch);
|
|
LOGIT(LGWRITE,cch,dwBytesWritten,pch);
|
|
goto errorWrite;
|
|
}
|
|
|
|
DEBUG_OUT1("PLPIPE: Wrote (%u)\n", dwBytesWritten);
|
|
|
|
LOGIT(LGWRITE,0,dwBytesWritten,pch);
|
|
return TRUE;
|
|
}
|
|
|
|
LeaveCriticalSection(&CsWritePipe);
|
|
|
|
errorWrite:
|
|
ec = GetLastError();
|
|
LOGIT(LGWRITE,ec,dwBytesRead,pch);
|
|
TlPipeFailure();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
TlFlushTransport(
|
|
VOID
|
|
)
|
|
{
|
|
return FlushFileBuffers( HandleNamedPipe );
|
|
}
|
|
|
|
|
|
DWORD
|
|
ReadFromPipe(
|
|
PUCHAR pch,
|
|
DWORD cch
|
|
)
|
|
{
|
|
DWORD dwBytesRead;
|
|
DWORD ec;
|
|
PNLBLK pnlblk = (PNLBLK)pch;
|
|
|
|
if (!FPipeConnected) {
|
|
return (DWORD) -1;
|
|
}
|
|
|
|
ResetEvent( OverlappedRead.hEvent );
|
|
|
|
if (ReadFile(HandleNamedPipe, pch, cch, &dwBytesRead, &OverlappedRead)) {
|
|
//
|
|
// Read has successfully completed
|
|
//
|
|
LOGIT(LGREAD,pnlblk->cchMessage,dwBytesRead,pch);
|
|
return dwBytesRead;
|
|
}
|
|
|
|
ec = GetLastError();
|
|
if (ec != ERROR_IO_PENDING) {
|
|
goto errorRead;
|
|
}
|
|
|
|
if (GetOverlappedResult(HandleNamedPipe, &OverlappedRead, &dwBytesRead, TRUE)) {
|
|
//
|
|
// Read has successfully completed
|
|
//
|
|
LOGIT(LGREAD,pnlblk->cchMessage,dwBytesRead,pch);
|
|
return dwBytesRead;
|
|
}
|
|
|
|
errorRead:
|
|
ec = GetLastError();
|
|
LOGIT(LGREAD,ec,dwBytesRead,pch);
|
|
TlPipeFailure();
|
|
|
|
return (DWORD) -1;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ReaderThread(
|
|
LPVOID lpvArg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the main function for the reader thread in this transport layer.
|
|
Its sole purpose is to pull things from the named pipe queue as fast
|
|
as possible and place them into an internal queue. This will prevent
|
|
us from getting piled up in the network queue to fast.
|
|
|
|
Arguments:
|
|
|
|
lpvArg - Supplies the starting parameter -- which is ignored
|
|
|
|
Return Value:
|
|
|
|
0 on a normal exit and -1 otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD bufSize;
|
|
PNLBLK pnlblk;
|
|
PNLBLK pnlblk2;
|
|
int cb = 0;
|
|
int cb2;
|
|
int i;
|
|
LPSTR lpb;
|
|
MPACKET * pMpacket;
|
|
|
|
|
|
|
|
bufSize = MAX_INTERNAL_PACKET + sizeof(NLBLK) + sizeof(MPACKET);
|
|
pnlblk = (PNLBLK) malloc( bufSize );
|
|
|
|
while(HandleNamedPipe == INVALID_HANDLE_VALUE || (!FPipeConnected)) {
|
|
Sleep( 500 );
|
|
}
|
|
|
|
while (TRUE) {
|
|
//
|
|
// Read the next packet item from the network
|
|
//
|
|
cb2 = cb;
|
|
cb = ReadFromPipe((PUCHAR)pnlblk, bufSize);
|
|
|
|
assert( cb != 0 );
|
|
|
|
//
|
|
// Did the read routine decide that the pipe has completely
|
|
// failed and caused a shut down of it to occur? if so
|
|
// then go ahead and exit this thread from the system.
|
|
//
|
|
|
|
if (cb == -1) {
|
|
//
|
|
// Make sure that there is space to put the entry into the
|
|
// queue -- if no then wait until we can get enough space
|
|
//
|
|
|
|
EnterCriticalSection(&CsQueue);
|
|
while ((IQueueFront + 1) % SIZE_OF_QUEUE == IQueueBack) {
|
|
LeaveCriticalSection(&CsQueue);
|
|
Sleep(100);
|
|
EnterCriticalSection(&CsQueue);
|
|
}
|
|
DEBUG_OUT("READER: Add killer\n");
|
|
|
|
//
|
|
// Allocate space for the killer message
|
|
//
|
|
|
|
lpb = malloc(sizeof(NLBLK));
|
|
pnlblk2 = (PNLBLK) lpb;
|
|
pnlblk2->mtypeBlk = mtypeTransportIsDead;
|
|
pnlblk2->cchMessage = 0;
|
|
|
|
//
|
|
// Put the message in the queue
|
|
//
|
|
|
|
RgQueue[IQueueFront].lpb = lpb;
|
|
RgQueue[IQueueFront].cb = sizeof(NLBLK);
|
|
IQueueFront = (IQueueFront + 1) % SIZE_OF_QUEUE;
|
|
|
|
//
|
|
// Wake up the other guy and terminate this thread
|
|
//
|
|
|
|
SetEvent(HQueueEvent);
|
|
LeaveCriticalSection(&CsQueue);
|
|
|
|
if (FDMSide) {
|
|
|
|
TlDestroyTransport();
|
|
while(HandleNamedPipe == INVALID_HANDLE_VALUE || (!FPipeConnected)) {
|
|
Sleep( 500 );
|
|
}
|
|
|
|
EnterCriticalSection(&CsQueue);
|
|
IQueueFront = 0;
|
|
IQueueBack = 0;
|
|
LeaveCriticalSection(&CsQueue);
|
|
ZeroMemory(pnlblk, bufSize);
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the readed item had some length -- then we need to process
|
|
// the message packet just recieved
|
|
//
|
|
else if ( cb > 0) {
|
|
|
|
//
|
|
// Print a message about this packet type.
|
|
//
|
|
|
|
//DEBUG_OUT2("READER: %s %d\n", SzTypes(pnlblk->mtypeBlk), cb);
|
|
DEBUG_OUT2("READER: %x %x\n", pnlblk->mtypeBlk, cb )
|
|
|
|
//
|
|
// For a reply or a version reply message. Place the reply
|
|
// into the buffer which was supplied for that purpose.
|
|
//
|
|
|
|
if ((pnlblk->mtypeBlk == mtypeVersionReply) ||
|
|
(pnlblk->mtypeBlk == mtypeReply)) {
|
|
EnterCriticalSection(&CsReplys);
|
|
i = IReplys - 1;
|
|
assert(i != -1);
|
|
if (i != -1) {
|
|
assert( WaitForSingleObject( RgReplys[i].hEvent, 0 ) != WAIT_OBJECT_0 );
|
|
cb = min(pnlblk->cchMessage, RgReplys[i].cbBuffer);
|
|
memcpy(RgReplys[i].lpb, pnlblk->rgchData, cb);
|
|
RgReplys[i].cbRet = cb;
|
|
SetEvent(RgReplys[i].hEvent);
|
|
}
|
|
LeaveCriticalSection(&CsReplys);
|
|
} else if (pnlblk->mtypeBlk == mtypeReplyMulti) {
|
|
EnterCriticalSection(&CsReplys);
|
|
i = IReplys - 1;
|
|
if (i != -1) {
|
|
pMpacket = (MPACKET *) pnlblk->rgchData;
|
|
cb2 = pMpacket->packetNum * MAX_INTERNAL_PACKET;
|
|
cb = pnlblk->cchMessage - sizeof(MPACKET);
|
|
cb = min(cb + cb2, RgReplys[i].cbBuffer);
|
|
if (cb > cb2) {
|
|
memcpy(RgReplys[i].lpb + cb2, pMpacket->rgchData,
|
|
cb - cb2);
|
|
RgReplys[i].cbRet = cb;
|
|
}
|
|
if (pMpacket->packetNum + 1 == pMpacket->packetCount) {
|
|
SetEvent(RgReplys[i].hEvent);
|
|
}
|
|
}
|
|
LeaveCriticalSection(&CsReplys);
|
|
} else {
|
|
|
|
assert( cb == (int) (pnlblk->cchMessage + sizeof(NLBLK)) );
|
|
|
|
lpb = malloc(cb);
|
|
memcpy(lpb, pnlblk, cb);
|
|
|
|
EnterCriticalSection( &CsQueue );
|
|
while ((IQueueFront + 1) % SIZE_OF_QUEUE == IQueueBack) {
|
|
LeaveCriticalSection( &CsQueue );
|
|
Sleep(100);
|
|
EnterCriticalSection( &CsQueue );
|
|
}
|
|
DEBUG_OUT2("READER: Add queue Front=%d End=%d\n", IQueueFront, IQueueBack);
|
|
RgQueue[IQueueFront].lpb = lpb;
|
|
RgQueue[IQueueFront].cb = cb;
|
|
IQueueFront = (IQueueFront + 1) % SIZE_OF_QUEUE;
|
|
SetEvent(HQueueEvent);
|
|
LeaveCriticalSection( &CsQueue );
|
|
}
|
|
}
|
|
}
|
|
|
|
return (DWORD) -1;
|
|
}
|
|
|
|
|
|
DWORD
|
|
CallbackThread(
|
|
LPVOID lpvArg
|
|
)
|
|
{
|
|
LPSTR lpb;
|
|
int cb;
|
|
|
|
while (TRUE) {
|
|
EnterCriticalSection( &CsQueue );
|
|
if (IQueueFront == IQueueBack) {
|
|
ResetEvent( HQueueEvent);
|
|
LeaveCriticalSection( &CsQueue );
|
|
WaitForSingleObject( HQueueEvent, INFINITE );
|
|
EnterCriticalSection( &CsQueue );
|
|
}
|
|
|
|
lpb = RgQueue[IQueueBack].lpb;
|
|
DEBUG_OUT3("CALLBACK: %x Back=%d Front=%d\n",((PNLBLK)lpb)->mtypeBlk,IQueueBack,IQueueFront);
|
|
cb = RgQueue[IQueueBack].cb;
|
|
RgQueue[IQueueBack].lpb = NULL;
|
|
RgQueue[IQueueBack].cb = 0;
|
|
IQueueBack = (IQueueBack + 1) % SIZE_OF_QUEUE;
|
|
LeaveCriticalSection( &CsQueue );
|
|
|
|
if (!CallBack((PNLBLK) lpb, cb)) {
|
|
|
|
if (!FDMSide) {
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
free(lpb);
|
|
|
|
}
|
|
return (DWORD) -1;
|
|
}
|
|
|
|
|
|
int FAR PASCAL
|
|
CopyString(
|
|
LPSTR * lplps,
|
|
LPSTR lpT,
|
|
char chEscape,
|
|
BOOL fQuote
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Scan and copy an optionally quoted C-style string. If the first
|
|
character is a quote, a matching quote will terminate the string,
|
|
otherwise the scanning will stop at the first whitespace encountered.
|
|
The target string will be null terminated if any characters are copied.
|
|
|
|
Arguments:
|
|
|
|
lplps - Supplies a pointer to a pointer to the source string
|
|
|
|
lpt - Supplies a pointer to the target string
|
|
|
|
chEscape - Supplies the escape character (typically '\\')
|
|
|
|
fQuote - Supplies a flag indicating whether the first character is a quote
|
|
|
|
Return Value:
|
|
|
|
The number of characters copied into lpt[]. If an error occurs, -1 is
|
|
returned.
|
|
|
|
--*/
|
|
{
|
|
LPSTR lps = *lplps;
|
|
LPSTR lpt = lpT;
|
|
int i;
|
|
int n;
|
|
int err = 0;
|
|
char cQuote;
|
|
#ifdef DBCS
|
|
BOOL fDBCS = FALSE;
|
|
#endif
|
|
|
|
if (fQuote) {
|
|
if (*lps) cQuote = *lps++;
|
|
}
|
|
|
|
while (!err) {
|
|
|
|
if (*lps == 0)
|
|
{
|
|
if (fQuote) err = 1;
|
|
else *lpt = '\0';
|
|
break;
|
|
}
|
|
#ifdef DBCS
|
|
else if (fQuote && *lps == cQuote && !fDBCS)
|
|
#else
|
|
else if (fQuote && *lps == cQuote)
|
|
#endif
|
|
{
|
|
*lpt = '\0';
|
|
// eat the quote
|
|
lps++;
|
|
break;
|
|
}
|
|
#ifdef DBCS
|
|
else if (!fQuote && !fDBCS &&
|
|
(!*lps ||
|
|
*lps == ' ' ||
|
|
*lps == '\t' ||
|
|
*lps == '\r' ||
|
|
*lps == '\n'))
|
|
#else
|
|
else if (!fQuote &&
|
|
(!*lps ||
|
|
*lps == ' ' ||
|
|
*lps == '\t' ||
|
|
*lps == '\r' ||
|
|
*lps == '\n'))
|
|
#endif
|
|
{
|
|
*lpt = '\0';
|
|
break;
|
|
}
|
|
|
|
#ifdef DBCS
|
|
else if (IsDBCSLeadByte((BYTE)*lps) && !fDBCS) {
|
|
*lpt++ = *lps++;
|
|
fDBCS = TRUE;
|
|
}
|
|
#endif
|
|
else if (*lps != chEscape)
|
|
{
|
|
*lpt++ = *lps++;
|
|
#ifdef DBCS
|
|
fDBCS = FALSE;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
switch (*++lps) {
|
|
case 0:
|
|
err = 1;
|
|
--lps;
|
|
break;
|
|
|
|
default: // any char - usually escape or quote
|
|
*lpt++ = *lps;
|
|
break;
|
|
|
|
case 'b': // backspace
|
|
*lpt++ = '\b';
|
|
break;
|
|
|
|
case 'f': // formfeed
|
|
*lpt++ = '\f';
|
|
break;
|
|
|
|
case 'n': // newline
|
|
*lpt++ = '\n';
|
|
break;
|
|
|
|
case 'r': // return
|
|
*lpt++ = '\r';
|
|
break;
|
|
|
|
case 's': // space
|
|
*lpt++ = ' ';
|
|
break;
|
|
|
|
case 't': // tab
|
|
*lpt++ = '\t';
|
|
break;
|
|
|
|
case '0': // octal escape
|
|
for (n = 0, i = 0; i < 3; i++) {
|
|
++lps;
|
|
if (*lps < '0' || *lps > '7') {
|
|
--lps;
|
|
break;
|
|
}
|
|
n = (n<<3) + *lps - '0';
|
|
}
|
|
*lpt++ = (UCHAR)(n & 0xff);
|
|
break;
|
|
}
|
|
lps++; // skip char from switch
|
|
#ifdef DBCS
|
|
fDBCS = FALSE;
|
|
#endif
|
|
}
|
|
|
|
} // while
|
|
|
|
if (err) {
|
|
return -1;
|
|
} else {
|
|
*lplps = lps;
|
|
return lpt - lpT;
|
|
}
|
|
}
|
|
|