|
|
/*==========================================================================
* * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved. * * File: dplaysvr.c * Content: dplay winsock shared .exe - allows multiple apps to share * a single winsock port * History: * Date By Reason * ==== == ====== * 2/10/97 andyco created it from ddhelp * 29-jan-98 sohailm added support for stream enum sessions * 1/12/2000 aarono added support for rsip * 11/29/2000 aarono B#228292: prefix bug initialize path in WinMain() * ***************************************************************************/
#ifdef WINNT
#ifdef DBG
#undef DEBUG
#define DEBUG
#endif
#endif
#include <windows.h>
#include "dplaysvr.h"
#include "newdpf.h"
#include "memalloc.h"
#include "dphelp.h"
#if USE_RSIP
#include "rsip.h"
#elif USE_NATHELP
#include "dpnathlp.h"
#endif
#if USE_RSIP
BOOL bRsip; #endif
#if USE_NATHELP
extern BOOL natGetCapsUpdate(VOID); extern BOOL natInit(VOID); extern VOID natFini(VOID); extern HRESULT natRegisterUDPPort(DWORD port); extern IDirectPlayNATHelp *g_pINatHelp; #endif
HANDLE hInstApp; BOOL bNoCallbacks; CRITICAL_SECTION gcsCritSection; // the crit section we take in winmain
// this is a global so dphelp can take it before
// forwarding enum requests that come in on its
// receive thread (manbugs 3907)
int gnCSCount; // dplaysvr lock count
/*
* Externs */ extern RECEIVELIST gReceiveList; extern FDS gReadfds;
// we watch every dplay process so when it exits we
// make sure it cleaned up...
typedef struct _PROCESSDATA { struct _PROCESSDATA *link; DWORD pid; } PROCESSDATA, *LPPROCESSDATA;
LPPROCESSDATA lpProcessList; // list of all processes that are registered
// with us
//**********************************************************************
// Globals
//**********************************************************************
BOOL g_fDaclInited = FALSE; SECURITY_ATTRIBUTES g_sa; BYTE g_abSD[SECURITY_DESCRIPTOR_MIN_LENGTH]; PSECURITY_ATTRIBUTES g_psa = NULL; PACL g_pEveryoneACL = NULL;
/*
* ThreadProc * * Open a process and wait for it to terminate */ DWORD WINAPI ThreadProc( LPVOID *pdata ) { HANDLE hproc; DWORD rc; LPPROCESSDATA ppd; LPPROCESSDATA curr; LPPROCESSDATA prev; PROCESSDATA pd; DPHELPDATA hd; ppd = (LPPROCESSDATA) pdata;
/*
* get a handle to the process that attached to DDRAW */ DPF( 2, "Watchdog thread started for pid %08lx", ppd->pid );
hproc = OpenProcess( PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, ppd->pid ); if( hproc == NULL ) { DPF( 1, "OpenProcess for %08lx failed!", ppd->pid ); ExitThread( 0 ); }
/*
* wait for process to die */ rc = WaitForSingleObject( hproc, INFINITE ); if( rc == WAIT_FAILED ) { DPF( 1, "Wait for process %08lx failed", ppd->pid ); CloseHandle( hproc ); ExitThread( 0 ); }
/*
* remove process from the list of watched processes */ ENTER_DPLAYSVR(); pd = *ppd; curr = lpProcessList; prev = NULL; while( curr != NULL ) { if( curr == ppd ) { if( prev == NULL ) { lpProcessList = curr->link; } else { prev->link = curr->link; } DPF( 2, "PID %08lx removed from list", ppd->pid ); MemFree( curr ); break; } prev = curr; curr = curr->link; }
if( bNoCallbacks ) { DPF( 1, "No callbacks allowed: leaving thread early" ); LEAVE_DPLAYSVR(); CloseHandle( hproc ); ExitThread( 0 ); }
// clean up!
memset(&hd,0,sizeof(hd)); hd.pid = pd.pid; DPlayHelp_DeleteServer(&hd,TRUE); LEAVE_DPLAYSVR(); CloseHandle( hproc );
ExitThread( 0 ); return 0;
} /* ThreadProc */
/*
* MainWndProc */ LONG_PTR __stdcall MainWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { switch(message) { case WM_ENDSESSION: /*
* shoot ourselves in the head */ if( lParam == FALSE ) { DPF( 3, "WM_ENDSESSION" ); ENTER_DPLAYSVR(); DPF( 1, "Setting NO CALLBACKS" ); bNoCallbacks = TRUE; LEAVE_DPLAYSVR(); } else { DPF( 3, "User logging off" ); }
break;
}
return DefWindowProc(hWnd, message, wParam, lParam); } /* MainWndProc */
/*
* WindowThreadProc */ void WindowThreadProc( LPVOID pdata ) { static char szClassName[] = "DPlayHelpWndClass"; WNDCLASS cls; MSG msg; HWND hwnd;
/*
* build class and create window */ cls.lpszClassName = szClassName; cls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); cls.hInstance = hInstApp; cls.hIcon = NULL; cls.hCursor = NULL; cls.lpszMenuName = NULL; cls.style = 0; cls.lpfnWndProc = MainWndProc; cls.cbWndExtra = 0; cls.cbClsExtra = 0;
if( !RegisterClass( &cls ) ) { DPF( 1, "RegisterClass FAILED!" ); ExitThread( 0 ); }
hwnd = CreateWindow( szClassName, szClassName, WS_POPUP, 0, 0, 0, 0, NULL, NULL, hInstApp, NULL);
if( hwnd == NULL ) { DPF( 1, "No monitor window!" ); ExitThread( 0 ); }
/*
* pump the messages */ while( GetMessage( &msg, NULL, 0, 0 ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } DPF( 1, "Exiting WindowThreadProc" ); ExitThread( 1 );
} /* WindowThreadProc */
//
// called by by DPlayHelp_AddServer when we get a new process attached.
// we wait for the process to go away, and then make sure it cleaned
// all its registered servers up.
//
void WatchNewPid(LPDPHELPDATA phd) { LPPROCESSDATA ppd; BOOL found; DWORD tid;
DPF( 1, "watching new pid" );
ENTER_DPLAYSVR(); ppd = lpProcessList; found = FALSE; while( ppd != NULL ) { if( ppd->pid == phd->pid ) { DPF( 2, "Have thread for process %08lx already", phd->pid ); found = TRUE; break; } ppd = ppd->link; }
/*
* couldn't find anyone waiting on this process, so create * a brand spanking new thread */ if( !found ) { DPF( 2, "Allocating new thread for process %08lx",phd->pid ); ppd = MemAlloc( sizeof( PROCESSDATA ) ); if( ppd != NULL ) { HANDLE h;
ppd->link = lpProcessList; lpProcessList = ppd; ppd->pid = phd->pid; h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ThreadProc, (LPVOID)ppd, 0, (LPDWORD)&tid); if( h != NULL ) { DPF( 2, "Thread %08lx created",tid); CloseHandle( h ); } else { #ifdef DEBUG
DPF( 0, "COULD NOT CREATE HELPER THREAD FOR PID %08lx", phd->pid ); DebugBreak(); //_asm int 3;
#endif
} } else { #ifdef DEBUG
DPF( 0, "OUT OF MEMORY CREATING HELPER THREAD FOR PID %08lx", phd->pid ); DebugBreak(); //_asm int 3;
#endif
} } LEAVE_DPLAYSVR(); } // WatchNewPid
typedef DWORD (WINAPI *PFNREGISTERSERVICE)(DWORD,DWORD); // nt's winbase.h doesn't have these constants - we need them
// so we can compile. taken from \proj\dev\inc\winbase.h
#ifndef RSP_UNREGISTER_SERVICE
#define RSP_UNREGISTER_SERVICE 0x00000000
#endif
#ifndef RSP_SIMPLE_SERVICE
#define RSP_SIMPLE_SERVICE 0x00000001
#endif
// on Win95, we want to call RegisterServiceProcess
// but, it's not available on NT, so we can't import it directly
// here we try to find it dynamically in kernel32. if we find it,
// we call it, otherwise we assume we're on NT and it's not avaible
void MakeMeService() { HANDLE hLib; PFNREGISTERSERVICE pfnRegisterServiceProcess; hLib = LoadLibrary("kernel32.dll"); if (!hLib) { // wacky!
DPF(1,"could not load library kernel32 to register service proc"); return; } pfnRegisterServiceProcess = (PFNREGISTERSERVICE)GetProcAddress(hLib,"RegisterServiceProcess"); if (!pfnRegisterServiceProcess) { // this is expected on NT
DPF(3,"could not register service process - expected on NT"); FreeLibrary(hLib); return ; } pfnRegisterServiceProcess( 0, RSP_SIMPLE_SERVICE ); FreeLibrary(hLib); return ; } // MakeMeService
// on Win95, we want to call RegisterServiceProcess to Unregister
// (see MakeMeService)
void StopServiceProcess() { HANDLE hLib; PFNREGISTERSERVICE pfnRegisterServiceProcess; hLib = LoadLibrary("kernel32.dll"); if (!hLib) { // wacky!
DPF(1,"could not load library kernel32 to register service proc"); return; } pfnRegisterServiceProcess = (PFNREGISTERSERVICE)GetProcAddress(hLib,"RegisterServiceProcess"); if (!pfnRegisterServiceProcess) { // this is expected on NT
DPF(3,"could not unregister service process - not avail - not tragic"); FreeLibrary(hLib); return ; } // unregistered!
pfnRegisterServiceProcess( 0, RSP_UNREGISTER_SERVICE ); FreeLibrary(hLib); return ;
} // StopServiceProcess
//**********************************************************************
// ------------------------------
// DNGetNullDacl - Get a SECURITY_ATTRIBUTE structure that specifies a
// NULL DACL which is accessible by all users.
// Taken from IDirectPlay8 code base.
//
// Entry: Nothing
//
// Exit: PSECURITY_ATTRIBUTES
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNGetNullDacl"
PSECURITY_ATTRIBUTES DNGetNullDacl() { PSID psidEveryone = NULL; SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY; DWORD dwAclSize;
// This is done to make this function independent of DNOSIndirectionInit so that the debug
// layer can call it before the indirection layer is initialized.
if (!g_fDaclInited) { if (!InitializeSecurityDescriptor((SECURITY_DESCRIPTOR*)g_abSD, SECURITY_DESCRIPTOR_REVISION)) { DPF(0, "Failed to initialize security descriptor" ); goto Error; }
// Create SID for the Everyone group.
if (!AllocateAndInitializeSid(&siaWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &psidEveryone)) { DPF(0, "Failed to allocate Everyone SID" ); goto Error; }
dwAclSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidEveryone) - sizeof(DWORD);
// Allocate the ACL, this won't be a tracked allocation and we will let process cleanup destroy it
g_pEveryoneACL = (PACL)HeapAlloc(GetProcessHeap(), 0, dwAclSize); if (g_pEveryoneACL == NULL) { DPF(0, "Failed to allocate ACL buffer" ); goto Error; }
// Intialize the ACL.
if (!InitializeAcl(g_pEveryoneACL, dwAclSize, ACL_REVISION)) { DPF(0, "Failed to initialize ACL" ); goto Error; }
// Add the ACE.
if (!AddAccessAllowedAce(g_pEveryoneACL, ACL_REVISION, GENERIC_ALL, psidEveryone)) { DPF(0, "Failed to add ACE to ACL" ); goto Error; }
// We no longer need the SID that was allocated.
FreeSid(psidEveryone); psidEveryone = NULL;
// Add the ACL to the security descriptor..
if (!SetSecurityDescriptorDacl((SECURITY_DESCRIPTOR*)g_abSD, TRUE, g_pEveryoneACL, FALSE)) { DPF(0, "Failed to add ACL to security descriptor" ); goto Error; }
g_sa.nLength = sizeof(SECURITY_ATTRIBUTES); g_sa.lpSecurityDescriptor = g_abSD; g_sa.bInheritHandle = FALSE;
g_psa = &g_sa;
g_fDaclInited = TRUE; } Error: if (psidEveryone) { FreeSid(psidEveryone); psidEveryone = NULL; } return g_psa; } //**********************************************************************
/*
* WinMain */ int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { DWORD tid; DWORD rc; OSVERSIONINFOA VersionInfo; BOOL fUseGlobalNamespace; HANDLE hstartevent; HANDLE hstartupevent; HANDLE hmutex; HANDLE hackevent; LPDPHELPDATA phd; HANDLE hsharedmem; HANDLE h; char szSystemDir[MAX_PATH*sizeof(WCHAR)];
DWORD tWait;
#if (USE_RSIP || USE_NATHELP)
DWORD tLast; DWORD tNow; #define RSIP_RENEW_TEST_INTERVAL 60000
#endif
DPFINIT(); DPF( 2, "*** dplaysvr STARTED, PID=%08lx ***", GetCurrentProcessId() ); if( !MemInit() ) { DPF( 1, "Could not init memory manager" ); return 0; }
/*
* Set our working directory to the system directory. * This prevents us from holding network connections open * forever if the first DirectDraw app that we run is across * a network connection. */ memset(szSystemDir, 0, sizeof(WCHAR)); GetSystemDirectory(szSystemDir, sizeof(szSystemDir)); SetCurrentDirectory(szSystemDir);
// Determine if we're running on NT.
memset(&VersionInfo, 0, sizeof(VersionInfo)); VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo); if (GetVersionExA(&VersionInfo)) { if (VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { DPF(2, "Running on NT version %u.%u.%u, using global namespace.", VersionInfo.dwMajorVersion, VersionInfo.dwMinorVersion, VersionInfo.dwBuildNumber); fUseGlobalNamespace = TRUE; } else { DPF(2, "Running on 9x version %u.%u.%u, not using global namespace.", VersionInfo.dwMajorVersion, VersionInfo.dwMinorVersion, LOWORD(VersionInfo.dwBuildNumber)); fUseGlobalNamespace = FALSE; } } else { rc = GetLastError(); DPF(0, "Could not determine OS version (err = %u), assuming global namespace not needed.", rc); fUseGlobalNamespace = FALSE; }
// try to register ourselves as a service so user can't see us
// in task list
MakeMeService();
#if 0
// andyco - not sure if we need this...
/*
* We must guarantee that DPHELP unloads after the last ddraw app, * since ctrl-alt-del may have happened while an app held the ddraw * lock, and DPHELP needs to clean up orphaned cheap ddraw mutex * locks. */ if ( ! SetProcessShutdownParameters(0x100,SHUTDOWN_NORETRY) ) { DPF(0,"dplaysvr could not set itself to shutdown last!"); }
#endif
hInstApp = hInstance;
/*
* create startup event */ if (fUseGlobalNamespace) { hstartupevent = CreateEvent( DNGetNullDacl(), TRUE, FALSE, "Global\\" DPHELP_STARTUP_EVENT_NAME ); } else { hstartupevent = CreateEvent( NULL, TRUE, FALSE, DPHELP_STARTUP_EVENT_NAME ); } if( hstartupevent == NULL ) { DPF( 1, "Could not create startup event!" ); return 0; }
/*
* create shared memory area */ if (fUseGlobalNamespace) { hsharedmem = CreateFileMapping( INVALID_HANDLE_VALUE, DNGetNullDacl(), PAGE_READWRITE, 0, sizeof( DPHELPDATA ), "Global\\" DPHELP_SHARED_NAME ); } else { hsharedmem = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof( DPHELPDATA ), DPHELP_SHARED_NAME ); } if( hsharedmem == NULL ) { DPF( 1, "Could not create file mapping!" ); return 0; }
/*
* create mutex for people who want to use the shared memory area */ if (fUseGlobalNamespace) { hmutex = CreateMutex( DNGetNullDacl(), FALSE, "Global\\" DPHELP_MUTEX_NAME ); } else { hmutex = CreateMutex( NULL, FALSE, DPHELP_MUTEX_NAME ); } if( hmutex == NULL ) { DPF( 1, "Could not create mutex " DPHELP_MUTEX_NAME ); CloseHandle( hsharedmem ); return 0; }
/*
* create events */ if (fUseGlobalNamespace) { hstartevent = CreateEvent( DNGetNullDacl(), FALSE, FALSE, "Global\\" DPHELP_EVENT_NAME ); } else { hstartevent = CreateEvent( NULL, FALSE, FALSE, DPHELP_EVENT_NAME ); } if( hstartevent == NULL ) { DPF( 1, "Could not create event " DPHELP_EVENT_NAME ); CloseHandle( hmutex ); CloseHandle( hsharedmem ); return 0; }
if (fUseGlobalNamespace) { hackevent = CreateEvent( DNGetNullDacl(), FALSE, FALSE, "Global\\" DPHELP_ACK_EVENT_NAME ); } else { hackevent = CreateEvent( NULL, FALSE, FALSE, DPHELP_ACK_EVENT_NAME ); } if( hackevent == NULL ) { DPF( 1, "Could not create event " DPHELP_ACK_EVENT_NAME ); CloseHandle( hmutex ); CloseHandle( hsharedmem ); CloseHandle( hstartevent ); return 0; }
/*
* Create window so we can get messages */ h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) WindowThreadProc, NULL, 0, (LPDWORD)&tid ); if( h == NULL ) { DPF( 1, "Create of WindowThreadProc FAILED!" ); CloseHandle( hackevent ); CloseHandle( hmutex ); CloseHandle( hsharedmem ); CloseHandle( hstartevent ); return 0; } CloseHandle( h );
/*
* serialize access to us */ INIT_DPLAYSVR_CSECT();
if (!gbIPStarted) { rc = StartupIP(); if (FAILED(rc)) { DPF_ERR("dphelp : could not init wsock ! not adding server"); return (rc); } }
#if USE_RSIP
bRsip=rsipInit(); if(bRsip){ rsipListenPort(FALSE, SERVER_DGRAM_PORT, NULL, NULL); } #endif
#if USE_NATHELP
natInit(); if(g_pINatHelp){ natRegisterUDPPort(SERVER_DGRAM_PORT); } #endif
/*
* let invoker and anyone else who comes along know we exist */ SetEvent( hstartupevent );
tLast=tNow=timeGetTime();
/*
* loop forever, processing requests */ while( 1 ) {
wait: tWait=(tLast+RSIP_RENEW_TEST_INTERVAL)-tNow; if((int)tWait < 0){ tWait=0; } ASSERT(!(tWait &0x80000000)); /*
* wait to be notified of a request */ DPF( 1, "Waiting for next request" ); rc = WaitForSingleObject( hstartevent, tWait );
#if (USE_RSIP || USE_NATHELP)
tNow=timeGetTime(); if(rc==WAIT_TIMEOUT) { tLast=tNow; #if USE_RSIP
if(bRsip) {rsipPortExtend(tNow);} #elif USE_NATHELP
if(g_pINatHelp){natGetCapsUpdate();} #endif
goto wait; } #endif
if( rc == WAIT_FAILED ) { DPF( 1, "Wait FAILED!!!" ); continue; }
ENTER_DPLAYSVR(); phd = (LPDPHELPDATA) MapViewOfFile( hsharedmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); if( phd == NULL ) { DPF( 1, "Could not create view of file!" ); LEAVE_DPLAYSVR(); continue; }
/*
* find out what we need to do */ switch( phd->req ) { case DPHELPREQ_SUICIDE: DPF( 1, "DPHELPREQ_SUICIDE" );
#if USE_RSIP
if(bRsip){ rsipFini(); } #endif
#if USE_NATHELP
if(g_pINatHelp){ natFini(); } #endif
DPlayHelp_FreeServerList(); SetEvent( hackevent ); CloseHandle( hmutex ); UnmapViewOfFile( phd ); CloseHandle( hsharedmem ); CloseHandle( hstartevent ); if (gReceiveList.pConnection) { MemFree(gReceiveList.pConnection); } if (gReadfds.pfdbigset) { MemFree(gReadfds.pfdbigset); } FINI_DPLAYSVR_CSECT(); // This should be done after functions that use a Dacl will no longer be
// called (CreateMutex, CreateFile, etc).
if (g_pEveryoneACL) { HeapFree(GetProcessHeap(), 0, g_pEveryoneACL); g_pEveryoneACL = NULL; g_psa = NULL; g_fDaclInited = FALSE; }
#ifdef DEBUG
MemState(); #endif
DPF( 3, "Good Night Gracie" ); TerminateProcess( GetCurrentProcess(), 0 ); break;
case DPHELPREQ_RETURNHELPERPID:
DPF( 2, "DDHELPREQ_RETURNHELPERPID" ); phd->pid = GetCurrentProcessId(); break;
case DPHELPREQ_DPLAYADDSERVER:
DPF( 2, "DPHELPREQ_DPLAYADDSERVER" ); phd->hr = DPlayHelp_AddServer(phd); #if USE_RSIP
if(!bRsip){ bRsip=rsipInit(); if(bRsip){ rsipListenPort(FALSE, SERVER_DGRAM_PORT, NULL, NULL); } } #endif
#if USE_NATHELP
if(!g_pINatHelp){ natInit(); if(g_pINatHelp){ natRegisterUDPPort(SERVER_DGRAM_PORT); } } #endif
break;
case DPHELPREQ_DPLAYDELETESERVER:
DPF( 2, "DPHELPREQ_DPLAYDELETESERVER" ); DPlayHelp_DeleteServer(phd,FALSE); break;
default: DPF( 1, "helper - Unknown Request???" ); break; }
/*
* let caller know we've got the news */ UnmapViewOfFile( phd ); SetEvent( hackevent ); LEAVE_DPLAYSVR(); } StopServiceProcess();
} /* WinMain */
|