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.

411 lines
10 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name :
  4. pe_out.hxx
  5. Abstract:
  6. This module defines the outbound protocol event classes
  7. Author:
  8. Keith Lau (KeithLau) 6/18/98
  9. Project:
  10. SMTP Server DLL
  11. Revision History:
  12. --*/
  13. #ifndef _PE_OUT_HXX_
  14. #define _PE_OUT_HXX_
  15. #include "spinlock.h"
  16. // =================================================================
  17. // Define a structure to hold an outbound binding node
  18. //
  19. typedef struct _PE_BINDING_NODE
  20. {
  21. struct _PE_BINDING_NODE *pNext;
  22. DWORD dwPriority;
  23. DWORD dwFlags;
  24. } PE_BINDING_NODE, *LPPE_BINDING_NODE;
  25. //
  26. // Flag indicating default binding (no sink)
  27. //
  28. #define PEBN_DEFAULT 0x00000001
  29. // =================================================================
  30. // Define a structue for a command node
  31. // Each command node has a list of binding nodes
  32. //
  33. typedef struct _PE_COMMAND_NODE
  34. {
  35. struct _PE_COMMAND_NODE *pNext;
  36. LPSTR pszCommandKeyword;
  37. DWORD dwHighestPriority;
  38. LPPE_BINDING_NODE pFirstBinding;
  39. } PE_COMMAND_NODE, *LPPE_COMMAND_NODE;
  40. // =================================================================
  41. // Define a struct for a command queue entry.
  42. //
  43. typedef struct _OUTBOUND_COMMAND_Q_ENTRY
  44. {
  45. struct _OUTBOUND_COMMAND_Q_ENTRY *pNext;
  46. DWORD dwFlags;
  47. LPSTR pszFullCommand;
  48. LPSTR pszCommandKeyword;
  49. } OUTBOUND_COMMAND_Q_ENTRY, *LPOUTBOUND_COMMAND_Q_ENTRY;
  50. //
  51. // Some flag values for the queue entry
  52. //
  53. #define PECQ_PIPELINED 0x00000001
  54. // =================================================================
  55. // Fifo Queue, works as long as the first element is the link
  56. //
  57. // This also supports concurrent queue and dequeue as long as there
  58. // is a single writer and a single reader.
  59. //
  60. class CFifoQueueOld
  61. {
  62. public:
  63. CFifoQueueOld()
  64. {
  65. m_pHead = m_pTail = NULL;
  66. m_dwCount = 0;
  67. }
  68. BOOL IsEmpty() { return((!m_pHead)?TRUE:FALSE); }
  69. DWORD Length() { return(InterlockedExchangeAdd((PLONG)&m_dwCount, 0)); }
  70. LPVOID Dequeue()
  71. {
  72. if (!m_pHead)
  73. return(NULL);
  74. LPVOID pTemp = InterlockedExchangePointer(&m_pHead, *(LPVOID *)m_pHead);
  75. if (pTemp)
  76. {
  77. InterlockedCompareExchangePointer(&m_pTail, NULL, pTemp);
  78. LONG lTemp = InterlockedDecrement((PLONG)&m_dwCount);
  79. _ASSERT(lTemp >= 0);
  80. }
  81. return(pTemp);
  82. }
  83. BOOL Enqueue(LPVOID pItem)
  84. {
  85. _ASSERT(pItem);
  86. if (!pItem)
  87. return(FALSE);
  88. *(LPVOID *)pItem = NULL;
  89. if (InterlockedCompareExchangePointer(&m_pTail, pItem, NULL) == NULL)
  90. InterlockedExchangePointer(&m_pHead, pItem);
  91. else
  92. *(LPVOID *)(InterlockedExchangePointer(&m_pTail, pItem)) = pItem;
  93. InterlockedIncrement((PLONG)&m_dwCount);
  94. return(TRUE);
  95. }
  96. private:
  97. DWORD m_dwCount;
  98. LPVOID m_pHead;
  99. LPVOID m_pTail;
  100. };
  101. class CFifoQueue
  102. {
  103. public:
  104. CFifoQueue()
  105. {
  106. m_pHead = m_pTail = NULL;
  107. m_dwCount = 0;
  108. InitializeSpinLock(&m_slock);
  109. }
  110. BOOL IsEmpty() { return((!m_pHead)?TRUE:FALSE); }
  111. DWORD Length() { return(m_dwCount); }
  112. LPVOID Dequeue()
  113. {
  114. LPVOID pRet;
  115. AcquireSpinLock(&m_slock);
  116. //
  117. // Return the head of the list
  118. //
  119. pRet = m_pHead;
  120. if(pRet) {
  121. //
  122. // Advance the head of the list
  123. //
  124. m_pHead = *((LPVOID *) m_pHead);
  125. m_dwCount--;
  126. _ASSERT(m_dwCount != (~0));
  127. //
  128. // If the list is now empty, set the tail to NULL
  129. //
  130. if(m_pHead == NULL)
  131. m_pTail = NULL;
  132. }
  133. ReleaseSpinLock(&m_slock);
  134. return(pRet);
  135. }
  136. BOOL Enqueue(LPVOID pItem)
  137. {
  138. _ASSERT(pItem);
  139. if (!pItem)
  140. return(FALSE);
  141. //
  142. // Initialize the item's next pointer to NULL
  143. //
  144. *(LPVOID *)pItem = NULL;
  145. AcquireSpinLock(&m_slock);
  146. //
  147. // If the list is empty, initilize head and tail with the one
  148. // element
  149. //
  150. if(m_pTail == NULL) {
  151. _ASSERT(m_pHead == NULL);
  152. m_pHead = m_pTail = pItem;
  153. } else {
  154. //
  155. // Set the current tail's next pointer to the new item
  156. //
  157. *((LPVOID *) m_pTail) = pItem;
  158. //
  159. // Set the new tail
  160. //
  161. m_pTail = pItem;
  162. }
  163. m_dwCount++;
  164. ReleaseSpinLock(&m_slock);
  165. return(TRUE);
  166. }
  167. private:
  168. SPIN_LOCK m_slock;
  169. DWORD m_dwCount;
  170. LPVOID m_pHead;
  171. LPVOID m_pTail;
  172. };
  173. // =================================================================
  174. // Generic bound buffer
  175. //
  176. class CBoundAppendBuffer
  177. {
  178. public:
  179. CBoundAppendBuffer()
  180. {
  181. m_pBuffer = NULL;
  182. m_dwLength = 0;
  183. m_dwMaxLength = 0;
  184. }
  185. HRESULT SetBuffer(
  186. LPSTR pBuffer,
  187. DWORD dwMaxLength
  188. )
  189. {
  190. if (!pBuffer || !dwMaxLength)
  191. return(E_POINTER);
  192. m_pBuffer = pBuffer;
  193. *m_pBuffer = '\0';
  194. m_dwLength = 1;
  195. m_dwMaxLength = dwMaxLength;
  196. return(S_OK);
  197. }
  198. HRESULT Append(
  199. LPSTR pbAppendData,
  200. DWORD dwDataSize,
  201. DWORD *pdwNewSize
  202. )
  203. {
  204. if (!m_pBuffer)
  205. return(E_POINTER);
  206. // If we have a buffer, the length should be > 0
  207. _ASSERT(m_dwLength > 0);
  208. //
  209. // If the user is supplying a null terminated buffer, ignore
  210. // their null termination (terminate it ourselves)
  211. //
  212. if((dwDataSize > 0) && (pbAppendData[dwDataSize - 1] == '\0'))
  213. dwDataSize--;
  214. if ((dwDataSize + m_dwLength) > m_dwMaxLength)
  215. return(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
  216. // We support a convention for NULL terminated strings
  217. _ASSERT(m_pBuffer[m_dwLength - 1] == '\0');
  218. // Copy data and update counters
  219. CopyMemory(m_pBuffer + m_dwLength - 1, pbAppendData, dwDataSize);
  220. m_dwLength += dwDataSize;
  221. // Set the null termiantor
  222. m_pBuffer[m_dwLength - 1] = '\0';
  223. if (pdwNewSize)
  224. *pdwNewSize = m_dwLength;
  225. return(S_OK);
  226. }
  227. BOOL SetLength(DWORD dwLength)
  228. {
  229. if ((dwLength > m_dwMaxLength) ||
  230. (dwLength <= 0))
  231. return(FALSE);
  232. m_dwLength = dwLength;
  233. return(TRUE);
  234. }
  235. DWORD Length() { return(m_dwLength); }
  236. DWORD MaxLength() { return(m_dwMaxLength); }
  237. LPSTR Buffer() { return(m_pBuffer); }
  238. void Reset()
  239. {
  240. m_dwLength = 0;
  241. if (m_pBuffer)
  242. {
  243. *m_pBuffer = '\0';
  244. m_dwLength = 1;
  245. }
  246. }
  247. private:
  248. LPSTR m_pBuffer;
  249. DWORD m_dwLength;
  250. DWORD m_dwMaxLength;
  251. };
  252. //
  253. // Variable sized buffer. Supports append mode only
  254. //
  255. #define _DEFAULT_APPEND_BUFFER_SIZE 256
  256. // =================================================================
  257. // Generic growable buffer
  258. //
  259. class CAppendBuffer
  260. {
  261. public:
  262. CAppendBuffer()
  263. {
  264. m_pBuffer = m_pbDefaultBuffer;
  265. *m_pBuffer = '\0';
  266. m_dwLength = 1;
  267. m_dwMaxLength = _DEFAULT_APPEND_BUFFER_SIZE;
  268. }
  269. ~CAppendBuffer()
  270. {
  271. if (m_pBuffer != m_pbDefaultBuffer)
  272. delete [] m_pBuffer;
  273. }
  274. HRESULT Append(
  275. LPSTR pbAppendData,
  276. DWORD dwDataSize,
  277. DWORD *pdwNewSize
  278. )
  279. {
  280. LPSTR pbNew;
  281. //
  282. // If the user passes in a null terminated buffer, ignore
  283. // their null termination
  284. //
  285. if((dwDataSize > 0) && (pbAppendData[dwDataSize - 1] == '\0'))
  286. dwDataSize--;
  287. if ((dwDataSize + m_dwLength) > m_dwMaxLength)
  288. {
  289. DWORD dwNewMax = m_dwMaxLength << 3;
  290. // Grow buffer by factor of 8
  291. // Keep growing the buffer if it's still not large enough
  292. while( (dwNewMax != 0) && (dwNewMax < (dwDataSize + m_dwLength)) )
  293. dwNewMax = dwNewMax << 1;
  294. if(dwNewMax == 0) {
  295. // We bit shifted right off the deep end. dwDataSize is > 2Gig
  296. return(E_OUTOFMEMORY);
  297. }
  298. pbNew = new char[dwNewMax];
  299. if (!pbNew)
  300. return(E_OUTOFMEMORY);
  301. // Copy existing stuff over
  302. CopyMemory(pbNew, m_pBuffer, m_dwLength);
  303. m_dwMaxLength = dwNewMax;
  304. }
  305. else
  306. pbNew = m_pBuffer;
  307. // We support a convention for NULL terminated strings
  308. _ASSERT(m_dwLength > 0);
  309. _ASSERT(m_pBuffer[m_dwLength - 1] == '\0');
  310. // Copy data and update counters
  311. CopyMemory(pbNew + m_dwLength - 1, pbAppendData, dwDataSize);
  312. m_dwLength += dwDataSize;
  313. // Set the NULL terminator
  314. pbNew[m_dwLength - 1] = '\0';
  315. if (pdwNewSize)
  316. *pdwNewSize = m_dwLength;
  317. // Release the old buffer
  318. if (pbNew != m_pBuffer)
  319. {
  320. if (m_pBuffer != m_pbDefaultBuffer)
  321. delete [] m_pBuffer;
  322. m_pBuffer = pbNew;
  323. }
  324. return(S_OK);
  325. }
  326. DWORD Length() { return(m_dwLength); }
  327. DWORD MaxLength() { return(m_dwMaxLength); }
  328. LPSTR Buffer() { return(m_pBuffer); }
  329. void Reset() { m_dwLength = 1; *m_pBuffer = '\0'; }
  330. private:
  331. LPSTR m_pBuffer;
  332. DWORD m_dwLength;
  333. DWORD m_dwMaxLength;
  334. char m_pbDefaultBuffer[_DEFAULT_APPEND_BUFFER_SIZE];
  335. };
  336. #endif