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.

553 lines
12 KiB

  1. /*++=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. ithreadpool.cxx
  5. Abstract:
  6. Implements the W3Spoof object's IThreadPool interface.
  7. Author:
  8. Paul M Midgen (pmidge) 08-February-2001
  9. Revision History:
  10. 08-February-2001 pmidge
  11. Created
  12. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--*/
  13. #include "common.h"
  14. BOOL
  15. CW3Spoof::_InitializeThreads(void)
  16. {
  17. DEBUG_ENTER((
  18. DBG_W3SOBJ,
  19. rt_bool,
  20. "CW3Spoof::_InitializeThreads",
  21. "this=%#x",
  22. this
  23. ));
  24. BOOL bStatus = FALSE;
  25. DWORD error = 0L;
  26. SOCKADDR_IN local = {0};
  27. m_hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, m_dwMaxActiveThreads);
  28. if( !m_hIOCP )
  29. {
  30. DEBUG_TRACE(
  31. W3SOBJ,
  32. ("error creating completion port: %s", MapErrorToString(GetLastError()))
  33. );
  34. goto quit;
  35. }
  36. m_sListen = socket(AF_INET, SOCK_STREAM, 0);
  37. if( m_sListen == INVALID_SOCKET )
  38. {
  39. DEBUG_TRACE(
  40. W3SOBJ,
  41. ("error creating listen socket: %s", MapErrorToString(WSAGetLastError()))
  42. );
  43. goto quit;
  44. }
  45. local.sin_family = AF_INET;
  46. local.sin_addr.s_addr = htonl(INADDR_ANY);
  47. local.sin_port = htons(m_usServerPort);
  48. error = bind(m_sListen, (PSOCKADDR) &local, sizeof(local));
  49. if( error == SOCKET_ERROR )
  50. {
  51. DEBUG_TRACE(W3SOBJ, ("error binding listen socket: %s", MapErrorToString(WSAGetLastError())));
  52. goto quit;
  53. }
  54. error = listen(m_sListen, SOMAXCONN);
  55. if( error == SOCKET_ERROR )
  56. {
  57. DEBUG_TRACE(W3SOBJ, ("error listening: %s", MapErrorToString(WSAGetLastError())));
  58. goto quit;
  59. }
  60. CreateIoCompletionPort((HANDLE) m_sListen, m_hIOCP, CK_NEW_CONNECTION, m_dwMaxActiveThreads);
  61. m_arThreads = new HANDLE[m_dwPoolSize];
  62. if( !m_arThreads )
  63. {
  64. DEBUG_TRACE(W3SOBJ, ("error allocating thread handles: %s", MapErrorToString(GetLastError())));
  65. goto quit;
  66. }
  67. for(DWORD n=0; n < m_dwPoolSize; n++)
  68. {
  69. m_arThreads[n] = CreateThread(
  70. NULL, 0,
  71. ThreadFunc, (LPVOID) (static_cast<IThreadPool*>(this)),
  72. 0, NULL
  73. );
  74. if( !m_arThreads[n] )
  75. {
  76. DEBUG_TRACE(W3SOBJ, ("error creating thread %d: %s", n, MapErrorToString(GetLastError())));
  77. goto quit;
  78. }
  79. }
  80. bStatus = TRUE;
  81. quit:
  82. DEBUG_LEAVE(bStatus);
  83. return bStatus;
  84. }
  85. void
  86. CW3Spoof::_TerminateThreads(void)
  87. {
  88. DEBUG_ENTER((
  89. DBG_W3SOBJ,
  90. rt_void,
  91. "CW3Spoof::_TerminateThreads",
  92. "this=%#x",
  93. this
  94. ));
  95. //
  96. // BUGBUG: this could generate *_OPERATION_ABORTED results, need to keep this in mind
  97. // in case there are weird state issues handling aborted io ops. should be no
  98. // problem... but you never know.
  99. //
  100. SAFECLOSESOCKET(m_sListen);
  101. for(DWORD n=0; n < m_dwPoolSize; n++)
  102. {
  103. PostQueuedCompletionStatus(m_hIOCP, 0L, CK_CANCEL_IO, NULL);
  104. }
  105. WaitForMultipleObjects(m_dwPoolSize, m_arThreads, TRUE, INFINITE);
  106. for(DWORD n=0; n < m_dwPoolSize; n++)
  107. {
  108. SAFECLOSE(m_arThreads[n]);
  109. }
  110. SAFEDELETEBUF(m_arThreads);
  111. SAFECLOSE(m_hIOCP);
  112. DEBUG_LEAVE(0);
  113. }
  114. DWORD
  115. CW3Spoof::_QueueAccept(void)
  116. {
  117. DEBUG_ENTER((
  118. DBG_W3SOBJ,
  119. rt_dword,
  120. "CW3Spoof::_QueueAccept",
  121. "this=%#x",
  122. this
  123. ));
  124. DWORD ret = ERROR_IO_PENDING;
  125. if( 0 == InterlockedCompareExchange(&m_PendingAccepts, 0, 0) )
  126. {
  127. // available pending accepts has dropped to 0, close
  128. // the accept queue.
  129. m_AcceptQueueStatus = 0;
  130. }
  131. else
  132. {
  133. if( m_AcceptQueueStatus )
  134. {
  135. BOOL bAccepted = TRUE;
  136. PIOCTX pioc = NULL;
  137. InterlockedDecrement(&m_PendingAccepts);
  138. pioc = new IOCTX(IOCT_CONNECT, socket(AF_INET, SOCK_STREAM, 0));
  139. if( pioc && pioc->sockbuf )
  140. {
  141. bAccepted = AcceptEx(
  142. m_sListen,
  143. pioc->socket,
  144. (LPVOID) pioc->sockbuf,
  145. 0L,
  146. sizeof(SOCKADDR_IN)+16,
  147. sizeof(SOCKADDR_IN)+16,
  148. NULL,
  149. &pioc->overlapped
  150. );
  151. if( !bAccepted )
  152. {
  153. ret = WSAGetLastError();
  154. }
  155. }
  156. else
  157. {
  158. ret = ERROR_OUTOFMEMORY;
  159. }
  160. }
  161. else
  162. {
  163. ret = ERROR_SUCCESS;
  164. DEBUG_TRACE(W3SOBJ, ("queue is closed"));
  165. }
  166. }
  167. DEBUG_LEAVE(ret);
  168. return ret;
  169. }
  170. BOOL
  171. CW3Spoof::_CompleteAccept(PIOCTX pioc)
  172. {
  173. DEBUG_ENTER((
  174. DBG_W3SOBJ,
  175. rt_bool,
  176. "CW3Spoof::_CompleteAccept",
  177. "this=%#x; pioc=%#x",
  178. this, pioc
  179. ));
  180. BOOL bStatus = FALSE;
  181. if( pioc->socket != INVALID_SOCKET )
  182. {
  183. DWORD mode = 1L;
  184. struct linger _linger = {1, 2};
  185. setsockopt(
  186. pioc->socket,
  187. SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
  188. (char*) &m_sListen, sizeof(m_sListen)
  189. );
  190. setsockopt(
  191. pioc->socket,
  192. SOL_SOCKET, SO_LINGER,
  193. (char*) &_linger, sizeof(struct linger)
  194. );
  195. setsockopt(
  196. pioc->socket,
  197. IPPROTO_TCP, TCP_NODELAY,
  198. (char*) &mode, sizeof(DWORD)
  199. );
  200. ParseSocketInfo(pioc);
  201. bStatus = SUCCEEDED(Register(pioc->socket)) ? TRUE : FALSE;
  202. }
  203. // increment available pending accepts and check to see if the queue
  204. // can be reopened
  205. InterlockedIncrement(&m_PendingAccepts);
  206. if( m_MaxQueuedAccepts ==
  207. InterlockedCompareExchange(&m_PendingAccepts, m_MaxQueuedAccepts, m_MaxQueuedAccepts)
  208. )
  209. {
  210. m_AcceptQueueStatus = 1;
  211. }
  212. DEBUG_LEAVE(bStatus);
  213. return bStatus;
  214. }
  215. BOOL
  216. CW3Spoof::_DisconnectSocket(PIOCTX pioc, BOOL fNBGC)
  217. {
  218. if( pioc->socket != INVALID_SOCKET )
  219. {
  220. if( fNBGC )
  221. {
  222. shutdown(pioc->socket, SD_SEND);
  223. }
  224. else
  225. {
  226. struct linger _linger = {1, 0};
  227. setsockopt(
  228. pioc->socket,
  229. SOL_SOCKET, SO_LINGER,
  230. (char*) &_linger, sizeof(struct linger)
  231. );
  232. }
  233. closesocket(pioc->socket);
  234. pioc->socket = INVALID_SOCKET;
  235. return TRUE;
  236. }
  237. return FALSE;
  238. }
  239. HRESULT
  240. __stdcall
  241. CW3Spoof::GetStatus(PIOCTX* ppioc, LPBOOL pbQuit)
  242. {
  243. DEBUG_ENTER((
  244. DBG_W3SOBJ,
  245. rt_hresult,
  246. "CW3Spoof::GetStatus",
  247. "this=%#x; ppioc=%#x; pbQuit=%#x",
  248. this,
  249. ppioc,
  250. pbQuit
  251. ));
  252. HRESULT hr = S_OK;
  253. DWORD error = ERROR_SUCCESS;
  254. DWORD comp = 0L;
  255. DWORD bytes = 0L;
  256. LPOVERLAPPED lpo = NULL;
  257. _QueueAccept();
  258. if( GetQueuedCompletionStatus(m_hIOCP, &bytes, &comp, &lpo, INFINITE) )
  259. {
  260. switch( comp )
  261. {
  262. case CK_NEW_CONNECTION :
  263. {
  264. DEBUG_TRACE(W3SOBJ, ("status: new connection"));
  265. *ppioc = GETIOCTX(lpo);
  266. *pbQuit = FALSE;
  267. if( (*ppioc) && _CompleteAccept(*ppioc) )
  268. {
  269. IW3Spoof* pw3s = NULL;
  270. hr = QueryInterface(IID_IW3Spoof, (void**) &pw3s);
  271. if( SUCCEEDED(hr) )
  272. {
  273. hr = SESSIONOBJ::Create(*ppioc, pw3s);
  274. SAFERELEASE(pw3s);
  275. }
  276. }
  277. else
  278. {
  279. SAFERELEASE((*ppioc));
  280. hr = E_FAIL;
  281. }
  282. if( FAILED(hr) )
  283. {
  284. break;
  285. }
  286. }
  287. case CK_NORMAL :
  288. {
  289. DEBUG_TRACE(W3SOBJ, ("status: normal"));
  290. *ppioc = GETIOCTX(lpo);
  291. (*ppioc)->bytes = bytes;
  292. *pbQuit = FALSE;
  293. hr = S_OK;
  294. }
  295. break;
  296. case CK_CANCEL_IO :
  297. {
  298. DEBUG_TRACE(W3SOBJ, ("status: cancel io"));
  299. m_AcceptQueueStatus = 0;
  300. CancelIo((HANDLE) m_sListen);
  301. //
  302. // BUGBUG: temporary hack to get all threads to call CancelIo().
  303. // i need to figure out a better way.
  304. //
  305. // P.S. this works because it puts the thread in a non-alertable state,
  306. // which causes the completion port code to wake up another thread.
  307. //
  308. Sleep(100);
  309. PostQueuedCompletionStatus(m_hIOCP, 0L, CK_TERMINATE_THREAD, NULL);
  310. *ppioc = NULL;
  311. *pbQuit = FALSE;
  312. hr = E_FAIL;
  313. }
  314. break;
  315. case CK_TERMINATE_THREAD :
  316. {
  317. DEBUG_TRACE(W3SOBJ, ("status: terminate thread"));
  318. *ppioc = NULL;
  319. *pbQuit = TRUE;
  320. hr = E_FAIL;
  321. }
  322. break;
  323. }
  324. }
  325. else
  326. {
  327. error = GetLastError();
  328. switch( error )
  329. {
  330. case ERROR_NETNAME_DELETED :
  331. {
  332. *ppioc = GETIOCTX(lpo);
  333. //
  334. // happens when a client closes a keep-alive connection on which
  335. // we have a receive pending. if there's a session associated with
  336. // this IO, we defer error handling to the session fsm.
  337. //
  338. if( (*ppioc)->clientid && SUCCEEDED(m_sessionmap->Get((*ppioc)->clientid, (void**) &(*ppioc)->session)) )
  339. {
  340. (*ppioc)->error = error;
  341. hr = S_OK;
  342. }
  343. else
  344. {
  345. _DisconnectSocket(*ppioc, TRUE);
  346. SAFERELEASE((*ppioc));
  347. hr = E_FAIL;
  348. }
  349. }
  350. break;
  351. case ERROR_OPERATION_ABORTED :
  352. {
  353. *ppioc = GETIOCTX(lpo);
  354. //
  355. // happens when CancelIo() or closesocket() are called and there are
  356. // pending overlapped operations. if there's a session associated with
  357. // the IOCTX, we defer error handling to the session fsm.
  358. //
  359. if( (*ppioc)->clientid && SUCCEEDED(m_sessionmap->Get((*ppioc)->clientid, (void**) &(*ppioc)->session)) )
  360. {
  361. (*ppioc)->error = error;
  362. hr = S_OK;
  363. }
  364. else
  365. {
  366. _DisconnectSocket(*ppioc, FALSE);
  367. SAFERELEASE((*ppioc));
  368. hr = E_FAIL;
  369. }
  370. }
  371. break;
  372. default :
  373. {
  374. DEBUG_TRACE(W3SOBJ, ("unhandled error - %s", MapErrorToString(error)));
  375. }
  376. break;
  377. }
  378. }
  379. DEBUG_LEAVE(hr);
  380. return hr;
  381. }
  382. HRESULT
  383. __stdcall
  384. CW3Spoof::GetSession(LPWSTR clientid, PSESSIONOBJ* ppso)
  385. {
  386. HRESULT hr = S_OK;
  387. hr = m_sessionmap->Get(clientid, (void**) ppso);
  388. return hr;
  389. }
  390. HRESULT
  391. __stdcall
  392. CW3Spoof::Register(SOCKET s)
  393. {
  394. DEBUG_ENTER((
  395. DBG_W3SOBJ,
  396. rt_hresult,
  397. "CW3Spoof::Register",
  398. "this=%#x; s=%#x",
  399. this,
  400. s
  401. ));
  402. HRESULT hr = S_OK;
  403. HANDLE ret = NULL;
  404. ret = CreateIoCompletionPort(
  405. (HANDLE) s, m_hIOCP,
  406. CK_NORMAL, m_dwMaxActiveThreads
  407. );
  408. if( !ret )
  409. {
  410. DEBUG_TRACE(W3SOBJ, ("failed to associate socket!"));
  411. hr = E_FAIL;
  412. }
  413. DEBUG_LEAVE(hr);
  414. return hr;
  415. }
  416. DWORD
  417. WINAPI
  418. ThreadFunc(LPVOID lpv)
  419. {
  420. DEBUG_ENTER((
  421. DBG_WORKER,
  422. rt_hresult,
  423. "worker",
  424. "lpv=%#x",
  425. lpv
  426. ));
  427. HRESULT hr = S_OK;
  428. BOOL bQuit = FALSE;
  429. PIOCTX pioc = NULL;
  430. IThreadPool* ptp = (IThreadPool*) lpv;
  431. PSESSIONOBJ pso = NULL;
  432. while( !bQuit )
  433. {
  434. if( SUCCEEDED(ptp->GetStatus(&pioc, &bQuit)) )
  435. {
  436. if( (pso = pioc->session) || SUCCEEDED(ptp->GetSession(pioc->clientid, &pso)) )
  437. {
  438. pso->Run(pioc);
  439. }
  440. SAFERELEASE(pioc);
  441. }
  442. }
  443. DEBUG_LEAVE(hr);
  444. return hr;
  445. }