417 lines
10 KiB
C++
417 lines
10 KiB
C++
|
|
#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 <rpcasync.h> // 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: <none>
|
|
//
|
|
// 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 <delayimp.h>
|
|
|
|
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);
|
|
}
|