//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 2000. // // File: C O N M A N S A. C P P // // Contents: Implementation of ICS connection class manager // // Notes: // // Author: kenwic 8 Aug 2000 // //---------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include "conmansa.h" #include "enumsa.h" #include "cmsabcon.h" //+--------------------------------------------------------------------------- // INetConnectionManager // CSharedAccessConnectionManager::CSharedAccessConnectionManager() { m_lSearchCookie = 0; m_pDeviceFinder = NULL; m_pDeviceFinderCallback = NULL; m_SocketEvent = WSA_INVALID_EVENT; m_hSocketNotificationWait = INVALID_HANDLE_VALUE; m_DummySocket = INVALID_SOCKET; } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnectionManager::EnumConnections // // Purpose: Returns an enumerator object for ICS connections // // Arguments: // Flags [in] // ppEnum [out] Returns enumerator object // // Returns: S_OK if succeeded, OLE or Win32 error code otherwise // // Author: kenwic 17 Jul 2000 // // Notes: // STDMETHODIMP CSharedAccessConnectionManager::EnumConnections(NETCONMGR_ENUM_FLAGS Flags, IEnumNetConnection** ppEnum) { *ppEnum = NULL; CComObject* pEnum; HRESULT hr = CComObject::CreateInstance(&pEnum); if(SUCCEEDED(hr)) { *ppEnum = static_cast(pEnum); pEnum->AddRef(); } TraceHr (ttidError, FAL, hr, FALSE, "CSharedAccessConnectionManager::EnumConnections"); return hr; } HRESULT CSharedAccessConnectionManager::FinalConstruct(void) { HRESULT hr = S_OK; m_DummySocket = socket(AF_INET, SOCK_DGRAM, 0); if(INVALID_SOCKET != m_DummySocket) { m_SocketEvent = CreateEvent(NULL, FALSE, TRUE, NULL); if(NULL != m_SocketEvent) { if(0 != WSAEventSelect(m_DummySocket, m_SocketEvent, FD_ADDRESS_LIST_CHANGE)) { hr = E_FAIL; } } else { hr = E_FAIL; } } else { hr = E_FAIL; } if(SUCCEEDED(hr)) // start up the first search on a background thread, this shoud fire immediately { // note that there is no addref here because it would keep the object alive forever. In FinalRelease we will make sure we won't get called back if(0 == RegisterWaitForSingleObject(&m_hSocketNotificationWait, m_SocketEvent, AsyncStartSearching, this, INFINITE, WT_EXECUTEDEFAULT)) { m_hSocketNotificationWait = INVALID_HANDLE_VALUE; } } TraceHr (ttidError, FAL, hr, FALSE, "CSharedAccessConnectionManager::FinalConstruct"); return hr; } HRESULT CSharedAccessConnectionManager::FinalRelease(void) { HRESULT hr = S_OK; if(INVALID_HANDLE_VALUE != m_hSocketNotificationWait) { UnregisterWaitEx(m_hSocketNotificationWait, INVALID_HANDLE_VALUE); // we must block here since we are not addrefed } if(INVALID_SOCKET != m_DummySocket) // the event wait must be unregistered first { closesocket(m_DummySocket); } if(WSA_INVALID_EVENT != m_SocketEvent) // the socket must be closed first { CloseHandle(m_SocketEvent); } // After the other thread is shut down, the device finder and callback won't change any more so we don't need a lock. if(NULL != m_pDeviceFinder) { hr = m_pDeviceFinder->CancelAsyncFind(m_lSearchCookie); m_pDeviceFinder->Release(); } if(NULL != m_pDeviceFinderCallback) { m_pDeviceFinderCallback->Release(); } TraceHr (ttidError, FAL, hr, FALSE, "CSharedAccessConnectionManager::FinalRelease"); return hr; } HRESULT CSharedAccessConnectionManager::StartSearch(void) { HRESULT hr = S_OK; CComObject* pDeviceFinderCallback; hr = CComObject::CreateInstance(&pDeviceFinderCallback); if(SUCCEEDED(hr)) { pDeviceFinderCallback->AddRef(); IUPnPDeviceFinder* pDeviceFinder; hr = CoCreateInstance(CLSID_UPnPDeviceFinder, NULL, CLSCTX_INPROC_SERVER, IID_IUPnPDeviceFinder, reinterpret_cast(&pDeviceFinder)); if(SUCCEEDED(hr)) { BSTR bstrTypeURI; bstrTypeURI = SysAllocString(L"urn:schemas-upnp-org:device:InternetGatewayDevice:1"); if (NULL != bstrTypeURI) { LONG lSearchCookie; hr = pDeviceFinder->CreateAsyncFind(bstrTypeURI, 0, static_cast(pDeviceFinderCallback), &lSearchCookie); if(SUCCEEDED(hr)) { LONG lOldSearchCookie; IUPnPDeviceFinder* pOldDeviceFinder; CComObject* pOldDeviceFinderCallback; Lock(); // swap in the new finder and callback lOldSearchCookie = m_lSearchCookie; m_lSearchCookie = lSearchCookie; pOldDeviceFinder = m_pDeviceFinder; m_pDeviceFinder = pDeviceFinder; pDeviceFinder->AddRef(); pOldDeviceFinderCallback = m_pDeviceFinderCallback; m_pDeviceFinderCallback = pDeviceFinderCallback; pDeviceFinderCallback->AddRef(); Unlock(); if(NULL != pOldDeviceFinder) { pOldDeviceFinder->CancelAsyncFind(lOldSearchCookie); pOldDeviceFinder->Release(); } if(NULL != pOldDeviceFinderCallback) { pOldDeviceFinderCallback->DeviceRemoved(NULL, NULL); // clear out the old callback, so netshell gets cleaned up pOldDeviceFinderCallback->Release(); } hr = pDeviceFinder->StartAsyncFind(lSearchCookie); // don't start the search until the new callback is in place } SysFreeString(bstrTypeURI); } pDeviceFinder->Release(); } pDeviceFinderCallback->Release(); } DWORD dwBytesReturned; if(SOCKET_ERROR != WSAIoctl(m_DummySocket, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &dwBytesReturned, NULL, NULL) || WSAEWOULDBLOCK != WSAGetLastError()) { hr = E_FAIL; } WSANETWORKEVENTS NetworkEvents; ZeroMemory(&NetworkEvents, sizeof(NetworkEvents)); WSAEnumNetworkEvents(m_DummySocket, NULL, &NetworkEvents); return hr; } void CSharedAccessConnectionManager::AsyncStartSearching(PVOID lpParameter, BOOLEAN TimerOrWaitFired) { if(FALSE == TimerOrWaitFired) { CSharedAccessConnectionManager* pThis = reinterpret_cast(lpParameter); HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if(SUCCEEDED(hr)) { hr = pThis->StartSearch(); CoUninitialize(); } } return; } HRESULT CSharedAccessConnectionManager::GetSharedAccessBeacon(BSTR DeviceId, ISharedAccessBeacon** ppSharedAccessBeacon) { HRESULT hr = S_OK; *ppSharedAccessBeacon = NULL; CComObject* pDeviceFinderCallback; Lock(); pDeviceFinderCallback = m_pDeviceFinderCallback; if(NULL != pDeviceFinderCallback) { pDeviceFinderCallback->AddRef(); } Unlock(); if(NULL != pDeviceFinderCallback) { hr = pDeviceFinderCallback->GetSharedAccessBeacon(DeviceId, ppSharedAccessBeacon); pDeviceFinderCallback->Release(); } else { hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } return hr; }