Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

551 lines
12 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. conn.cpp
  5. Abstract:
  6. Code to maintain list of process connections for an active device
  7. Author:
  8. Vlad Sadovsky (VladS) 11-Feb-1997
  9. History:
  10. --*/
  11. //
  12. // Include Headers
  13. //
  14. #include "precomp.h"
  15. #include "stiexe.h"
  16. #include "conn.h"
  17. //
  18. // Static variables
  19. //
  20. //
  21. LONG g_lGlobalConnectionId = 0;
  22. LIST_ENTRY g_ConnectionListHead; //
  23. LONG g_lTotalOpenedConnections = 0; //
  24. CRIT_SECT g_ConnectionListSync; // Global sync object for linked list syncronization
  25. //
  26. // Static functions
  27. //
  28. STI_CONN *
  29. LocateConnectionByHandle(
  30. HANDLE hConnection
  31. );
  32. //
  33. // Methods
  34. //
  35. STI_CONN::STI_CONN(
  36. IN LPCTSTR pszDeviceName,
  37. IN DWORD dwMode,
  38. IN DWORD dwProcessId
  39. )
  40. {
  41. BOOL fRet;
  42. //
  43. // Initialize fields
  44. //
  45. m_dwSignature = CONN_SIGNATURE;
  46. m_dwProcessId = dwProcessId;
  47. m_pOpenedDevice = NULL;
  48. m_dwOpenMode = dwMode;
  49. strDeviceName.CopyString(pszDeviceName);
  50. m_dwNotificationMessage = 0L;
  51. m_hwndProcessWindow = NULL;
  52. m_hevProcessEvent = INVALID_HANDLE_VALUE;
  53. m_GlocalListEntry.Flink = m_GlocalListEntry.Blink = NULL;
  54. m_DeviceListEntry.Flink = m_DeviceListEntry.Blink = NULL;
  55. InitializeListHead( &m_NotificationListHead );
  56. m_hUniqueId = LongToPtr(InterlockedIncrement(&g_lGlobalConnectionId));
  57. __try {
  58. // Critical section for protecting interthread access to the device
  59. if(!InitializeCriticalSectionAndSpinCount(&m_CritSec, MINLONG)) {
  60. m_fValid = FALSE;
  61. return;
  62. }
  63. }
  64. __except (EXCEPTION_EXECUTE_HANDLER) {
  65. // This is really bad - mark this connection as invalid
  66. m_fValid = FALSE;
  67. return;
  68. }
  69. SetFlags(0);
  70. //
  71. // Locate device incrementing it's ref count
  72. //
  73. m_pOpenedDevice = g_pDevMan->IsInList(DEV_MAN_IN_LIST_DEV_ID, pszDeviceName);
  74. if (!m_pOpenedDevice) {
  75. // Failed to connect to the device
  76. DBG_WRN(("Refused connection to non-existing device (%S)", pszDeviceName));
  77. return;
  78. }
  79. //
  80. // Establish link to the device object
  81. //
  82. fRet = m_pOpenedDevice->AddConnection(this);
  83. m_pOpenedDevice->Release();
  84. if (!fRet) {
  85. //
  86. // Failed to connect to the device, find out reason
  87. //
  88. DBG_WRN(("Refused connection to device (%S)", pszDeviceName));
  89. ReportError(::GetLastError());
  90. return;
  91. }
  92. m_fValid = TRUE;
  93. DBG_TRC(("Successfully created connection to device (%S) handle:(%x)",
  94. pszDeviceName,this));
  95. }
  96. STI_CONN::~STI_CONN()
  97. {
  98. SetFlags(CONN_FLAG_SHUTDOWN);
  99. DBG_TRC(("Destroying connection(%X)",this));
  100. DumpObject();
  101. #if 0
  102. DebugDumpScheduleList(TEXT("Conn DTOR enter"));
  103. #endif
  104. EnterCrit();
  105. //
  106. // If there are items in notification queue - remove them
  107. //
  108. if (!IsListEmpty(&m_NotificationListHead )) {
  109. }
  110. LeaveCrit();
  111. //
  112. // Disconnect from the device
  113. //
  114. if (m_pOpenedDevice) {
  115. m_pOpenedDevice->RemoveConnection(this);
  116. }
  117. //
  118. // Remove from global list if still there
  119. //
  120. if (m_GlocalListEntry.Flink &&!IsListEmpty(&m_GlocalListEntry)) {
  121. RemoveEntryList(&m_GlocalListEntry);
  122. }
  123. //
  124. // We know we tried to initialize it, so it is safe to delete it.
  125. //
  126. DeleteCriticalSection(&m_CritSec);
  127. m_fValid = FALSE;
  128. }
  129. /*
  130. * Reference counting methods. It is simpler to use COM ref counting , to looks the same
  131. * as COM objects, in spite of the fact we are not really supporting COM, because QI method is
  132. * not functional
  133. */
  134. STDMETHODIMP
  135. STI_CONN::QueryInterface( REFIID riid, LPVOID * ppvObj)
  136. {
  137. return E_FAIL;
  138. }
  139. STDMETHODIMP_(ULONG)
  140. STI_CONN::AddRef( void)
  141. {
  142. return ::InterlockedIncrement(&m_cRef);
  143. }
  144. STDMETHODIMP_(ULONG)
  145. STI_CONN::Release( void)
  146. {
  147. LONG cNew;
  148. if(!(cNew = ::InterlockedDecrement(&m_cRef))) {
  149. delete this;
  150. }
  151. return cNew;
  152. }
  153. BOOL
  154. STI_CONN::
  155. SetSubscribeInfo(
  156. PLOCAL_SUBSCRIBE_CONTAINER pSubscribe
  157. )
  158. {
  159. BOOL fRet = FALSE;
  160. DBG_TRC(("Subscribing to device on connection (%X)",this));
  161. ReportError(NOERROR);
  162. //
  163. // NULL means resetting subscribe info block
  164. //
  165. if (!pSubscribe) {
  166. m_dwSubscribeFlags = 0L;
  167. m_hwndProcessWindow = NULL;
  168. m_hevProcessEvent = INVALID_HANDLE_VALUE;
  169. fRet = TRUE;
  170. }
  171. else {
  172. //
  173. // Save information needed to notify process
  174. //
  175. m_dwSubscribeFlags = pSubscribe->dwFlags;
  176. if (pSubscribe->dwFlags & STI_SUBSCRIBE_FLAG_WINDOW) {
  177. if (IsWindow((HWND)pSubscribe->upLocalWindowHandle)) {
  178. m_hwndProcessWindow = (HWND)pSubscribe->upLocalWindowHandle;
  179. m_uiNotificationMessage = pSubscribe->uiNotificationMessage;
  180. fRet = TRUE;
  181. }
  182. else {
  183. ASSERT(("Invalid window handle passed", 0));
  184. }
  185. }
  186. else if (pSubscribe->dwFlags & STI_SUBSCRIBE_FLAG_EVENT) {
  187. HANDLE hProcessMe = GetCurrentProcess();
  188. HANDLE hProcessClient = NULL;
  189. hProcessClient = ::OpenProcess(PROCESS_DUP_HANDLE,
  190. FALSE,
  191. m_dwProcessId
  192. );
  193. if (IS_VALID_HANDLE(hProcessClient)) {
  194. if (::DuplicateHandle(hProcessClient,
  195. (HANDLE)pSubscribe->upLocalEventHandle,
  196. hProcessMe,
  197. &m_hevProcessEvent,
  198. EVENT_MODIFY_STATE,
  199. 0,
  200. 0)
  201. ) {
  202. fRet = TRUE;
  203. ReportError(NOERROR);
  204. }
  205. else {
  206. DBG_WRN(("Subscribe handler failed to recognize client process on connection (%X)",this));
  207. ReportError(::GetLastError());
  208. }
  209. ::CloseHandle(hProcessClient);
  210. }
  211. else {
  212. ReportError(::GetLastError());
  213. }
  214. }
  215. }
  216. return fRet;
  217. }
  218. BOOL
  219. STI_CONN::
  220. QueueNotificationToProcess(
  221. LPSTINOTIFY pStiNotification
  222. )
  223. {
  224. BOOL fRet;
  225. //
  226. // Validate notification block
  227. //
  228. //
  229. // Add to the tail of the list
  230. //
  231. STI_NOTIFICATION * pNotification = NULL;
  232. pNotification = new STI_NOTIFICATION(pStiNotification);
  233. if (pNotification && pNotification->IsValid()) {
  234. EnterCrit();
  235. InsertTailList(&m_NotificationListHead,&pNotification->m_ListEntry);
  236. LeaveCrit();
  237. }
  238. //
  239. // Notify process
  240. //
  241. if (m_dwSubscribeFlags & STI_SUBSCRIBE_FLAG_WINDOW) {
  242. ::PostMessage(m_hwndProcessWindow,m_uiNotificationMessage ,0,0L);
  243. }
  244. else if (m_dwSubscribeFlags & STI_SUBSCRIBE_FLAG_EVENT) {
  245. ::SetEvent(m_hevProcessEvent);
  246. }
  247. fRet = TRUE;
  248. return fRet;
  249. }
  250. DWORD
  251. STI_CONN::
  252. GetNotification(
  253. PVOID pBuffer,
  254. DWORD *pdwSize
  255. )
  256. {
  257. STI_NOTIFICATION * pNotification = NULL;
  258. TAKE_STI_CONN t(this);
  259. LIST_ENTRY *pentry;
  260. if (IsListEmpty(&m_NotificationListHead)) {
  261. return ERROR_NO_DATA;
  262. }
  263. DBG_TRC(("Request to get last notification on connection (%X) ",this));
  264. //
  265. // Get size of the head
  266. //
  267. pentry = m_NotificationListHead.Flink;
  268. pNotification = CONTAINING_RECORD( pentry, STI_NOTIFICATION,m_ListEntry );
  269. if (*pdwSize < pNotification->QueryAllocSize() ) {
  270. *pdwSize = pNotification->QueryAllocSize();
  271. return ERROR_MORE_DATA;
  272. }
  273. //
  274. // Get head of the list ( and remove) and copy into user buffer
  275. //
  276. pentry = RemoveHeadList(&m_NotificationListHead);
  277. pNotification = CONTAINING_RECORD( pentry, STI_NOTIFICATION,m_ListEntry );
  278. memcpy(pBuffer,pNotification->QueryNotifyData(),pNotification->QueryAllocSize());
  279. delete pNotification;
  280. return NOERROR;
  281. }
  282. //
  283. // Create and initialize connection object
  284. //
  285. BOOL
  286. CreateDeviceConnection(
  287. LPCTSTR pszDeviceName,
  288. DWORD dwMode,
  289. DWORD dwProcessId,
  290. HANDLE *phConnection
  291. )
  292. {
  293. STI_CONN *pConn = NULL;
  294. BOOL fRet = FALSE;
  295. DWORD dwErr = NOERROR;
  296. DBG_TRC(("Request to add connection to device (%S) from process(%x) with mode (%x)",
  297. pszDeviceName, dwProcessId, dwMode));
  298. //
  299. // Create connection object
  300. //
  301. pConn = new STI_CONN(pszDeviceName,
  302. dwMode,
  303. dwProcessId);
  304. if (pConn) {
  305. if(pConn->IsValid()) {
  306. *phConnection = (HANDLE)(pConn->QueryID());
  307. fRet = TRUE;
  308. }
  309. else {
  310. // Did not initialize properly
  311. dwErr = pConn->QueryError();
  312. delete pConn;
  313. }
  314. }
  315. else {
  316. // Could not allocate connectionobject
  317. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  318. }
  319. //
  320. // If succeeded - add created object to linked list head
  321. //
  322. if (fRet)
  323. // BEGIN PROTECTED CODE
  324. {
  325. TAKE_CRIT_SECT t(g_ConnectionListSync);
  326. InsertTailList(&g_ConnectionListHead,&pConn->m_GlocalListEntry);
  327. }
  328. // END PROTECTED CODE
  329. ::SetLastError(dwErr);
  330. return fRet;
  331. }
  332. //
  333. //
  334. // Remove connection object from the list
  335. //
  336. BOOL
  337. DestroyDeviceConnection(
  338. HANDLE hConnection,
  339. BOOL fForce
  340. )
  341. {
  342. //
  343. // Find connection by id
  344. //
  345. DBG_TRC(("Request to remove connection (%X) ",hConnection));
  346. STI_CONN *pConnection = NULL;
  347. // BEGIN PROTECTED CODE
  348. {
  349. TAKE_CRIT_SECT t(g_ConnectionListSync);
  350. pConnection = LocateConnectionByHandle(hConnection);
  351. if (pConnection) {
  352. if (!fForce) {
  353. pConnection->Release();
  354. }
  355. else {
  356. delete pConnection;
  357. }
  358. }
  359. }
  360. // END PROTECTED CODE
  361. #if 0
  362. DebugDumpScheduleList(TEXT("DestroyConnection"));
  363. #endif
  364. return (!(pConnection == NULL));
  365. }
  366. //
  367. // Find connection object by given handle by walking all devices and all connections
  368. // for each device
  369. //
  370. BOOL
  371. LookupConnectionByHandle(
  372. HANDLE hConnection,
  373. STI_CONN **ppConnectionObject
  374. )
  375. {
  376. STI_CONN *pConnection = NULL;
  377. *ppConnectionObject = NULL;
  378. // BEGIN PROTECTED CODE
  379. {
  380. TAKE_CRIT_SECT t(g_ConnectionListSync);
  381. pConnection = LocateConnectionByHandle(hConnection);
  382. if (pConnection) {
  383. *ppConnectionObject = pConnection;
  384. pConnection->AddRef();
  385. }
  386. }
  387. // END PROTECTED CODE
  388. return (!(*ppConnectionObject == NULL));
  389. }
  390. //
  391. // Requires caller to synchronize access
  392. //
  393. STI_CONN *
  394. LocateConnectionByHandle(
  395. HANDLE hConnection
  396. )
  397. {
  398. LIST_ENTRY *pentry;
  399. LIST_ENTRY *pentryNext;
  400. STI_CONN *pConnection = NULL;
  401. ULONG ulInternalHandle = HandleToUlong(hConnection);
  402. for ( pentry = g_ConnectionListHead.Flink;
  403. pentry != &g_ConnectionListHead;
  404. pentry = pentryNext ) {
  405. pentryNext = pentry->Flink;
  406. pConnection = CONTAINING_RECORD( pentry, STI_CONN,m_GlocalListEntry );
  407. if ( !pConnection->IsValid()) {
  408. ASSERT(("Invalid connection signature", 0));
  409. break;
  410. }
  411. if ((ulInternalHandle == PtrToUlong(pConnection->QueryID())) &&
  412. !(pConnection->QueryFlags() & CONN_FLAG_SHUTDOWN)
  413. ) {
  414. return pConnection;
  415. }
  416. }
  417. return NULL;
  418. }