2025-04-27 07:49:33 -04:00

713 lines
16 KiB
C++

/*==========================================================================
*
* Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
*
* File: enumsvr.cpp
* Content: DirectPlay8 <--> DPNSVR Utility functions
*
*@@BEGIN_MSINTERNAL
* History:
* Date By Reason
* ==== == ======
* 03/24/00 rmt Created
* 03/25/00 rmt Updated to handle new status/table format for n providers
* 09/04/00 mjn Changed DPNSVR_Register() and DPNSVR_UnRegister() to use guids directly (rather than ApplicationDesc)
*@@END_MSINTERNAL
*
***************************************************************************/
#include "dnsvlibi.h"
#undef DPF_SUBCOMP
#define DPF_SUBCOMP DN_SUBCOMP_DPNSVR
#define DPNSVR_WAIT_STARTUP 30000
#undef DPF_MODNAME
#define DPF_MODNAME "DPNSVR_WaitForStartup"
HRESULT DPNSVR_WaitForStartup( HANDLE hWaitHandle )
{
LONG lWaitResult;
DPFX(DPFPREP, 3, "Waiting for DPNSVR startup" );
// Wait for startup.. just in case it's starting up.
lWaitResult = WaitForSingleObject( hWaitHandle, DPNSVR_WAIT_STARTUP );
if( lWaitResult == WAIT_TIMEOUT )
{
DPFX(DPFPREP, 0, "Timeout waiting for DPNSVR startup" );
return DPNERR_TIMEDOUT;
}
else
{
DPFX(DPFPREP, 3, "Server has signalled it has started up" );
return DPN_OK;
}
}
#undef DPF_MODNAME
#define DPF_MODNAME "DPNSVR_SendMessage"
HRESULT DPNSVR_SendMessage( LPVOID pvMessage, DWORD dwSize )
{
CDPNSVRIPCQueue ipcQueue;
HRESULT hr;
// Attempt to open server queue
hr = ipcQueue.Open( &GUID_DPNSVR_QUEUE, DPNSVR_MSGQ_SIZE, DPNSVR_MSGQ_OPEN_FLAG_NO_CREATE );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Error opening server queue hr=[0x%lx]", hr );
return hr;
}
hr = ipcQueue.Send( (PBYTE) pvMessage, dwSize, 1000, DPNSVR_MSGQ_MSGFLAGS_USER1, 0 );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Send failed hr=[0x%lx]", hr );
}
ipcQueue.Close();
return hr;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DPNSVR_WaitForResult"
HRESULT DPNSVR_WaitForResult( CDPNSVRIPCQueue *pQueue )
{
DPNSVR_MSGQ_HEADER dplMsgHeader;
PDPNSVMSG_RESULT pdplMsgResult;
HANDLE hWaitSemaphore = pQueue->GetReceiveSemaphoreHandle();
HRESULT hr = DPN_OK;
PBYTE pbBuffer = NULL;
DWORD dwBufferSize = 0;
if( WaitForSingleObject( hWaitSemaphore, 1000 ) == WAIT_TIMEOUT )
{
DPFX(DPFPREP, 0, "ERROR: Timeout waiting for response\n" );
return DPNERR_TIMEDOUT;
}
while( 1 )
{
hr = pQueue->GetNextMessage( &dplMsgHeader, pbBuffer, &dwBufferSize );
if( hr == DPNERR_BUFFERTOOSMALL )
{
pbBuffer = new BYTE[dwBufferSize];
if( !pbBuffer )
{
hr = DPNERR_OUTOFMEMORY;
goto EXIT_ERROR;
}
}
else if( FAILED( hr ) )
{
goto EXIT_ERROR;
}
else
{
break;
}
}
pdplMsgResult = (PDPNSVMSG_RESULT) pbBuffer;
if( pdplMsgResult == NULL )
{
DPFX(DPFPREP, 0, "ERROR: Getting message failed\n");
hr = DPNERR_GENERIC;
}
else
{
if( pdplMsgResult->dwType != DPNSVMSGID_RESULT )
{
DPFX(DPFPREP, 0, "ERROR: Invalid message type from server [%d]\n", pdplMsgResult->dwType );
hr = DPNERR_GENERIC;
}
else
{
hr = pdplMsgResult->hrCommandResult;
}
}
EXIT_ERROR:
if( pbBuffer )
delete [] pbBuffer;
return hr;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DPNSVR_StartDPNSVR"
HRESULT DPNSVR_StartDPNSVR( )
{
HANDLE hStartupEvent = NULL;
HANDLE hRunningHandle = NULL;
HRESULT hr = DPN_OK;
STARTUPINFO si;
PROCESS_INFORMATION pi;
// Create / open startup event for the server
if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
{
hStartupEvent = CreateEvent( DNGetNullDacl(), TRUE, FALSE, _T("Global\\") STRING_GUID_DPNSVR_STARTUP );
}
else
{
hStartupEvent = CreateEvent( DNGetNullDacl(), TRUE, FALSE, STRING_GUID_DPNSVR_STARTUP );
}
if( hStartupEvent == NULL )
{
hr = GetLastError();
DPFX(DPFPREP, 0, "Could not create startup event lastError=0x%x", hr );
goto STARTDPNSVR_CLEANUP;
}
// Attempt to open the running event
if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
{
hRunningHandle = OpenEvent( SYNCHRONIZE, FALSE, _T("Global\\") STRING_GUID_DPNSVR_RUNNING );
}
else
{
hRunningHandle = OpenEvent( SYNCHRONIZE, FALSE, STRING_GUID_DPNSVR_RUNNING );
}
if( hRunningHandle != NULL )
{
hr = DPNSVR_WaitForStartup(hStartupEvent);
goto STARTDPNSVR_CLEANUP;
}
si.cb = sizeof(STARTUPINFO);
si.lpReserved = NULL;
si.lpDesktop = NULL;
si.lpTitle = NULL;
si.dwFlags = 0;
si.cbReserved2 = 0;
si.lpReserved2 = NULL;
DPFX(DPFPREP, 3, "Launching DPNSVR" );
// Put quotes around .exe to prevent possible security problem.
if( !CreateProcess(NULL, "\"dpnsvr.exe\"", NULL, NULL, FALSE,
NORMAL_PRIORITY_CLASS,
NULL, NULL, &si, &pi) )
{
hr = GetLastError();
DPFX(DPFPREP, 2, "Could not create dpnsvr.EXE hr=0x%x", hr );
goto STARTDPNSVR_CLEANUP;
}
DPFX(DPFPREP, 3, "Helper Process created" );
hr = DPNSVR_WaitForStartup(hStartupEvent);
STARTDPNSVR_CLEANUP:
if( hStartupEvent != NULL )
CloseHandle( hStartupEvent );
if( hRunningHandle != NULL )
CloseHandle( hRunningHandle );
return hr;
}
// DPNSVR_Register
//
// This function asks the DPNSVR process to add the application specified to it's list of applications and forward
// enumeration requests from the main port to the specified addresses.
//
// If the DPNSVR process is not running, it will be started by this function.
//
#undef DPF_MODNAME
#define DPF_MODNAME "DPNSVR_Register"
HRESULT DPNSVR_Register(GUID *const pguidApplication,
GUID *const pguidInstance,
IDirectPlay8Address *const prgpDeviceInfo)
{
HRESULT hr;
PBYTE pbSendBuffer = NULL;
DWORD dwSendBufferSize = 0;
PDPNSVMSG_OPENPORT pdpnOpenPort;
CDPNSVRIPCQueue appQueue;
DWORD dwURLSize = 0;
GUID guidSP;
hr = prgpDeviceInfo->lpVtbl->GetSP( prgpDeviceInfo, &guidSP );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Specified address does not have an SP specified hr=0x%x", hr );
return hr;
}
hr = prgpDeviceInfo->lpVtbl->GetURLA( prgpDeviceInfo, (CHAR *) pbSendBuffer, &dwURLSize );
if( hr != DPNERR_BUFFERTOOSMALL )
{
DPFX(DPFPREP, 0, "Unable to get URL size from address hr=0x%x", hr );
return hr;
}
dwSendBufferSize = sizeof( DPNSVMSG_OPENPORT ) + dwURLSize;
pbSendBuffer = new BYTE[dwSendBufferSize];
if( pbSendBuffer == NULL )
{
DPFX(DPFPREP, 0, "Failed to allocate send buffer for openport hr=0x%x", hr );
goto CLEANUP;
}
// Attempt to launch DPNSVR if it has not yet been launched
hr = DPNSVR_StartDPNSVR();
if( FAILED(hr) )
{
DPFX(DPFPREP, 0, "Failed to launch DPNSVR hr=0x%x", hr );
goto CLEANUP;
}
hr = appQueue.Open( pguidInstance, DPNSVR_MSGQ_SIZE, 0 );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Failed to open local queue hr=0x%x", hr );
goto CLEANUP;
}
pdpnOpenPort = (PDPNSVMSG_OPENPORT) pbSendBuffer;
pdpnOpenPort->dwType = DPNSVMSGID_OPENPORT;
pdpnOpenPort->dwProcessID = GetCurrentProcessId();
pdpnOpenPort->guidInstance = *pguidInstance;
pdpnOpenPort->guidApplication = *pguidApplication;
pdpnOpenPort->guidSP = guidSP;
pdpnOpenPort->dwAddressSize = dwURLSize;
hr = prgpDeviceInfo->lpVtbl->GetURLA( prgpDeviceInfo, (char *) &pdpnOpenPort[1], &dwURLSize );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Failed getting URL hr=0x%x", hr );
goto CLEANUP;
}
hr = DPNSVR_SendMessage( pbSendBuffer, dwSendBufferSize );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Failed to send message to server process hr=0x%x", hr );
goto CLEANUP;
}
hr = DPNSVR_WaitForResult( &appQueue );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Failed to wait for server result hr=0x%x", hr );
goto CLEANUP;
}
CLEANUP:
if( pbSendBuffer != NULL )
delete [] pbSendBuffer;
appQueue.Close();
return hr;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DPNSVR_UnRegister"
HRESULT DPNSVR_UnRegister(GUID *const pguidApplication,
GUID *const pguidInstance)
{
if( !DPNSVR_IsRunning() )
{
DPFX(DPFPREP, 0, "DPNSVR is not running" );
return DPNERR_INVALIDAPPLICATION;
}
DPNSVMSG_CLOSEPORT dpnClose;
HRESULT hr;
CDPNSVRIPCQueue appQueue;
hr = appQueue.Open( pguidInstance, DPNSVR_MSGQ_SIZE, 0 );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Failed to open local queue hr=0x%x", hr );
return hr;
}
dpnClose.dwType = DPNSVMSGID_CLOSEPORT;
dpnClose.dwProcessID = GetCurrentProcessId();
dpnClose.guidInstance = *pguidInstance;
dpnClose.guidApplication = *pguidApplication;
hr = DPNSVR_SendMessage( &dpnClose, sizeof( DPNSVMSG_CLOSEPORT ) );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Failed to send message to server process hr=0x%x", hr );
goto CLEANUP;
}
hr = DPNSVR_WaitForResult( &appQueue );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Failed to wait for server result hr=0x%x", hr );
}
CLEANUP:
appQueue.Close();
return hr;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DPNSVR_IsRunning"
BOOL DPNSVR_IsRunning()
{
HANDLE hRunningHandle;
// Attempt to open the running event
if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
{
hRunningHandle = OpenEvent( SYNCHRONIZE, FALSE, _T("Global\\") STRING_GUID_DPNSVR_RUNNING );
}
else
{
hRunningHandle = OpenEvent( SYNCHRONIZE, FALSE, STRING_GUID_DPNSVR_RUNNING );
}
if( hRunningHandle != NULL )
{
CloseHandle(hRunningHandle);
return TRUE;
}
else
{
return FALSE;
}
}
#undef DPF_MODNAME
#define DPF_MODNAME "DPNSVR_RequestTerminate"
HRESULT DPNSVR_RequestTerminate( GUID *pguidInstance )
{
if( !DPNSVR_IsRunning() )
{
DPFX(DPFPREP, 0, "DPNSVR is not running" );
return DPNERR_INVALIDAPPLICATION;
}
DPNSVMSG_COMMAND dpnCommand = {0};
HRESULT hr;
CDPNSVRIPCQueue appQueue;
hr = appQueue.Open( pguidInstance, DPNSVR_MSGQ_SIZE, 0 );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Failed to open local queue hr=0x%x", hr );
return hr;
}
dpnCommand.dwType = DPNSVMSGID_COMMAND;
dpnCommand.dwCommand = DPNSVCOMMAND_KILL;
dpnCommand.dwParam1 = 0;
dpnCommand.dwParam2 = 0;
dpnCommand.guidInstance = *pguidInstance;
hr = DPNSVR_SendMessage( &dpnCommand, sizeof( DPNSVMSG_COMMAND ) );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Failed to send message to server process hr=0x%x", hr );
goto CLEANUP;
}
hr = DPNSVR_WaitForResult( &appQueue );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Failed to wait for server result hr=0x%x", hr );
}
CLEANUP:
appQueue.Close();
return hr;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DPNSVR_RequestStatus"
HRESULT DPNSVR_RequestStatus( GUID *pguidInstance, PSTATUSHANDLER pStatusHandler, PVOID pvContext )
{
if( !DPNSVR_IsRunning() )
{
DPFX(DPFPREP, 0, "DPNSVR is not running" );
return DPNERR_INVALIDAPPLICATION;
}
DPNSVMSG_COMMAND dpnCommand;
HRESULT hr;
CDPNSVRIPCQueue appQueue;
HANDLE hStatusSharedMemory = NULL;
PSERVICESTATUS pServerStatus = NULL;
LONG lRet;
HANDLE hStatusMutex = NULL;
BOOL fHaveMutex = FALSE;
hr = appQueue.Open( pguidInstance, DPNSVR_MSGQ_SIZE, 0 );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Failed to open local queue hr=0x%x", hr );
return hr;
}
dpnCommand.dwType = DPNSVMSGID_COMMAND;
dpnCommand.dwCommand = DPNSVCOMMAND_STATUS;
dpnCommand.dwParam1 = 0;
dpnCommand.dwParam2 = 0;
dpnCommand.guidInstance = *pguidInstance;
hr = DPNSVR_SendMessage( &dpnCommand, sizeof( DPNSVMSG_COMMAND ) );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Failed to send message to server process hr=0x%x", hr );
goto CLEANUP;
}
hr = DPNSVR_WaitForResult( &appQueue );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Failed to wait for server result hr=0x%x", hr );
goto CLEANUP;
}
if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
{
hStatusMutex = OpenMutex( MUTEX_ALL_ACCESS, FALSE, _T("Global\\") STRING_GUID_DPNSVR_STATUSSTORAGE );
}
else
{
hStatusMutex = OpenMutex( MUTEX_ALL_ACCESS, FALSE, STRING_GUID_DPNSVR_STATUSSTORAGE );
}
if( hStatusMutex == NULL )
{
DPFX(DPFPREP, 0, "Server exited before table was retrieved" );
return DPNERR_INVALIDAPPLICATION;
}
WaitForSingleObject( hStatusMutex, INFINITE );
fHaveMutex = TRUE;
hStatusSharedMemory = OpenFileMapping(
FILE_MAP_READ,
FALSE,
STRING_GUID_DPNSVR_STATUS_MEMORY
);
lRet = GetLastError();
if (hStatusSharedMemory == NULL)
{
DPFX(DPFPREP, 0, "Unable to get server status info hr=[0x%lx] Process may not be running\n", lRet );
hr = lRet;
goto CLEANUP;
}
pServerStatus = (PSERVICESTATUS) MapViewOfFile(
hStatusSharedMemory,
FILE_MAP_READ,
0,
0,
sizeof( SERVICESTATUS ) );
lRet = GetLastError();
if (pServerStatus == NULL)
{
DPFX(DPFPREP, 0, "Unable to read status hr=[0x%lx] Process may have exited\n", lRet );
hr = lRet;
goto CLEANUP;
}
(*pStatusHandler)(pServerStatus,pvContext);
CLEANUP:
if( fHaveMutex )
ReleaseMutex( hStatusMutex );
if( hStatusMutex != NULL )
CloseHandle( hStatusMutex );
if( pServerStatus != NULL )
UnmapViewOfFile(pServerStatus);
if( hStatusSharedMemory != NULL )
CloseHandle(hStatusSharedMemory);
appQueue.Close();
return hr;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DPNSVR_RequestTable"
HRESULT DPNSVR_RequestTable( GUID *pguidInstance, PTABLEHANDLER pTableHandler, PVOID pvContext )
{
if( !DPNSVR_IsRunning() )
{
DPFX(DPFPREP, 0, "DPNSVR is not running" );
return DPNERR_INVALIDAPPLICATION;
}
DPNSVMSG_COMMAND dpnCommand;
HRESULT hr;
CDPNSVRIPCQueue appQueue;
PSERVERTABLEHEADER pTableHeader = NULL;
HANDLE hTableHandle = NULL;
HANDLE hTableMutex = NULL;
LONG lRet;
BOOL fHaveMutex = FALSE;
if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
{
hTableMutex = OpenMutex( MUTEX_ALL_ACCESS, FALSE, _T("Global\\") STRING_GUID_DPSVR_TABLESTORAGE );
}
else
{
hTableMutex = OpenMutex( MUTEX_ALL_ACCESS, FALSE, STRING_GUID_DPSVR_TABLESTORAGE );
}
if( hTableMutex == NULL )
{
DPFX(DPFPREP, 0, "Server exited before table was retrieved" );
return DPNERR_INVALIDAPPLICATION;
}
hr = appQueue.Open( pguidInstance, DPNSVR_MSGQ_SIZE, 0 );
if( FAILED( hr ) )
{
CloseHandle(hTableMutex);
DPFX(DPFPREP, 0, "Failed to open local queue hr=0x%x", hr );
return hr;
}
dpnCommand.dwType = DPNSVMSGID_COMMAND;
dpnCommand.dwCommand = DPNSVCOMMAND_TABLE;
dpnCommand.dwParam1 = 0;
dpnCommand.dwParam2 = 0;
dpnCommand.guidInstance = *pguidInstance;
hr = DPNSVR_SendMessage( &dpnCommand, sizeof( DPNSVMSG_COMMAND ) );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Failed to send message to server process hr=0x%x", hr );
goto CLEANUP;
}
hr = DPNSVR_WaitForResult( &appQueue );
if( FAILED( hr ) )
{
DPFX(DPFPREP, 0, "Failed to wait for server result hr=0x%x", hr );
goto CLEANUP;
}
// Wait for table mutex
WaitForSingleObject( hTableMutex, INFINITE );
fHaveMutex = TRUE;
// Map the table memory
hTableHandle = OpenFileMapping(
FILE_MAP_READ,
FALSE,
STRING_GUID_DPNSVR_TABLE_MEMORY
);
lRet = GetLastError();
if (hTableHandle == NULL)
{
DPFX(DPFPREP, 0, "Unable to get server status info hr=[0x%lx] Process may not be running\n", lRet );
hr = lRet;
goto CLEANUP;
}
pTableHeader = (PSERVERTABLEHEADER) MapViewOfFile(
hTableHandle,
FILE_MAP_READ,
0,
0,
0 );
lRet = GetLastError();
if (pTableHeader == NULL)
{
DPFX(DPFPREP, 0, "ERROR: Unable to read table hr=[0x%lx] Process may have exited\n", lRet );
hr = lRet;
goto CLEANUP;
}
(*pTableHandler)(pTableHeader,pvContext);
CLEANUP:
if( pTableHeader != NULL )
{
UnmapViewOfFile( pTableHeader );
}
if( hTableHandle != NULL )
{
CloseHandle( hTableHandle );
}
if( fHaveMutex )
ReleaseMutex( hTableMutex );
if( hTableMutex != NULL )
CloseHandle( hTableMutex );
appQueue.Close();
return hr;
}