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.
569 lines
11 KiB
569 lines
11 KiB
#include <sysinc.h>
|
|
#include <windows.h>
|
|
#include <lpcsys.hxx>
|
|
#include <lpcheap.hxx>
|
|
|
|
#define LPC_PORT_THROW RaiseException(RPC_S_OUT_OF_MEMORY, 0, 0, NULL)
|
|
|
|
#define UnAlignBuffer(Buffer) (void *) ((char *)Buffer - ((int *)Buffer)[-1])
|
|
|
|
const int ReceivePollInterval = 5000;
|
|
|
|
const int ConnectReferenceIterations = 15;
|
|
const DWORD ConnectReferenceDelay = 400; // 400 milliseconds
|
|
const DWORD ConnectSignalTimeout = 5000; // 5 seconds
|
|
|
|
LPC_PORT::LPC_PORT(
|
|
)
|
|
{
|
|
ObjectType = LpcPortObjectType;
|
|
}
|
|
|
|
LPC_PORT::~LPC_PORT(
|
|
)
|
|
{
|
|
ASSERT(ObjectType == LpcPortObjectType);
|
|
}
|
|
|
|
LPVOID
|
|
LPC_PORT::GetBuffer(
|
|
DWORD Size
|
|
)
|
|
{
|
|
int AmountOfPad;
|
|
int * Memory;
|
|
void * Result;
|
|
|
|
ASSERT(ObjectType == LpcPortObjectType);
|
|
|
|
// Result = LpcHeapAlloc(Size);
|
|
// return (Result);
|
|
|
|
Memory = (int *) LpcHeapAlloc(Size + 8);
|
|
|
|
if (Memory == NULL) {
|
|
return (NULL);
|
|
}
|
|
|
|
AmountOfPad = (int)(8 - ((long) Memory & 7));
|
|
Memory = (int *) (((char *) Memory) + AmountOfPad);
|
|
Memory[-1] = AmountOfPad;
|
|
return (Memory);
|
|
}
|
|
|
|
VOID
|
|
LPC_PORT::FreeBuffer(
|
|
LPVOID Buffer
|
|
)
|
|
{
|
|
ASSERT(ObjectType == LpcPortObjectType);
|
|
|
|
ASSERT(Buffer != NULL);
|
|
|
|
LpcHeapFree(UnAlignBuffer(Buffer));
|
|
// LpcHeapFree(Buffer);
|
|
}
|
|
|
|
LPC_CONNECT_PORT::LPC_CONNECT_PORT(
|
|
)
|
|
{
|
|
ASSERT(ObjectType == LpcPortObjectType);
|
|
|
|
PortName = NULL;
|
|
|
|
LpcSystemInsertPort(this);
|
|
}
|
|
|
|
LPC_CONNECT_PORT::~LPC_CONNECT_PORT(
|
|
)
|
|
{
|
|
|
|
ASSERT(ObjectType == LpcPortObjectType);
|
|
|
|
LpcSystemRemovePort(this);
|
|
|
|
if (PortName) {
|
|
LpcHeapFree((LPVOID)PortName);
|
|
PortName = NULL;
|
|
}
|
|
}
|
|
|
|
RPC_STATUS
|
|
LPC_CONNECT_PORT::BindToName(
|
|
LPCSTR BindPortName
|
|
)
|
|
{
|
|
LPCSTR NewPortName;
|
|
unsigned int BindPortNameLength;
|
|
LPC_CONNECT_PORT * ConnectPort;
|
|
|
|
ASSERT(ObjectType == LpcPortObjectType);
|
|
|
|
ConnectPort = LpcSystemReferencePortByName(BindPortName);
|
|
if (ConnectPort != NULL) {
|
|
ConnectPort->Dereference();
|
|
return (RPC_S_DUPLICATE_ENDPOINT);
|
|
}
|
|
|
|
BindPortNameLength = lstrlen(BindPortName) + 1;
|
|
|
|
NewPortName = (LPCSTR)LpcHeapAlloc(BindPortNameLength);
|
|
|
|
if (NewPortName == NULL) {
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
RpcpMemoryCopy((LPVOID)NewPortName, BindPortName, BindPortNameLength);
|
|
|
|
CritSec.Enter();
|
|
|
|
this->PortName = NewPortName;
|
|
|
|
CritSec.Leave();
|
|
|
|
#ifdef DEBUGRPC_DETAIL
|
|
PrintToDebugger("LRPC: Port %x bound to name %s\n", this, BindPortName);
|
|
#endif
|
|
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS
|
|
LPC_CONNECT_PORT::Listen(
|
|
LPC_DATA_PORT * * SourcePort
|
|
)
|
|
{
|
|
LPC_MSG * Msg = NULL;
|
|
|
|
ASSERT(ObjectType == LpcPortObjectType);
|
|
|
|
if (Sem.Wait() != ERROR_SUCCESS) {
|
|
return (RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
CritSec.Enter();
|
|
|
|
Msg = MsgQueue.Dequeue();
|
|
|
|
CritSec.Leave();
|
|
|
|
if (Msg == NULL) {
|
|
return (RPC_P_CONNECTION_CLOSED);
|
|
}
|
|
|
|
*SourcePort = Msg->Port;
|
|
|
|
delete Msg;
|
|
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
LPC_DATA_PORT *
|
|
LPC_CONNECT_PORT::Accept(
|
|
LPC_DATA_PORT * ClientPort
|
|
)
|
|
{
|
|
LPC_DATA_PORT * ServerPort;
|
|
|
|
ASSERT(ObjectType == LpcPortObjectType);
|
|
|
|
ServerPort = new LPC_DATA_PORT;
|
|
|
|
ServerPort->PeerPort = ClientPort;
|
|
ClientPort->AddRef();
|
|
|
|
ClientPort->PeerPort = ServerPort;
|
|
|
|
ServerPort->PeerSem = new LPC_SEM(ClientPort->Sem);
|
|
|
|
if (ServerPort->PeerSem->Release() != ERROR_SUCCESS) {
|
|
ClientPort->PeerPort = NULL;
|
|
return (NULL);
|
|
}
|
|
|
|
return (ServerPort);
|
|
}
|
|
|
|
LPC_DATA_PORT::LPC_DATA_PORT(
|
|
)
|
|
{
|
|
PeerPort = NULL;
|
|
|
|
PeerSem = NULL;
|
|
}
|
|
|
|
LPC_DATA_PORT::~LPC_DATA_PORT(
|
|
)
|
|
{
|
|
Disconnect();
|
|
}
|
|
|
|
inline BOOL
|
|
LPC_DATA_PORT::CopyLocal(
|
|
LPVOID LocalBuf,
|
|
DWORD LocalBufSize,
|
|
PDWORD LocalBufActualSize,
|
|
LPC_MSG * Msg
|
|
)
|
|
{
|
|
if (LocalBuf && Msg->LocalBufSize) {
|
|
if (LocalBufSize < Msg->LocalBufSize) {
|
|
return (FALSE);
|
|
}
|
|
RpcpMemoryCopy(LocalBuf, Msg->LocalBuf, (unsigned int)Msg->LocalBufSize);
|
|
*LocalBufActualSize = Msg->LocalBufSize;
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
inline VOID
|
|
LPC_DATA_PORT::CopyGlobal(
|
|
LPVOID * GlobalBuf,
|
|
PDWORD GlobalBufSize,
|
|
LPC_MSG * Msg
|
|
)
|
|
{
|
|
if (GlobalBuf) {
|
|
if (Msg->GlobalBuf) {
|
|
*GlobalBuf = Msg->GlobalBuf;
|
|
*GlobalBufSize = Msg->GlobalBufSize;
|
|
} else {
|
|
*GlobalBuf = 0;
|
|
*GlobalBufSize = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
RPC_STATUS
|
|
LPC_DATA_PORT::Send(
|
|
LPVOID LocalBuf,
|
|
DWORD LocalBufSize,
|
|
LPVOID GlobalBuf,
|
|
DWORD GlobalBufSize
|
|
)
|
|
{
|
|
LPC_MSG * Msg;
|
|
DWORD Status;
|
|
|
|
ASSERT(ObjectType == LpcPortObjectType);
|
|
|
|
if (PeerPort == NULL) {
|
|
return (RPC_P_CONNECTION_CLOSED);
|
|
}
|
|
|
|
ASSERT(PeerPort->ObjectType == LpcPortObjectType);
|
|
|
|
Msg = new LPC_MSG(this, LocalBuf, LocalBufSize);
|
|
|
|
if (Msg == NULL) {
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
if (GlobalBuf) {
|
|
Msg->GlobalBuf = GlobalBuf;
|
|
Msg->GlobalBufSize = GlobalBufSize;
|
|
} else {
|
|
Msg->GlobalBuf = 0;
|
|
Msg->GlobalBufSize = 0;
|
|
}
|
|
|
|
PeerPort->CritSec.Enter();
|
|
|
|
PeerPort->MsgQueue.Enqueue(Msg);
|
|
|
|
PeerPort->CritSec.Leave();
|
|
|
|
if ((Status = PeerSem->Release()) != ERROR_SUCCESS) {
|
|
return (RPC_P_SEND_FAILED);
|
|
}
|
|
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS
|
|
LPC_DATA_PORT::Receive(
|
|
LPVOID LocalBuf,
|
|
DWORD LocalBufSize,
|
|
PDWORD LocalBufActualSize,
|
|
LPVOID * GlobalBuf,
|
|
PDWORD GlobalBufSize
|
|
)
|
|
{
|
|
DWORD Status;
|
|
LPC_MSG * Msg;
|
|
|
|
ASSERT(ObjectType == LpcPortObjectType);
|
|
|
|
Status = Sem.WaitOrOwnerDead(PeerPort->ProcessId);
|
|
|
|
switch (Status)
|
|
{
|
|
case LPC_SEM_WAIT_PROCESS_DEAD:
|
|
return (RPC_P_CONNECTION_CLOSED);
|
|
|
|
case LPC_SEM_WAIT_SUCCESS:
|
|
break;
|
|
|
|
default:
|
|
return (RPC_P_CONNECTION_CLOSED);
|
|
}
|
|
|
|
CritSec.Enter();
|
|
|
|
Msg = MsgQueue.Dequeue();
|
|
|
|
if (Msg == NULL) {
|
|
Disconnect();
|
|
return (RPC_P_CONNECTION_CLOSED);
|
|
}
|
|
|
|
CritSec.Leave();
|
|
|
|
if (CopyLocal(LocalBuf, LocalBufSize, LocalBufActualSize, Msg) == FALSE) {
|
|
delete Msg;
|
|
return (RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
CopyGlobal(GlobalBuf, GlobalBufSize, Msg);
|
|
|
|
delete Msg;
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS
|
|
LPC_DATA_PORT::Transceive(
|
|
LPVOID OutLocalBuf,
|
|
DWORD OutLocalBufSize,
|
|
LPVOID OutGlobalBuf,
|
|
DWORD OutGlobalBufSize,
|
|
LPVOID InLocalBuf,
|
|
DWORD InLocalBufSize,
|
|
PDWORD InLocalBufActualSize,
|
|
LPVOID * InGlobalBuf,
|
|
PDWORD InGlobalBufSize
|
|
)
|
|
{
|
|
DWORD Status;
|
|
RPC_STATUS RpcStatus;
|
|
LPC_MSG * Msg;
|
|
|
|
ASSERT(ObjectType == LpcPortObjectType);
|
|
|
|
RpcStatus = Send(OutLocalBuf, OutLocalBufSize, OutGlobalBuf, OutGlobalBufSize);
|
|
if (RpcStatus != RPC_S_OK) {
|
|
return (RpcStatus);
|
|
}
|
|
Status = Sem.WaitOrOwnerDead(PeerPort->ProcessId);
|
|
|
|
switch (Status)
|
|
{
|
|
case LPC_SEM_WAIT_PROCESS_DEAD:
|
|
return (RPC_P_CONNECTION_CLOSED);
|
|
|
|
case LPC_SEM_WAIT_SUCCESS:
|
|
break;
|
|
|
|
default:
|
|
return (RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
Msg = MsgQueue.Dequeue();
|
|
if (Msg == NULL) {
|
|
Disconnect();
|
|
return (RPC_P_CONNECTION_CLOSED);
|
|
}
|
|
|
|
if (CopyLocal(InLocalBuf, InLocalBufSize, InLocalBufActualSize, Msg) == FALSE) {
|
|
delete Msg;
|
|
return (RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
CopyGlobal(InGlobalBuf, InGlobalBufSize, Msg);
|
|
|
|
delete Msg;
|
|
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
VOID
|
|
LPC_DATA_PORT::Disconnect(
|
|
)
|
|
{
|
|
ASSERT(ObjectType == LpcPortObjectType);
|
|
|
|
CritSec.Enter();
|
|
|
|
if (PeerPort) {
|
|
PeerPort->Dereference();
|
|
PeerPort = NULL;
|
|
|
|
if (PeerSem) {
|
|
|
|
delete PeerSem;
|
|
PeerSem = NULL;
|
|
}
|
|
}
|
|
|
|
CritSec.Leave();
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
LPC_CLIENT_PORT::Connect(
|
|
LPCSTR PortName
|
|
)
|
|
{
|
|
int i;
|
|
LPC_MSG * Msg;
|
|
LPC_CONNECT_PORT * ConnectPort;
|
|
LPC_SEM * ConnectSem;
|
|
DWORD Status;
|
|
RPC_STATUS RpcStatus;
|
|
|
|
ASSERT(ObjectType == LpcPortObjectType);
|
|
|
|
RpcStatus = RPC_S_SERVER_UNAVAILABLE;
|
|
|
|
CritSec.Enter();
|
|
|
|
if (PeerPort) {
|
|
CritSec.Leave();
|
|
return (RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
|
|
for (i = 0; i < ConnectReferenceIterations; i++) {
|
|
ConnectPort = LpcSystemReferencePortByName(PortName);
|
|
if (ConnectPort != NULL) {
|
|
break;
|
|
}
|
|
Sleep(ConnectReferenceDelay);
|
|
}
|
|
|
|
if (ConnectPort == NULL) {
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("LRPC-C: client port %x failed to find %s\n", this, PortName);
|
|
#endif
|
|
CritSec.Leave();
|
|
return (RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
|
|
ASSERT(ConnectPort->ObjectType == LpcPortObjectType);
|
|
|
|
Msg = new LPC_MSG(this, 0, 0);
|
|
if (Msg == NULL) {
|
|
RpcStatus = RPC_S_OUT_OF_MEMORY;
|
|
goto cleanup_and_return;
|
|
}
|
|
|
|
ConnectSem = new LPC_SEM(ConnectPort->Sem);
|
|
|
|
ConnectPort->CritSec.Enter();
|
|
|
|
ConnectPort->MsgQueue.Enqueue(Msg);
|
|
|
|
ConnectPort->CritSec.Leave();
|
|
|
|
Status = ConnectSem->Release();
|
|
|
|
delete ConnectSem;
|
|
|
|
if (Status != ERROR_SUCCESS) {
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("LRPC-C: Connect Release failed %d\n", Status);
|
|
#endif
|
|
goto cleanup_and_return;
|
|
}
|
|
|
|
Status = Sem.Wait(ConnectSignalTimeout);
|
|
|
|
if (Status != WAIT_OBJECT_0) {
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("LRPC-C: Connect Wait failed %d\n", Status);
|
|
#endif
|
|
goto cleanup_and_return;
|
|
}
|
|
|
|
if (PeerPort == NULL) {
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("LRPC-C: Connect PeerPort not assigned\n");
|
|
#endif
|
|
goto cleanup_and_return;
|
|
}
|
|
|
|
PeerSem = new LPC_SEM(PeerPort->Sem);
|
|
if (PeerSem == NULL) {
|
|
RpcStatus = RPC_S_OUT_OF_MEMORY;
|
|
goto cleanup_and_return;
|
|
}
|
|
|
|
PeerPort->AddRef();
|
|
|
|
#ifdef DEBUGRPC_DETAIL
|
|
PrintToDebugger("LRPC: Client Port %x connected to Server Port %x (%s)\n", this, PeerPort, PortName);
|
|
#endif
|
|
|
|
RpcStatus = RPC_S_OK;
|
|
|
|
cleanup_and_return:
|
|
|
|
ConnectPort->Dereference();
|
|
|
|
CritSec.Leave();
|
|
|
|
return (RpcStatus);
|
|
}
|
|
|
|
LPC_CONNECT_PORT_LIST::LPC_CONNECT_PORT_LIST(
|
|
)
|
|
{
|
|
Head = Tail = NULL;
|
|
}
|
|
|
|
VOID
|
|
LPC_CONNECT_PORT_LIST::Insert(
|
|
LPC_CONNECT_PORT * Port
|
|
)
|
|
{
|
|
Port->Next = NULL;
|
|
Port->Prev = Tail;
|
|
|
|
if (Tail == NULL) {
|
|
Head = Port;
|
|
} else {
|
|
Tail->Next = Port;
|
|
}
|
|
|
|
Tail = Port;
|
|
}
|
|
|
|
BOOL
|
|
LPC_CONNECT_PORT_LIST::Remove(
|
|
LPC_CONNECT_PORT * Port
|
|
)
|
|
{
|
|
LPC_CONNECT_PORT * Cursor;
|
|
|
|
for (Cursor = Head; Cursor != NULL; Cursor = Cursor->Next) {
|
|
if (Cursor == Port) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Cursor == NULL) {
|
|
return (FALSE);
|
|
}
|
|
|
|
if (Port->Prev) {
|
|
Port->Prev->Next = Port->Next;
|
|
} else {
|
|
Head = Port->Next;
|
|
}
|
|
|
|
if (Port->Next) {
|
|
Port->Next->Prev = Port->Prev;
|
|
} else {
|
|
Tail = Port->Prev;
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|