505 lines
13 KiB
C
505 lines
13 KiB
C
/*++
|
|
|
|
Copyright (c) 1998-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
server.c
|
|
|
|
Abstract:
|
|
This module contains the server code for dealing with clients.
|
|
|
|
Author:
|
|
Michael Tsang (MikeTs) 02-May-2000
|
|
|
|
Environment:
|
|
User mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
/*++
|
|
@doc INTERNAL
|
|
|
|
@func VOID | ServerThread | Server thread procedure.
|
|
|
|
@parm IN PVOID | pv | (Not Used).
|
|
|
|
@rvalue None.
|
|
--*/
|
|
|
|
VOID __cdecl
|
|
ServerThread(
|
|
IN PVOID pv
|
|
)
|
|
{
|
|
TRTRACEPROC("ServerThread", 1)
|
|
RPC_STATUS status;
|
|
RPC_BINDING_VECTOR *BindingVector = NULL;
|
|
|
|
TRENTER(("(pv=%p)\n", pv));
|
|
|
|
if ((status = RpcServerUseProtseq("ncalrpc",
|
|
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
|
|
// "\\pipe\\tracer",
|
|
NULL)) != RPC_S_OK)
|
|
{
|
|
TRERRPRINT(("RpcServerUseProtseq failed (status=%d)\n", status));
|
|
}
|
|
else if ((status = RpcServerRegisterIf(WTServer_v1_0_s_ifspec, NULL, NULL))
|
|
!= RPC_S_OK)
|
|
{
|
|
TRERRPRINT(("RpcServerRegisterIf failed (status=%d)\n", status));
|
|
}
|
|
else if ((status = RpcServerInqBindings(&BindingVector)) != RPC_S_OK)
|
|
{
|
|
TRERRPRINT(("RpcServerInqBindings failed (status=%d)\n", status));
|
|
}
|
|
else if ((status = RpcEpRegister(WTServer_v1_0_s_ifspec,
|
|
BindingVector,
|
|
NULL,
|
|
NULL)) != RPC_S_OK)
|
|
{
|
|
RpcBindingVectorFree(&BindingVector);
|
|
TRERRPRINT(("RpcEpRegister failed (status=%d)\n", status));
|
|
}
|
|
else if ((status = RpcServerRegisterAuthInfo(NULL,
|
|
RPC_C_AUTHN_WINNT,
|
|
NULL,
|
|
NULL)) != RPC_S_OK)
|
|
{
|
|
RpcEpUnregister(WTServer_v1_0_s_ifspec, BindingVector, NULL);
|
|
RpcBindingVectorFree(&BindingVector);
|
|
TRERRPRINT(("RpcServerRegisterAuthInfo failed (status=%d)\n", status));
|
|
}
|
|
else
|
|
{
|
|
status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, FALSE);
|
|
TRASSERT(status == RPC_S_OK);
|
|
RpcEpUnregister(WTServer_v1_0_s_ifspec, BindingVector, NULL);
|
|
RpcBindingVectorFree(&BindingVector);
|
|
}
|
|
_endthread();
|
|
|
|
TREXIT(("!\n"));
|
|
return;
|
|
} //ServerThread
|
|
|
|
/*++
|
|
@doc EXTERNAL
|
|
|
|
@func HCLIENT | WTRegisterClient | Register a new client.
|
|
|
|
@parm IN handle_t | hBinding | RPC binding handle.
|
|
@parm IN unsigned char * | pszClientName |
|
|
Points to the client name string.
|
|
|
|
@rvalue SUCCESS | Returns new client handle.
|
|
@rvalue FAILURE | Returns NULL.
|
|
--*/
|
|
|
|
HCLIENT
|
|
WTRegisterClient(
|
|
IN handle_t hBinding,
|
|
IN unsigned char *pszClientName
|
|
)
|
|
{
|
|
TRTRACEPROC("WTRegisterClient", 1)
|
|
PCLIENT_ENTRY ClientEntry;
|
|
|
|
TRENTER(("(hBinding=%p,ClientName=%s)\n", hBinding, pszClientName));
|
|
|
|
ClientEntry = (PCLIENT_ENTRY)malloc(sizeof(CLIENT_ENTRY));
|
|
if (ClientEntry != NULL)
|
|
{
|
|
memset(ClientEntry, 0, sizeof(*ClientEntry));
|
|
lstrcpynA(ClientEntry->szClientName,
|
|
pszClientName,
|
|
sizeof(ClientEntry->szClientName));
|
|
InsertTailList(&glistClients, &ClientEntry->list);
|
|
WTGetClientInfo(&ClientEntry->ClientInfo);
|
|
if ((ClientEntry->ClientInfo.Settings.iVerboseLevel +
|
|
ClientEntry->ClientInfo.Settings.iTraceLevel +
|
|
ClientEntry->ClientInfo.Settings.dwfSettings == 0) &&
|
|
(gDefGlobalSettings.iVerboseLevel +
|
|
gDefGlobalSettings.iTraceLevel +
|
|
gDefGlobalSettings.dwfSettings != 0))
|
|
{
|
|
ClientEntry->ClientInfo.Settings = gDefGlobalSettings;
|
|
WTSetClientInfo(&ClientEntry->ClientInfo);
|
|
}
|
|
|
|
if (ghwndPropSheet != NULL)
|
|
{
|
|
PROPSHEETPAGEA psp;
|
|
HPROPSHEETPAGE hpsp;
|
|
|
|
psp.dwSize = sizeof(psp);
|
|
psp.dwFlags = PSP_USETITLE;
|
|
psp.hInstance = ghInstance;
|
|
psp.pszTitle = ClientEntry->szClientName;
|
|
psp.lParam = (LPARAM)ClientEntry;
|
|
psp.pszTemplate = (LPSTR)MAKEINTRESOURCE(IDD_CLIENTSETTINGS);
|
|
psp.pfnDlgProc = ClientSettingsDlgProc;
|
|
hpsp = CreatePropertySheetPageA(&psp);
|
|
|
|
ClientEntry->hPage = hpsp;
|
|
PropSheet_AddPage(ghwndPropSheet, hpsp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRERRPRINT(("failed to allocate client entry for %s\n", pszClientName));
|
|
}
|
|
|
|
TREXIT(("=%p\n", ClientEntry));
|
|
return (HCLIENT)ClientEntry;
|
|
} //WTRegisterClient
|
|
|
|
/*++
|
|
@doc EXTERNAL
|
|
|
|
@func VOID | WTDeregisterClient | Deregister a client.
|
|
|
|
@parm IN handle_t | hBinding | RPC binding handle.
|
|
@parm IN HCLIENT | hClient | Client handle.
|
|
|
|
@rvalue None.
|
|
--*/
|
|
|
|
VOID
|
|
WTDeregisterClient(
|
|
IN handle_t hBinding,
|
|
IN HCLIENT hClient
|
|
)
|
|
{
|
|
TRTRACEPROC("WTDeregisterClient", 1)
|
|
PCLIENT_ENTRY ClientEntry = (PCLIENT_ENTRY)hClient;
|
|
|
|
TRENTER(("(hBinding=%p,hClient=%p)\n", hBinding, hClient));
|
|
|
|
RemoveEntryList(&ClientEntry->list);
|
|
if (ghwndPropSheet != NULL)
|
|
{
|
|
PropSheet_RemovePage(ghwndPropSheet, 0, ClientEntry->hPage);
|
|
}
|
|
SendServerRequest(ClientEntry, SRVREQ_TERMINATE, NULL);
|
|
free(ClientEntry);
|
|
|
|
TREXIT(("!\n"));
|
|
return;
|
|
} //WTDeregisterClient
|
|
|
|
/*++
|
|
@doc EXTERNAL
|
|
|
|
@func VOID | WTTraceProc | Print the TraceProc text.
|
|
|
|
@parm IN handle_t | hBinding | RPC binding handle.
|
|
@parm IN HCLIENT | hClient | Client handle.
|
|
@parm IN DWORD | dwThreadId | Thread ID.
|
|
@parm IN int | iIndentLevel | Specifies the level of indentation.
|
|
@parm IN unsigned char * | pszText | Points to the TraceProc text.
|
|
|
|
@rvalue None.
|
|
--*/
|
|
|
|
VOID
|
|
WTTraceProc(
|
|
IN handle_t hBinding,
|
|
IN HCLIENT hClient,
|
|
IN DWORD dwThreadId,
|
|
IN int iIndentLevel,
|
|
IN unsigned char *pszText
|
|
)
|
|
{
|
|
TRTRACEPROC("WTTraceProc", 1)
|
|
PCLIENT_ENTRY ClientEntry = (PCLIENT_ENTRY)hClient;
|
|
static char szText[1024];
|
|
int i;
|
|
LONG lSel;
|
|
|
|
TRENTER(("(hBinding=%p,hClient=%p,ThreadId=%x,IndentLevel=%d,Text=%s)\n",
|
|
hBinding, hClient, dwThreadId, iIndentLevel, pszText));
|
|
|
|
wsprintfA(szText, "[%08x]%s: ", dwThreadId, ClientEntry->szClientName);
|
|
for (i = 0; i < iIndentLevel; ++i)
|
|
{
|
|
lstrcpyA(&szText[lstrlenA(szText)], "| ");
|
|
}
|
|
CopyStr(&szText[lstrlenA(szText)], pszText);
|
|
lSel = (LONG)SendMessage(ghwndEdit, WM_GETTEXTLENGTH, 0, 0);
|
|
SendMessage(ghwndEdit, EM_SETSEL, lSel, lSel);
|
|
SendMessage(ghwndEdit, EM_REPLACESEL, 0, (LPARAM)szText);
|
|
|
|
TREXIT(("!\n"));
|
|
return;
|
|
} //WTTraceProc
|
|
|
|
/*++
|
|
@doc EXTERNAL
|
|
|
|
@func VOID | WTTraceMsg | Print the TraceMsg text.
|
|
|
|
@parm IN handle_t | hBinding | RPC binding handle.
|
|
@parm IN HCLIENT | hClient | Client handle.
|
|
@parm IN unsigned char * | pszMsg | Points to the TraceMsg text.
|
|
|
|
@rvalue None.
|
|
--*/
|
|
|
|
VOID
|
|
WTTraceMsg(
|
|
IN handle_t hBinding,
|
|
IN HCLIENT hClient,
|
|
IN unsigned char *pszMsg
|
|
)
|
|
{
|
|
TRTRACEPROC("WTTraceMsg", 1)
|
|
PCLIENT_ENTRY ClientEntry = (PCLIENT_ENTRY)hClient;
|
|
static char szText[1024];
|
|
LONG lSel;
|
|
|
|
TRENTER(("(hBinding=%p,hClient=%p,Msg=%s)\n", hBinding, hClient, pszMsg));
|
|
|
|
CopyStr(szText, pszMsg);
|
|
lSel = (LONG)SendMessage(ghwndEdit, WM_GETTEXTLENGTH, 0, 0);
|
|
SendMessage(ghwndEdit, EM_SETSEL, lSel, lSel);
|
|
SendMessage(ghwndEdit, EM_REPLACESEL, 0, (LPARAM)szText);
|
|
|
|
TREXIT(("!\n"));
|
|
return;
|
|
} //WTTraceMsg
|
|
|
|
/*++
|
|
@doc EXTERNAL
|
|
|
|
@func VOID | WTDispatchServerRequests | Dispatch server requests to the
|
|
client.
|
|
|
|
@parm IN handle_t | hBinding | RPC binding handle.
|
|
@parm IN HCLIENT | hClient | Client handle.
|
|
|
|
@rvalue None.
|
|
--*/
|
|
|
|
VOID
|
|
WTDispatchServerRequests(
|
|
IN handle_t hBinding,
|
|
IN HCLIENT hClient
|
|
)
|
|
{
|
|
TRTRACEPROC("WTDispatchServerRequests", 1)
|
|
PCLIENT_ENTRY ClientEntry = (PCLIENT_ENTRY)hClient;
|
|
|
|
TRENTER(("(hBinding=%p,hClient=%p)\n", hBinding, hClient));
|
|
|
|
TRASSERT(ClientEntry->hSrvReqEvent == 0);
|
|
ClientEntry->hSrvReqEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (ClientEntry->hSrvReqEvent == NULL)
|
|
{
|
|
TRERRPRINT(("failed to create server request event (err=%d)\n",
|
|
GetLastError()));
|
|
}
|
|
else
|
|
{
|
|
BOOL fDone = FALSE;
|
|
LONG Req;
|
|
DWORD rcWait;
|
|
|
|
while (!fDone)
|
|
{
|
|
Req = InterlockedExchange(&ClientEntry->SrvReq.lRequest,
|
|
SRVREQ_BUSY);
|
|
switch (Req)
|
|
{
|
|
case SRVREQ_NONE:
|
|
Req = InterlockedExchange(&ClientEntry->SrvReq.lRequest,
|
|
Req);
|
|
TRASSERT(Req == SRVREQ_BUSY);
|
|
rcWait = WaitForSingleObject(ClientEntry->hSrvReqEvent,
|
|
INFINITE);
|
|
if (rcWait != WAIT_OBJECT_0)
|
|
{
|
|
TRERRPRINT(("failed waiting for server request event (err=%d)\n",
|
|
GetLastError));
|
|
}
|
|
break;
|
|
|
|
case SRVREQ_BUSY:
|
|
//
|
|
// Try again.
|
|
//
|
|
break;
|
|
|
|
case SRVREQ_GETCLIENTINFO:
|
|
WTGetClientInfo((PCLIENTINFO)ClientEntry->SrvReq.Context);
|
|
Req = InterlockedExchange(&ClientEntry->SrvReq.lRequest,
|
|
SRVREQ_NONE);
|
|
TRASSERT(Req == SRVREQ_BUSY);
|
|
break;
|
|
|
|
case SRVREQ_SETCLIENTINFO:
|
|
WTSetClientInfo((PCLIENTINFO)ClientEntry->SrvReq.Context);
|
|
Req = InterlockedExchange(&ClientEntry->SrvReq.lRequest,
|
|
SRVREQ_NONE);
|
|
TRASSERT(Req == SRVREQ_BUSY);
|
|
break;
|
|
|
|
case SRVREQ_TERMINATE:
|
|
fDone = TRUE;
|
|
Req = InterlockedExchange(&ClientEntry->SrvReq.lRequest,
|
|
SRVREQ_NONE);
|
|
TRASSERT(Req == SRVREQ_BUSY);
|
|
break;
|
|
|
|
default:
|
|
TRERRPRINT(("unexpected server request %x.\n", Req));
|
|
Req = InterlockedExchange(&ClientEntry->SrvReq.lRequest,
|
|
SRVREQ_NONE);
|
|
TRASSERT(Req == SRVREQ_BUSY);
|
|
}
|
|
}
|
|
|
|
CloseHandle(ClientEntry->hSrvReqEvent);
|
|
ClientEntry->hSrvReqEvent = 0;
|
|
}
|
|
|
|
TREXIT(("!\n"));
|
|
return;
|
|
} //WTDispatchServerRequests
|
|
|
|
/*++
|
|
@doc INTERNAL
|
|
|
|
@func VOID | SendServerRequest | Send a server request to the client.
|
|
|
|
@parm IN PCLIENT_ENTRY | ClientEntry | Points to the client entry.
|
|
@parm IN LONG | lRequest | Request.
|
|
@parm IN PVOID | Context | Request context.
|
|
|
|
@rvalue None.
|
|
--*/
|
|
|
|
VOID
|
|
SendServerRequest(
|
|
IN PCLIENT_ENTRY ClientEntry,
|
|
IN LONG lRequest,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
TRTRACEPROC("SendServerRequest", 1)
|
|
LONG Req;
|
|
|
|
TRENTER(("(ClientEntry=%p,Request=%x,Context=%p)\n",
|
|
ClientEntry, lRequest, Context));
|
|
|
|
while (InterlockedCompareExchange(&ClientEntry->SrvReq.lRequest,
|
|
SRVREQ_BUSY,
|
|
SRVREQ_NONE) != SRVREQ_NONE)
|
|
;
|
|
ClientEntry->SrvReq.Context = Context;
|
|
Req = InterlockedExchange(&ClientEntry->SrvReq.lRequest, lRequest);
|
|
TRASSERT(Req == SRVREQ_BUSY);
|
|
SetEvent(ClientEntry->hSrvReqEvent);
|
|
|
|
TREXIT(("!\n"));
|
|
return;
|
|
} //SendServerRequest
|
|
|
|
/*++
|
|
@doc INTERNAL
|
|
|
|
@func LPSTR | CopyStr | Copy string from source to destination and
|
|
replaces all the '\n' to '\r\n'.
|
|
|
|
@parm OUT LPSTR | pszDest | Points to the destination string.
|
|
@parm IN LPCSTR | pszSrc | Points to the source string.
|
|
|
|
@rvalue Returns pointer to the destination string.
|
|
--*/
|
|
|
|
LPSTR
|
|
CopyStr(
|
|
OUT LPSTR pszDest,
|
|
IN LPCSTR pszSrc
|
|
)
|
|
{
|
|
TRTRACEPROC("CopyStr", 3)
|
|
LPSTR psz;
|
|
|
|
TRENTER(("(Dest=%p,Src=%s)\n", pszDest, pszSrc));
|
|
|
|
for (psz = pszDest; *pszSrc != '\0'; psz++, pszSrc++)
|
|
{
|
|
if (*pszSrc != '\n')
|
|
{
|
|
*psz = *pszSrc;
|
|
}
|
|
else
|
|
{
|
|
*psz = '\r';
|
|
psz++;
|
|
*psz = '\n';
|
|
}
|
|
}
|
|
*psz = '\0';
|
|
|
|
TREXIT(("=%p (Dest=%s)\n", pszDest, pszDest));
|
|
return pszDest;
|
|
} //CopyStr
|
|
|
|
/*++
|
|
@doc EXTERNAL
|
|
|
|
@func void __RPC_FAR * | MIDL_user_allocate | MIDL allocate.
|
|
|
|
@parm IN size_t | len | size of allocation.
|
|
|
|
@rvalue SUCCESS | Returns the pointer to the memory allocated.
|
|
@rvalue FAILURE | Returns NULL.
|
|
--*/
|
|
|
|
void __RPC_FAR * __RPC_USER
|
|
MIDL_user_allocate(
|
|
IN size_t len
|
|
)
|
|
{
|
|
TRTRACEPROC("MIDL_user_allocate", 5)
|
|
void __RPC_FAR *ptr;
|
|
|
|
TRENTER(("(len=%d)\n", len));
|
|
|
|
ptr = malloc(len);
|
|
|
|
TREXIT(("=%p\n", ptr));
|
|
return ptr;
|
|
} //MIDL_user_allocate
|
|
|
|
/*++
|
|
@doc EXTERNAL
|
|
|
|
@func void | MIDL_user_free | MIDL free.
|
|
|
|
@parm IN void __PRC_FAR * | ptr | Points to the memory to be freed.
|
|
|
|
@rvalue None.
|
|
--*/
|
|
|
|
void __RPC_USER
|
|
MIDL_user_free(
|
|
IN void __RPC_FAR *ptr
|
|
)
|
|
{
|
|
TRTRACEPROC("MIDL_user_free", 5)
|
|
|
|
TRENTER(("(ptr=%p)\n", ptr));
|
|
|
|
free(ptr);
|
|
|
|
TREXIT(("!\n"));
|
|
return;
|
|
} //MIDL_user_free
|