#include "nt.h" #include "ntrtl.h" #include "nturtl.h" #include "objbase.h" #include "status.h" #include "ssdpfuncc.h" #include "ssdpapi.h" #include "common.h" #include "ncmem.h" #include "ncdefine.h" #include "ncdebug.h" #include "client_c.c" #include "timer.h" #include // I_RpcExceptionFilter extern HANDLE g_hLaunchEvent; extern RTL_RESOURCE g_rsrcReg; LONG cInitialized = 0; static CRITICAL_SECTION g_csListOpenConn; int RpcClientStop(); static CONST c_msecMaxServiceStart = 30 * 1000; // 30 seconds static CONST c_msecPollInterval = 100; // .1 seconds BOOL FStartSsdpService() { SC_HANDLE scm; BOOL fRet = FALSE; scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (scm) { SC_HANDLE hsvc; hsvc = OpenService(scm, "SSDPSRV", SERVICE_QUERY_STATUS | SERVICE_START); if (hsvc) { SERVICE_STATUS status = {0}; DWORD dwTickStart = GetTickCount(); BOOL fDone = FALSE; do { if (QueryServiceStatus(hsvc, &status)) { switch (status.dwCurrentState) { case SERVICE_RUNNING: TraceTag(ttidSsdpCRpcInit, "SSDP Service has started"); // Success! fDone = TRUE; fRet = TRUE; break; case SERVICE_STOPPED: if (!StartService(hsvc, 0, NULL)) { AssertSz(GetLastError() != ERROR_SERVICE_ALREADY_RUNNING, "Service cannot be running!"); TraceError("StartSsdpService - could not query" "start SSDPSRV service!", HrFromLastWin32Error()); fDone = TRUE; } else { // reset this again to be more accurate dwTickStart = GetTickCount(); } break; case SERVICE_START_PENDING: if (GetTickCount() - dwTickStart >= c_msecMaxServiceStart) { // Time ran out fDone = TRUE; } else { Sleep(c_msecPollInterval); } break; } } else { // Error! TraceError("StartSsdpService - could not query" "service status for SSDPSRV!", HrFromLastWin32Error()); fDone = TRUE; } } while (!fDone); CloseServiceHandle(hsvc); } else { TraceError("StartSsdpService - could not open SSDPSRV service!", HrFromLastWin32Error()); } CloseServiceHandle(scm); } else { TraceError("StartSsdpService - could not open SC Manager!", HrFromLastWin32Error()); } return fRet; } int RpcClientStart() { HRESULT hr = S_OK; RPC_STATUS status; unsigned char * pszUuid = NULL; unsigned char * pszProtocolSequence = (unsigned char *)"ncalrpc"; unsigned char * pszNetworkAddress = NULL; unsigned char * pszOptions = NULL; unsigned char * pszStringBinding = NULL; unsigned long ulCode; status = 0; hSSDP = NULL; #ifdef DBG InitializeDebugging(); #endif // DBG TraceTag(ttidSsdpCRpcInit, "RpcClientStart - Enter"); if (!InitializeListNotify()) { TraceTag(ttidError, "RpcClientStart - InitializeListNotify failed"); goto cleanup; } RtlInitializeResource(&g_rsrcReg); if (!FStartSsdpService()) { TraceTag(ttidError, "RpcClientStart - Failed to start SSDPSRV service"); goto cleanup; } InitializeListSearch(); hr = CTimerQueue::Instance().HrInitialize(); if(FAILED(hr)) { TraceHr(ttidSsdpCRpcInit, FAL, hr, FALSE, "RpcClientStart - CTimerQueue::Instance().HrInitialize failed"); goto cleanup; } // SocketInit() returns 0 on success, and places failure codes in // GetLastError() // if (SocketInit() !=0) { TraceTag(ttidError, "RpcClientStart - SocketInit failed"); goto cleanup; } Assert(INVALID_HANDLE_VALUE == g_hLaunchEvent); g_hLaunchEvent = CreateEvent(NULL, TRUE, FALSE, NULL); hr = HrFromLastWin32Error(); TraceTag(ttidSsdpCRpcInit, FAL, hr, FALSE, "RpcClientStart - CreateEvent failed"); if (g_hLaunchEvent == NULL) { g_hLaunchEvent = INVALID_HANDLE_VALUE; return FALSE; } Assert(INVALID_HANDLE_VALUE != g_hLaunchEvent); /* Use a convenience function to concatenate the elements of */ /* the string binding into the proper sequence. */ // To-Do: Security? status = RpcStringBindingCompose(pszUuid, pszProtocolSequence, pszNetworkAddress, NULL, pszOptions, &pszStringBinding); TraceError("RpcStringBindingCompose returned.", HRESULT_FROM_WIN32(status)); ABORT_ON_FAILURE(status); /* Set the binding handle that will be used to bind to the server. */ status = RpcBindingFromStringBinding(pszStringBinding, &hSSDP); TraceError("RpcBindingFromStringBinding returned.", HRESULT_FROM_WIN32(status)); RpcStringFree(&pszStringBinding); ABORT_ON_FAILURE(status); TraceTag(ttidSsdpCRpcInit, "RpcClientStart - Exit"); return TRUE; cleanup: TraceTag(ttidError, "RpcClientStart - Exit with failure"); RpcClientStop(); SocketFinish(); #ifdef DBG UnInitializeDebugging(); #endif // DBG if (status) { // we got here from rpc errors, which leave their result in 'status' ::SetLastError(status); } return FALSE; } int RpcClientStop() { RPC_STATUS status; CleanupNotificationThread(); CleanupListSearch(); CTimerQueue::Instance().HrShutdown(INVALID_HANDLE_VALUE); if (hSSDP != NULL) { status = RpcBindingFree(&hSSDP); hSSDP = NULL; TraceError("RpcClientStop returned.", HRESULT_FROM_WIN32(status)); } if (INVALID_HANDLE_VALUE != g_hLaunchEvent) { BOOL fResult; fResult = ::CloseHandle(g_hLaunchEvent); Assert(fResult); g_hLaunchEvent = INVALID_HANDLE_VALUE; } RtlDeleteResource(&g_rsrcReg); return 0; } //+--------------------------------------------------------------------------- // // Function: SsdpStartup // // Purpose: Initializes global state for the SSDP api functions. // // Arguments: // // Returns: If the function succeeds, the return value is nonzero. // // If the function fails, the return value is zero. // To get extended error information, call GetLastError. // // Notes: This must be called at least once before calling any SSDP // API functions, or they will fail.with ERROR_NOT_READY. // // To deinitialize the ssdp library for a process, // each successful call to SsdpStartup must be balanced by a // corresponding call to SsdpCleanup. // BOOL WINAPI SsdpStartup() { int iRetVal; EnterCriticalSection(&g_csListOpenConn); iRetVal = TRUE; if (!cInitialized) { iRetVal = RpcClientStart(); } if (iRetVal) { // if we didn't hit an error, increment the reference count // cInitialized++; } LeaveCriticalSection(&g_csListOpenConn); return iRetVal; } VOID WINAPI SsdpCleanup() { EnterCriticalSection(&g_csListOpenConn); if (cInitialized > 0) { // decrement the reference count, and cleanup when the count // goes to zero. // if (--cInitialized == 0) { RpcClientStop(); SocketFinish(); #ifdef DBG UnInitializeDebugging(); #endif // DBG } } LeaveCriticalSection(&g_csListOpenConn); } // Delay load support // #include EXTERN_C FARPROC WINAPI DelayLoadFailureHook ( UINT unReason, PDelayLoadInfo pDelayInfo ); PfnDliHook __pfnDliFailureHook = DelayLoadFailureHook; BOOL DllMain(IN PVOID DllHandle, IN ULONG Reason, IN PVOID Context OPTIONAL) { switch (Reason) { case DLL_PROCESS_ATTACH: InitializeCriticalSection(&g_csListOpenConn); // We don't need to receive thread attach and detach // notifications, so disable them to help application // performance. DisableThreadLibraryCalls((HMODULE)DllHandle); break; case DLL_THREAD_ATTACH: break; case DLL_PROCESS_DETACH: DeleteCriticalSection(&g_csListOpenConn); break; case DLL_THREAD_DETACH: break; } return TRUE; } void WINAPI DHEnableDeviceHost() { EnableDeviceHost(); } void WINAPI DHDisableDeviceHost() { DisableDeviceHost(); } void WINAPI DHSetICSInterfaces(long nCount, GUID * arInterfaces) { SetICSInterfaces(nCount, arInterfaces); } void WINAPI DHSetICSOff() { SetICSOff(); } /*********************************************************************/ /* MIDL allocate and free */ /*********************************************************************/ VOID __RPC_FAR * __RPC_USER midl_user_allocate(size_t len) { return(malloc(len)); } VOID __RPC_USER midl_user_free(VOID __RPC_FAR * ptr) { free(ptr); }