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.

754 lines
20 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: DPNSVRQ.cpp
  6. * Content: DirectPlay8 Server Queues Header
  7. *@@BEGIN_MSINTERNAL
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 03/19/00 rmt Modified from dplmsgq
  12. * 06/28/2000 rmt Prefix Bug #38044
  13. * 07/06/00 rmt Bug #38111 - Fixed prefix bug
  14. * 07/21/2000 rmt Removed assert that wasn't needed
  15. * 08/05/2000 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
  16. * 08/31/2000 rmt Prefix Bug #171825, 171828
  17. * 04/03/2001 RichGr Bug #325752 - Improved Queue mutex so opens, updates and closes don't clash.
  18. *@@END_MSINTERNAL
  19. *
  20. ***************************************************************************/
  21. #include "dnsvlibi.h"
  22. #undef DPF_SUBCOMP
  23. #define DPF_SUBCOMP DN_SUBCOMP_DPNSVR
  24. // DirectPlay8Server Message Queues
  25. //
  26. // We will use shared memory circular message buffers to implement this.
  27. // Each MsgQ has a set of synchronization objects to control access to the MsgQs.
  28. // The head of the shared memory file contains state information about the MsgQ:
  29. // pStartAddress
  30. // dwTotalUsableSpace
  31. // dwFirstMsgOffset
  32. // dwNextFreeOffset
  33. // dwFreeSpaceAtEnd
  34. // dwTotalFreeSpace
  35. // Messages are DWORD aligned in the MsgQ.
  36. // Each message in the MsgQ has a header:
  37. // dwMsgId
  38. // dwCurrentOffset
  39. // dwCurrentSize
  40. // dwTotalSize
  41. // Messages which fit in one frame have dwCurrentSize = dwTotalSize and dwCurrentOffset = 0.
  42. // Messages over multiple frames have dwCurrentSize < dwTotalSize.
  43. //**********************************************************************
  44. // Constant definitions
  45. //**********************************************************************
  46. //**********************************************************************
  47. // Macro definitions
  48. //**********************************************************************
  49. //**********************************************************************
  50. // Structure definitions
  51. //**********************************************************************
  52. //**********************************************************************
  53. // Variable definitions
  54. //**********************************************************************
  55. //**********************************************************************
  56. // Function prototypes
  57. //**********************************************************************
  58. //**********************************************************************
  59. // Function definitions
  60. //**********************************************************************
  61. //**********************************************************************
  62. // ------------------------------
  63. // CDPNSVRIPCQueue::Open
  64. //
  65. // Entry: const DWORD dwPID Id associated with this queue (user supplied)
  66. // const CHAR cSuffix Suffix character associated with this Q (user supp.)
  67. // const DWORD dwQueueSize Size of file map to use when implementing msg queue
  68. // const DWORD dwFlags TBA
  69. //
  70. // Exit: HRESULT: DPN_OK If able to open an existing message queue,
  71. // or create a message queue if one didn't exist
  72. // DPNERR_OUTOFMEMORY
  73. // ------------------------------
  74. // String of GUID in length
  75. #define QUEUE_NAME_LENGTH 64
  76. #undef DPF_MODNAME
  77. #define DPF_MODNAME "CDPNSVRIPCQueue::Open"
  78. HRESULT CDPNSVRIPCQueue::Open(const GUID * const pguidQueueName,const DWORD dwQueueSize,const DWORD dwFlags)
  79. {
  80. HRESULT hResultCode;
  81. DWORD dwRet = 0;
  82. BOOL bQueueExists = FALSE;
  83. DWORD dwFileMapSize;
  84. TCHAR szObjectName[QUEUE_NAME_LENGTH];
  85. TCHAR* pszCursor = szObjectName;
  86. DPFX(DPFPREP,6,"Parameters: dwQueueSize [%d], dwFlags [0x%x]",dwQueueSize,dwFlags);
  87. _tcscpy(pszCursor, GLOBALIZE_STR);
  88. pszCursor += _tcslen(GLOBALIZE_STR);
  89. // Build GUID string name
  90. wsprintf(
  91. pszCursor,
  92. _T("{%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}"),
  93. pguidQueueName->Data1,
  94. pguidQueueName->Data2,
  95. pguidQueueName->Data3,
  96. pguidQueueName->Data4[0],
  97. pguidQueueName->Data4[1],
  98. pguidQueueName->Data4[2],
  99. pguidQueueName->Data4[3],
  100. pguidQueueName->Data4[4],
  101. pguidQueueName->Data4[5],
  102. pguidQueueName->Data4[6],
  103. pguidQueueName->Data4[7] );
  104. DPFX(DPFPREP, 7, "Shared object name [%s]", szObjectName);
  105. // If there is no mutex, it is created. If it already exists, we get a handle to it.
  106. *pszCursor = DPNSVR_MSGQ_OBJECT_IDCHAR_MUTEX;
  107. m_hQueueGUIDMutex = DNCreateMutex(DNGetNullDacl(), FALSE, szObjectName);
  108. if (m_hQueueGUIDMutex == NULL)
  109. {
  110. DPFERR("CreateMutex() failed" );
  111. hResultCode = DPNERR_OUTOFMEMORY;
  112. goto Failure;
  113. }
  114. // Wait for the mutex.
  115. dwRet = DNWaitForSingleObject(m_hQueueGUIDMutex, INFINITE);
  116. if (dwRet != WAIT_ABANDONED && dwRet != WAIT_OBJECT_0)
  117. {
  118. DPFERR("WaitForSingleObject() failed" );
  119. hResultCode = DPNERR_GENERIC;
  120. goto Failure;
  121. }
  122. // Create Receive Thread Running Event
  123. // This will be set by the receive thread once it has spun up. We need it for synchronization
  124. m_hReceiveThreadRunningEvent = DNCreateEvent(NULL,TRUE,FALSE,NULL);
  125. if (m_hReceiveThreadRunningEvent == NULL)
  126. {
  127. DPFERR("Could not create receive thread");
  128. hResultCode = DPNERR_OUTOFMEMORY;
  129. goto Failure;
  130. }
  131. // Set the filemap size big enough that the largest message (text) will be dwQueueSize
  132. // so we add on the MsgQ info structure at the front and 1 Msg header
  133. dwFileMapSize = dwQueueSize + sizeof(DPNSVR_MSGQ_INFO) + sizeof(DPNSVR_MSGQ_HEADER);
  134. dwFileMapSize = (dwFileMapSize + 3) & 0xfffffffc; // DWORD align
  135. // Create File Mapping Object
  136. *pszCursor = DPNSVR_MSGQ_OBJECT_IDCHAR_FILEMAP;
  137. m_hFileMap = DNCreateFileMapping(INVALID_HANDLE_VALUE,DNGetNullDacl(),
  138. PAGE_READWRITE,(DWORD)0,dwQueueSize,szObjectName);
  139. if (m_hFileMap == NULL)
  140. {
  141. DPFERR("CreateFileMapping() failed");
  142. hResultCode = DPNERR_GENERIC;
  143. goto Failure;
  144. }
  145. if (GetLastError() == ERROR_ALREADY_EXISTS)
  146. bQueueExists = TRUE;
  147. if ((dwFlags & DPNSVR_MSGQ_OPEN_FLAG_NO_CREATE) && !bQueueExists)
  148. {
  149. DPFERR("Open existing queue failed - does not exist");
  150. hResultCode = DPNERR_DOESNOTEXIST;
  151. goto Failure;
  152. }
  153. // Map file
  154. m_pFileMapAddress = reinterpret_cast<BYTE*>(MapViewOfFile(HANDLE_FROM_DNHANDLE(m_hFileMap),FILE_MAP_ALL_ACCESS,0,0,0));
  155. if (m_pFileMapAddress == NULL)
  156. {
  157. DPFERR("MapViewOfFile() failed");
  158. hResultCode = DPNERR_OUTOFMEMORY;
  159. goto Failure;
  160. }
  161. // Create semaphore object
  162. *pszCursor = DPNSVR_MSGQ_OBJECT_IDCHAR_SEMAPHORE;
  163. m_hSemaphore = DNCreateSemaphore(DNGetNullDacl(),0,
  164. (dwQueueSize/sizeof(DPNSVR_MSGQ_HEADER))+1,szObjectName);
  165. if (m_hSemaphore == NULL)
  166. {
  167. DPFERR("CreateSemaphore() failed");
  168. hResultCode = DPNERR_OUTOFMEMORY;
  169. goto Failure;
  170. }
  171. // Create another semaphore (was an event, but we want to make sure we don't miss any).
  172. *pszCursor = DPNSVR_MSGQ_OBJECT_IDCHAR_EVENT;
  173. m_hEvent = DNCreateSemaphore( DNGetNullDacl(), 0, (dwQueueSize/sizeof(DPNSVR_MSGQ_HEADER))+1, szObjectName );
  174. if( m_hEvent == NULL )
  175. {
  176. DPFERR( "CreateSemaphore() failed" );
  177. hResultCode = DPNERR_OUTOFMEMORY;
  178. goto Failure;
  179. }
  180. // Update structure elements
  181. m_pInfo = reinterpret_cast<DPNSVR_MSGQ_INFO*>(m_pFileMapAddress);
  182. // Initialize msg queue if it didn't exist
  183. if ( !bQueueExists)
  184. {
  185. m_pInfo->dwFlags = dwFlags & 0x0000ffff; // Just last two bytes
  186. m_pInfo->dwStartOffset = 0;
  187. m_pInfo->dwEndOffset = 0;
  188. m_pInfo->dwQueueSize = dwQueueSize - sizeof(DPNSVR_MSGQ_INFO);
  189. m_pInfo->dwFreeBytes = m_pInfo->dwQueueSize;
  190. m_pInfo->lRefCount = 0;
  191. }
  192. m_pData = (BYTE *) &m_pInfo[1];
  193. m_dwSig = DPNSVR_MSGQ_SIGNATURE;
  194. // Increment user count
  195. m_pInfo->lRefCount++;
  196. DNReleaseMutex(m_hQueueGUIDMutex);
  197. // If we made it this far, everything was okay
  198. hResultCode = DPN_OK;
  199. Exit:
  200. DPFX(DPFPREP, 6, "Returning: [0x%lx]", hResultCode);
  201. return hResultCode;
  202. Failure:
  203. // There was a problem - close handles
  204. DPFERR("Errors encountered - closing");
  205. CloseHandles();
  206. if (m_hQueueGUIDMutex)
  207. {
  208. DNReleaseMutex(m_hQueueGUIDMutex);
  209. DNCloseHandle(m_hQueueGUIDMutex);
  210. m_hQueueGUIDMutex = NULL;
  211. }
  212. goto Exit;
  213. }
  214. //**********************************************************************
  215. // ------------------------------
  216. // CDPNSVRIPCQueue::Close
  217. //
  218. // Entry: Nothing
  219. //
  220. // Exit: Nothing
  221. // ------------------------------
  222. #undef DPF_MODNAME
  223. #define DPF_MODNAME "CDPNSVRIPCQueue::Close"
  224. void CDPNSVRIPCQueue::Close(void)
  225. {
  226. DWORD dwRet = 0;
  227. DPFX(DPFPREP, 6,"Parameters: (none)");
  228. // Wait for mutex to be signalled.
  229. if (m_hQueueGUIDMutex)
  230. {
  231. dwRet = DNWaitForSingleObject(m_hQueueGUIDMutex, INFINITE);
  232. if (dwRet != WAIT_ABANDONED && dwRet != WAIT_OBJECT_0)
  233. {
  234. DPFERR("WaitForSingleObject() failed" );
  235. return;
  236. }
  237. }
  238. CloseHandles();
  239. if (m_hQueueGUIDMutex)
  240. {
  241. DNReleaseMutex(m_hQueueGUIDMutex);
  242. DNCloseHandle(m_hQueueGUIDMutex);
  243. m_hQueueGUIDMutex = NULL;
  244. }
  245. DPFX(DPFPREP, 6,"Returning");
  246. return;
  247. }
  248. //**********************************************************************
  249. // ------------------------------
  250. // CDPNSVRIPCQueue::CloseHandles
  251. //
  252. // Entry: Nothing
  253. //
  254. // Exit: Nothing
  255. // ------------------------------
  256. #undef DPF_MODNAME
  257. #define DPF_MODNAME "CDPNSVRIPCQueue::CloseHandles"
  258. void CDPNSVRIPCQueue::CloseHandles()
  259. {
  260. DPFX(DPFPREP, 6, "Parameters: (none)");
  261. if( m_pInfo != NULL )
  262. {
  263. // Decrement user count
  264. m_pInfo->lRefCount--;
  265. // If the RefCount on the memory-mapped Queue object is 0, then no-one else
  266. // has it open and we can mark the signature and set the rest of the header info to zero.
  267. if (m_pInfo->lRefCount == 0)
  268. {
  269. DPFX(DPFPREP, 7, "Finished with memory-mapped Queue object - clear it");
  270. m_pInfo->dwFlags = 0;
  271. m_pInfo->dwStartOffset = 0;
  272. m_pInfo->dwEndOffset = 0;
  273. m_pInfo->dwQueueSize = 0;
  274. m_pInfo->dwFreeBytes = 0;
  275. }
  276. }
  277. if (m_hEvent != NULL)
  278. {
  279. DPFX(DPFPREP, 9,"Close Event [0x%p]",m_hEvent);
  280. DNCloseHandle(m_hEvent);
  281. m_hEvent = NULL;
  282. }
  283. if (m_hSemaphore != NULL)
  284. {
  285. DPFX(DPFPREP, 9,"Close Semaphore [0x%p]",m_hSemaphore);
  286. DNCloseHandle(m_hSemaphore);
  287. m_hSemaphore = NULL;
  288. }
  289. if (m_pFileMapAddress != NULL)
  290. {
  291. DPFX(DPFPREP, 9,"UnMap View of File [0x%p]",m_pFileMapAddress);
  292. UnmapViewOfFile(m_pFileMapAddress);
  293. m_pFileMapAddress = NULL;
  294. }
  295. if (m_hFileMap != NULL)
  296. {
  297. DPFX(DPFPREP, 9,"Close FileMap [0x%p]",m_hFileMap);
  298. DNCloseHandle(m_hFileMap);
  299. m_hFileMap = NULL;
  300. }
  301. if (m_hReceiveThreadRunningEvent != NULL)
  302. {
  303. DPFX(DPFPREP, 9,"Close Event [0x%p]",m_hReceiveThreadRunningEvent);
  304. DNCloseHandle(m_hReceiveThreadRunningEvent);
  305. m_hReceiveThreadRunningEvent = NULL;
  306. }
  307. m_pInfo = NULL;
  308. DPFX(DPFPREP, 6, "Returning");
  309. return;
  310. }
  311. //**********************************************************************
  312. // ------------------------------
  313. // CDPNSVRIPCQueue::Terminate
  314. //
  315. // Entry: Nothing
  316. //
  317. // Exit: Nothing
  318. // ------------------------------
  319. #undef DPF_MODNAME
  320. #define DPF_MODNAME "CDPNSVRIPCQueue::Terminate"
  321. void CDPNSVRIPCQueue::Terminate(void)
  322. {
  323. DWORD dwMsgId = DPNSVR_MSGQ_MSGID_TERMINATE;
  324. BOOL bDone = FALSE;
  325. DPFX(DPFPREP, 6,"Parameters: (none)");
  326. DNASSERT(m_pInfo != NULL);
  327. while (!bDone)
  328. {
  329. // Wait until there's enough space for the message
  330. while (sizeof(DWORD) > m_pInfo->dwFreeBytes)
  331. WaitForConsumption(INFINITE);
  332. Lock();
  333. // Ensure there is space once we get the lock
  334. // (someone else might have beaten us here)
  335. if (sizeof(DWORD) <= m_pInfo->dwFreeBytes)
  336. {
  337. AddData(reinterpret_cast<BYTE*>(&dwMsgId),sizeof(DWORD));
  338. bDone = TRUE;
  339. IndicateMessage();
  340. }
  341. Unlock();
  342. }
  343. DPFX(DPFPREP, 6,"Returning");
  344. }
  345. // GetNextMessage
  346. //
  347. // Attempts to retrieve the next message from the queue
  348. //
  349. // pMsgHeader must be large enough to hold a message header.
  350. //
  351. // If no message is present in the queue then this function fills pMsgHeader with an
  352. // idle message header
  353. //
  354. HRESULT CDPNSVRIPCQueue::GetNextMessage( PDPNSVR_MSGQ_HEADER pMsgHeader, BYTE *pbPayload, DWORD *pdwBufferSize )
  355. {
  356. HRESULT hr;
  357. Lock();
  358. hr = GetData( (BYTE *) pMsgHeader, sizeof( DPNSVR_MSGQ_HEADER ) );
  359. // If there is no header on the queue fill in the header with an
  360. // idle message
  361. if( hr == DPNERR_DOESNOTEXIST )
  362. {
  363. pMsgHeader->dwCurrentSize = sizeof( DPNSVR_MSGQ_HEADER );
  364. pMsgHeader->dwTotalSize = sizeof( DPNSVR_MSGQ_HEADER );
  365. pMsgHeader->dwMsgId = DPNSVR_MSGQ_MSGID_IDLE;
  366. pMsgHeader->hSender = 0;
  367. pMsgHeader->dwFlags = DPNSVR_MSGQ_MSGFLAGS_QUEUESYSTEM;
  368. pMsgHeader->dwCurrentOffset = 0;
  369. Unlock();
  370. return DPN_OK;
  371. }
  372. //// DBG
  373. else if( FAILED( hr ) )
  374. {
  375. DNASSERT( FALSE );
  376. }
  377. else if( pMsgHeader->dwMsgId == 0xFFFFFFFF )
  378. {
  379. DNASSERT( FALSE );
  380. }
  381. DWORD dwPayloadSize = pMsgHeader->dwCurrentSize;
  382. // Otherwise it's a valid message of some kind
  383. if( *pdwBufferSize < dwPayloadSize || pbPayload == NULL )
  384. {
  385. *pdwBufferSize = dwPayloadSize;
  386. Unlock();
  387. return DPNERR_BUFFERTOOSMALL;
  388. }
  389. *pdwBufferSize = dwPayloadSize;
  390. Consume( sizeof(DPNSVR_MSGQ_HEADER) );
  391. // There is no payload, only a header. Return here.
  392. if( dwPayloadSize == 0 )
  393. {
  394. Unlock();
  395. return DPN_OK;
  396. }
  397. hr = GetData( pbPayload, dwPayloadSize );
  398. if( FAILED( hr ) )
  399. {
  400. DPFERR("Error getting IPC queue message payload" );
  401. DNASSERT( FALSE );
  402. Unlock();
  403. return hr;
  404. }
  405. Consume( dwPayloadSize );
  406. Unlock();
  407. return DPN_OK;
  408. }
  409. // Consume
  410. //
  411. // Marks dwSize bytes as consumed
  412. //
  413. // Needs LOCK()
  414. void CDPNSVRIPCQueue::Consume( const DWORD dwSize )
  415. {
  416. DWORD dwAlignedSize = (dwSize + 3) & (~0x3);
  417. m_pInfo->dwStartOffset += dwAlignedSize;
  418. if( m_pInfo->dwStartOffset >= m_pInfo->dwQueueSize )
  419. {
  420. m_pInfo->dwStartOffset -= m_pInfo->dwQueueSize;
  421. }
  422. m_pInfo->dwFreeBytes += dwAlignedSize;
  423. DNASSERT( m_pInfo->dwFreeBytes <= m_pInfo->dwFreeBytes );
  424. IndicateConsumption();
  425. }
  426. // GetData
  427. //
  428. // Get dwSize bytes from the queue. If the queue is empty this function will return
  429. // DPNERR_DOESNOTEXIST. Once this function returns the dwSize bytes will be consumed
  430. //
  431. // REQUIRES LOCK
  432. //
  433. HRESULT CDPNSVRIPCQueue::GetData( BYTE *pbData, DWORD dwSize )
  434. {
  435. if( m_pInfo->dwQueueSize == m_pInfo->dwFreeBytes )
  436. {
  437. return DPNERR_DOESNOTEXIST;
  438. }
  439. if( pbData == NULL )
  440. {
  441. return DPNERR_BUFFERTOOSMALL;
  442. }
  443. // Calculate aligned size
  444. DWORD dwAlignedSize = (dwSize + 3) & (~0x3);
  445. // Data block we want is wrapped
  446. if( m_pInfo->dwStartOffset+dwAlignedSize > m_pInfo->dwQueueSize )
  447. {
  448. DWORD cbBytesLeft = m_pInfo->dwQueueSize - m_pInfo->dwStartOffset;
  449. DWORD cbSecondBlockAligned = dwAlignedSize - (cbBytesLeft);
  450. DWORD cbSecondBlock = dwSize - (cbBytesLeft);
  451. DNASSERT( dwAlignedSize > cbBytesLeft);
  452. memcpy( pbData, m_pData + m_pInfo->dwStartOffset, cbBytesLeft);
  453. memcpy( pbData + cbBytesLeft, m_pData , cbSecondBlock );
  454. }
  455. // Data block is contiguous
  456. else
  457. {
  458. memcpy( pbData, m_pData + m_pInfo->dwStartOffset, dwSize );
  459. }
  460. return DPN_OK;
  461. }
  462. //**********************************************************************
  463. // ------------------------------
  464. // CMessageQueue::AddData
  465. //
  466. // Entry: BYTE *const pBuffer
  467. // const DWORD dwSize
  468. //
  469. // Exit: HRESULT
  470. // ------------------------------
  471. //
  472. // REQUIRES LOCK!!
  473. //
  474. #undef DPF_MODNAME
  475. #define DPF_MODNAME "CMessageQueue::AddData"
  476. HRESULT CDPNSVRIPCQueue::AddData(BYTE *const pBuffer,
  477. const DWORD dwSize)
  478. {
  479. HRESULT hResultCode;
  480. DWORD dwAlignedSize;
  481. DPFX(DPFPREP, 6,"Parameters: pBuffer [0x%p], dwSize [%ld]",pBuffer,dwSize);
  482. dwAlignedSize = (dwSize + 3) & (~0x3);
  483. // Check to ensure there is space
  484. if( dwAlignedSize > m_pInfo->dwFreeBytes )
  485. {
  486. hResultCode = DPNERR_BUFFERTOOSMALL;
  487. goto Exit;
  488. }
  489. // We have a wrapping condition
  490. if( (m_pInfo->dwEndOffset+dwAlignedSize) > m_pInfo->dwQueueSize )
  491. {
  492. DWORD cbBytesLeft = m_pInfo->dwQueueSize - m_pInfo->dwEndOffset;
  493. DWORD cbSecondBlockAligned = dwAlignedSize - cbBytesLeft;
  494. DWORD cbSecondBlock = dwSize - cbBytesLeft;
  495. DNASSERT( dwAlignedSize > cbBytesLeft );
  496. memcpy( m_pData + m_pInfo->dwEndOffset, pBuffer, cbBytesLeft );
  497. memcpy( m_pData, pBuffer + cbBytesLeft, cbSecondBlock );
  498. m_pInfo->dwEndOffset = cbSecondBlockAligned;
  499. }
  500. // Queue is in the middle
  501. else
  502. {
  503. memcpy( m_pData + m_pInfo->dwEndOffset, pBuffer, dwSize );
  504. m_pInfo->dwEndOffset += dwAlignedSize;
  505. }
  506. m_pInfo->dwFreeBytes -= dwAlignedSize;
  507. hResultCode = DPN_OK;
  508. Exit:
  509. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  510. return(hResultCode);
  511. }
  512. //**********************************************************************
  513. // ------------------------------
  514. // CDPNSVRIPCQueue::Send
  515. //
  516. // Entry: BYTE *const pBuffer
  517. // const DWORD dwSize
  518. // const DWORD dwFlags
  519. //
  520. // Exit: HRESULT
  521. // ------------------------------
  522. #undef DPF_MODNAME
  523. #define DPF_MODNAME "CDPNSVRIPCQueue::Send"
  524. HRESULT CDPNSVRIPCQueue::Send(BYTE *const pBuffer,
  525. const DWORD dwSize,
  526. const DWORD dwTimeOut,
  527. const DWORD dwMsgFlags,
  528. const DWORD dwFlags)
  529. {
  530. HRESULT hResultCode;
  531. DWORD dwMsgSize; // DWORD aligned
  532. DWORD dwTotalMsgSize; // Msg + Header - DWORD aligned
  533. DPNSVR_MSGQ_HEADER Header;
  534. BOOL bDone;
  535. DWORD dwTimeRemaining;
  536. DWORD dwTimeStart;
  537. DWORD dwTimeFinish;
  538. DPFX(DPFPREP, 6,"Parameters: pBuffer [0x%p], dwSize [%ld], dwFlags [0x%lx]",pBuffer,dwSize,dwFlags);
  539. dwTimeRemaining = dwTimeOut;
  540. // Need DWORD aligned size
  541. dwMsgSize = (dwSize + 3) & 0xfffffffc;
  542. dwTotalMsgSize = dwMsgSize + sizeof(DPNSVR_MSGQ_HEADER);
  543. // Place the message into the MsgQ
  544. // Check to see if fragmentation is required
  545. // If we're at the end of the MsgQ and there isn't enough space for a Msg Header, REALIGN
  546. if (dwTotalMsgSize <= m_pInfo->dwQueueSize)
  547. {
  548. DPFX(DPFPREP, 7,"Message does not need to be fragmented");
  549. Header.dwMsgId = DPNSVR_MSGQ_MSGID_SEND;
  550. Header.dwCurrentOffset = 0;
  551. Header.dwCurrentSize = dwSize;
  552. Header.dwTotalSize = dwSize;
  553. Header.hSender = m_hSender;
  554. Header.dwFlags = dwMsgFlags;
  555. bDone = FALSE;
  556. while ( !bDone)
  557. {
  558. // Wait until there's enough space for the message
  559. while (dwTotalMsgSize > m_pInfo->dwFreeBytes)
  560. {
  561. if (dwTimeOut != INFINITE)
  562. {
  563. dwTimeStart = GETTIMESTAMP();
  564. }
  565. if (!WaitForConsumption(dwTimeRemaining))
  566. {
  567. return(DPNERR_TIMEDOUT);
  568. }
  569. if (dwTimeOut != INFINITE)
  570. {
  571. dwTimeFinish = GETTIMESTAMP();
  572. if ((dwTimeFinish - dwTimeStart) > dwTimeRemaining)
  573. {
  574. return(DPNERR_TIMEDOUT);
  575. }
  576. dwTimeRemaining -= (dwTimeFinish - dwTimeStart);
  577. }
  578. }
  579. Lock();
  580. // Ensure there is space once we get the lock
  581. // (someone else might have beaten us here)
  582. if (dwTotalMsgSize <= m_pInfo->dwFreeBytes)
  583. {
  584. AddData(reinterpret_cast<BYTE*>(&Header),sizeof(DPNSVR_MSGQ_HEADER));
  585. AddData(pBuffer,dwSize);
  586. bDone = TRUE;
  587. IndicateMessage();
  588. }
  589. Unlock();
  590. hResultCode = DPN_OK;
  591. }
  592. }
  593. else
  594. {
  595. DPFX(DPFPREP, 7,"Message needs to be fragmented");
  596. DNASSERT(FALSE);
  597. #pragma TODO(a-minara,"Implement this")
  598. hResultCode = DPNERR_GENERIC;
  599. }
  600. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  601. return(hResultCode);
  602. }