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.

569 lines
18 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. emaccept.cpp
  5. Abstract:
  6. Contains all the event manager routines which
  7. manage the overlapped accept operations.
  8. Environment:
  9. User Mode - Win32
  10. History:
  11. 1. created
  12. Ajay Chitturi (ajaych) 12-Jun-1998
  13. --*/
  14. ///////////////////////////////////////////////////////////////////////////////
  15. // //
  16. // Include files //
  17. // //
  18. ///////////////////////////////////////////////////////////////////////////////
  19. #include "stdafx.h"
  20. ///////////////////////////////////////////////////////////////////////////////
  21. // //
  22. // Constants //
  23. // //
  24. ///////////////////////////////////////////////////////////////////////////////
  25. ///////////////////////////////////////////////////////////////////////////////
  26. // //
  27. // Global Variables //
  28. // //
  29. ///////////////////////////////////////////////////////////////////////////////
  30. ///////////////////////////////////////////////////////////////////////////////
  31. // //
  32. // Externally defined identifiers //
  33. // //
  34. ///////////////////////////////////////////////////////////////////////////////
  35. ///////////////////////////////////////////////////////////////////////////////
  36. // //
  37. // Overlapped accept functions //
  38. // //
  39. ///////////////////////////////////////////////////////////////////////////////
  40. HRESULT
  41. EventMgrCreateAcceptContext(
  42. IN OVERLAPPED_PROCESSOR *pOvProcessor,
  43. IN OUT struct sockaddr_in *pBindAddress,
  44. OUT PAcceptContext *ppAcceptCtxt
  45. )
  46. /*++
  47. Routine Description:
  48. This function creates a socket, binds it to bindAddress and
  49. issues a listen. It creates the Accept I/O Context and returns
  50. it to the caller.
  51. Arguments:
  52. pOvProcessor - pointer to the overlapped processor object.
  53. Once the accept completes the callback of this object is
  54. called.
  55. pBindAddress - pointer to the address to listen on.
  56. ppAcceptCtxt - A new Accept I/O context is allocated initialized
  57. and returned through this OUT parameter.
  58. Return Values:
  59. Returns S_OK on success, E_OUTOFMEMORY if the memory allocator fails
  60. or E_FAIL if any of the Winsock functions fail.
  61. --*/
  62. {
  63. SOCKET listenSock;
  64. int Error;
  65. HRESULT Result;
  66. BOOL KeepaliveOption;
  67. PAcceptContext pAcceptCtxt;
  68. *ppAcceptCtxt = NULL;
  69. // Create an overlapped socket
  70. listenSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
  71. NULL, 0,
  72. WSA_FLAG_OVERLAPPED);
  73. if (listenSock == INVALID_SOCKET)
  74. {
  75. Error = WSAGetLastError ();
  76. DebugF(_T("H323: 0x%x error creating listener socket error: %d pOvProcessor: %p.\n"),
  77. &pOvProcessor -> GetCallBridge (),
  78. Error, pOvProcessor);
  79. return HRESULT_FROM_WIN32 (Error);
  80. }
  81. //
  82. // Set RCV and SND buffers to zero
  83. // Yes, it is ugly and bad practice but this is a QFE
  84. // for details look up bug# WinSE 31054, 691666 (read both 35928 and 33546).
  85. //
  86. ULONG Option = 0;
  87. setsockopt( listenSock, SOL_SOCKET, SO_SNDBUF,
  88. (PCHAR)&Option, sizeof(Option) );
  89. Option = 0;
  90. setsockopt( listenSock, SOL_SOCKET, SO_SNDBUF,
  91. (PCHAR)&Option, sizeof(Option) );
  92. // Bind the socket to the listen address
  93. if (bind(listenSock,
  94. (struct sockaddr *)pBindAddress,
  95. sizeof(struct sockaddr_in)) == SOCKET_ERROR)
  96. {
  97. Error = WSAGetLastError ();
  98. DebugF (_T("H323: 0x%x bind() failed error: %d.\n"),
  99. &pOvProcessor -> GetCallBridge (),
  100. Error);
  101. closesocket(listenSock);
  102. listenSock = INVALID_SOCKET;
  103. return HRESULT_FROM_WIN32 (Error);
  104. }
  105. // Set keepalive on the socket
  106. KeepaliveOption = TRUE;
  107. if (SOCKET_ERROR == setsockopt(listenSock, SOL_SOCKET,
  108. SO_KEEPALIVE, (PCHAR) &KeepaliveOption, sizeof (KeepaliveOption)))
  109. {
  110. Error = WSAGetLastError ();
  111. DebugF (_T("H323: 0x%x failed to set keepalive on listen socket. Error %d.\n"),
  112. &pOvProcessor -> GetCallBridge (),
  113. Error);
  114. closesocket(listenSock);
  115. listenSock = INVALID_SOCKET;
  116. return HRESULT_FROM_WIN32 (Error);
  117. }
  118. // Bind the socket handle to the I/O completion port
  119. if (EventMgrBindIoHandle(listenSock) != S_OK)
  120. {
  121. DebugF (_T("H323: 0x%x binding socket:%d to IOCP failed.\n"),
  122. &pOvProcessor -> GetCallBridge (),
  123. listenSock);
  124. closesocket(listenSock);
  125. listenSock = INVALID_SOCKET;
  126. return E_FAIL;
  127. }
  128. if (listen(listenSock, MAX_LISTEN_BACKLOG) == SOCKET_ERROR)
  129. {
  130. Error = WSAGetLastError ();
  131. DebugF (_T("H323: 0x%x listen() failed: 0x%x pOvProcessor; %p.\n"),
  132. &pOvProcessor -> GetCallBridge (),
  133. Error, pOvProcessor);
  134. closesocket(listenSock);
  135. listenSock = INVALID_SOCKET;
  136. return HRESULT_FROM_WIN32 (Error);
  137. }
  138. // Allocate memory from a private heap for accept contexts
  139. pAcceptCtxt = (PAcceptContext) HeapAlloc (GetProcessHeap (),
  140. 0, // No Flags
  141. sizeof(AcceptContext));
  142. if (!pAcceptCtxt)
  143. {
  144. DebugF (_T("H323: 0x%x could not allocate Accept context.\n"),
  145. &pOvProcessor -> GetCallBridge ());
  146. closesocket(listenSock);
  147. listenSock = INVALID_SOCKET;
  148. return E_OUTOFMEMORY;
  149. }
  150. memset(pAcceptCtxt, 0, sizeof(AcceptContext));
  151. pAcceptCtxt->ioCtxt.reqType = EMGR_OV_IO_REQ_ACCEPT;
  152. pAcceptCtxt->ioCtxt.pOvProcessor = pOvProcessor;
  153. pAcceptCtxt->listenSock = listenSock;
  154. pAcceptCtxt->acceptSock = INVALID_SOCKET;
  155. *ppAcceptCtxt = pAcceptCtxt;
  156. return S_OK;
  157. } // EventMgrCreateAcceptContext
  158. void
  159. EventMgrFreeAcceptContext (
  160. PAcceptContext pAcceptCtxt
  161. )
  162. /*++
  163. Routine Description:
  164. This function frees the pAcceptCtxt.
  165. OvProcessor is owned by the Call Bridge Machine and
  166. so we do not free it.
  167. Arguments:
  168. pAcceptCtxt - pointer to the AcceptCtxt to be freed.
  169. Return Values:
  170. This function has not return value.
  171. --*/
  172. {
  173. if (pAcceptCtxt->acceptSock != INVALID_SOCKET)
  174. {
  175. closesocket(pAcceptCtxt->acceptSock);
  176. pAcceptCtxt -> acceptSock = INVALID_SOCKET;
  177. }
  178. HeapFree (GetProcessHeap (),
  179. 0, // no flags
  180. pAcceptCtxt);
  181. } // EventMgrFreeAcceptContext
  182. HRESULT
  183. EventMgrIssueAcceptHelperFn(
  184. PAcceptContext pAcceptCtxt
  185. )
  186. /*++
  187. Routine Description:
  188. This function issues an Asynchronous overlapped accept using
  189. AcceptEx(). The accept socket is created and stored in the
  190. Accept context before making the call to AcceptEx().
  191. In case of an error, the caller needs to free pAcceptCtxt.
  192. Arguments:
  193. pAcceptCtxt - pointer to the Accept I/O context.
  194. Return Values:
  195. This function returns S_OK in case of success or E_FAIL
  196. in case of an error.
  197. CODEWORK: Need to convert Winsock errors to HRESULT and
  198. return them instead.
  199. --*/
  200. {
  201. SOCKET acceptSock;
  202. DWORD lastError, bytesRead;
  203. HRESULT Result;
  204. BOOL KeepaliveOption;
  205. _ASSERTE(pAcceptCtxt);
  206. // create an overlapped socket
  207. acceptSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
  208. NULL, 0,
  209. WSA_FLAG_OVERLAPPED);
  210. if (acceptSock == INVALID_SOCKET)
  211. {
  212. DebugF (_T("H323: 0x%x error creating accept socket: %d.\n"),
  213. &pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
  214. WSAGetLastError());
  215. return E_FAIL;
  216. }
  217. //
  218. // Set RCV and SND buffers to zero
  219. // Yes, it is ugly and bad practice but this is a QFE
  220. // for details look up bug# WinSE 31054, regular 691666 (read both 35928 and 33546).
  221. //
  222. ULONG Option = 0;
  223. setsockopt( acceptSock, SOL_SOCKET, SO_SNDBUF,
  224. (PCHAR)&Option, sizeof(Option) );
  225. Option = 0;
  226. setsockopt( acceptSock, SOL_SOCKET, SO_SNDBUF,
  227. (PCHAR)&Option, sizeof(Option) );
  228. pAcceptCtxt->acceptSock = acceptSock;
  229. // Bind the socket handle to the I/O completion port
  230. if (EventMgrBindIoHandle(acceptSock) != S_OK)
  231. {
  232. DebugF (_T("H323: 0x%x binding socket:%d to IOCP failed.\n"),
  233. &pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
  234. acceptSock);
  235. return E_FAIL;
  236. }
  237. memset(&pAcceptCtxt->ioCtxt.ov, 0, sizeof(OVERLAPPED));
  238. // Set keepalive on the socket
  239. KeepaliveOption = TRUE;
  240. if (SOCKET_ERROR == setsockopt (acceptSock, SOL_SOCKET,
  241. SO_KEEPALIVE, (PCHAR) &KeepaliveOption, sizeof (KeepaliveOption)))
  242. {
  243. DebugF (_T("H323: 0x%x failed to set keepalive on accept socket. Error %d.\n"),
  244. &pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
  245. WSAGetLastError());
  246. return E_FAIL;
  247. }
  248. pAcceptCtxt->ioCtxt.pOvProcessor->GetCallBridge().AddRef();
  249. // Issue overlapped accept
  250. if (!AcceptEx(pAcceptCtxt->listenSock,
  251. acceptSock,
  252. pAcceptCtxt->addrBuf,
  253. 0, // Read nothing from socket
  254. sizeof(struct sockaddr_in) + 16,
  255. sizeof(struct sockaddr_in) + 16,
  256. &bytesRead,
  257. &pAcceptCtxt->ioCtxt.ov))
  258. {
  259. lastError = WSAGetLastError();
  260. if (lastError != ERROR_IO_PENDING)
  261. {
  262. pAcceptCtxt->ioCtxt.pOvProcessor->GetCallBridge().Release();
  263. // This means the overlapped AcceptEx() failed
  264. DebugF(_T("H323: 0x%x AcceptEx() failed error: %d listenSock: %d acceptSock: %d.\n"),
  265. &pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
  266. lastError, pAcceptCtxt->listenSock,
  267. pAcceptCtxt->acceptSock);
  268. return E_FAIL;
  269. }
  270. }
  271. return S_OK;
  272. }
  273. HRESULT
  274. EventMgrIssueAccept(
  275. IN DWORD bindIPAddress,
  276. IN OVERLAPPED_PROCESSOR &rOvProcessor,
  277. OUT WORD& rBindPort,
  278. OUT SOCKET& rListenSock
  279. )
  280. /*++
  281. Routine Description:
  282. This function is exported to the Call Bridge machine for
  283. making an asynchronous accept request for H.245 connections.
  284. Once the accept is completed, the accept callback function on
  285. rOvProcessor is called.
  286. This function calls bind() with on IP address "bindIPAddress"
  287. and port 0. Winsock allocates a free port which is got using
  288. getsockname(). This port is returned using the OUT param
  289. rBindPort.
  290. This function also returns the listen socket using the OUT
  291. param rListenSock. The Call Bridge machine can use this
  292. socket to cancel the asynchronous Accept() request.
  293. Once this function succeeds only the Call bridge frees the
  294. listen socket.
  295. Arguments:
  296. bindIPAddress - This is the IP address to listen on.
  297. This is in host byte order.
  298. rOvProcessor - A reference to the Overlapped processor. This
  299. is stored in the Accept I/O context. Once the accept
  300. completes the AcceptCallback() on this object is called.
  301. rBindPort - The port on which the listen is issued is returned
  302. through this OUT param. This function calls bind() with on
  303. IP address "bindIPAddress" and port 0. Winsock allocates a
  304. free port which is got using getsockname(). This port is
  305. returned using the OUT param rBindPort.
  306. The port returned is in host byte order.
  307. rListenSock - The listening socket is returned through this OUT
  308. param. The Call Bridge machine can use this socket to cancel
  309. the asynchronous Accept() request. Once this function succeeds
  310. only the Call bridge frees the listen socket.
  311. Return Values:
  312. This function returns S_OK in case of success or E_FAIL
  313. in case of a failure.
  314. --*/
  315. {
  316. PAcceptContext pAcceptCtxt;
  317. struct sockaddr_in bindAddress;
  318. HRESULT hRes;
  319. int bindAddressLen = sizeof(struct sockaddr_in);
  320. memset(&bindAddress, 0, sizeof(bindAddress));
  321. bindAddress.sin_family = AF_INET;
  322. bindAddress.sin_addr.s_addr = htonl(bindIPAddress);
  323. bindAddress.sin_port = htons(0);
  324. hRes = EventMgrCreateAcceptContext(&rOvProcessor,
  325. &bindAddress, &pAcceptCtxt);
  326. if (hRes != S_OK)
  327. return hRes;
  328. if (!pAcceptCtxt)
  329. return E_FAIL;
  330. // Get the port
  331. if (getsockname(pAcceptCtxt->listenSock,
  332. (struct sockaddr *)&bindAddress,
  333. &bindAddressLen))
  334. {
  335. closesocket(pAcceptCtxt->listenSock);
  336. pAcceptCtxt->listenSock = INVALID_SOCKET;
  337. EventMgrFreeAcceptContext(pAcceptCtxt);
  338. return E_FAIL;
  339. }
  340. rBindPort = ntohs(bindAddress.sin_port);
  341. hRes = EventMgrIssueAcceptHelperFn(pAcceptCtxt);
  342. if (hRes != S_OK)
  343. {
  344. closesocket(pAcceptCtxt->listenSock);
  345. pAcceptCtxt->listenSock = INVALID_SOCKET;
  346. EventMgrFreeAcceptContext(pAcceptCtxt);
  347. return hRes;
  348. }
  349. rListenSock = pAcceptCtxt->listenSock;
  350. return S_OK;
  351. } // EventMgrIssueAccept
  352. void
  353. HandleAcceptCompletion(
  354. PAcceptContext pAcceptCtxt,
  355. DWORD status
  356. )
  357. /*++
  358. Routine Description:
  359. This function is called by the event loop when an accept I/O completes.
  360. The Call Bridge Machine's accept callback function is called for
  361. H.245 connections.
  362. This function always frees pAcceptCtxt if another accept is not issued.
  363. Arguments:
  364. pAcceptCtxt - The Accept I/O context. This contains the overlapped
  365. context on which the accept callback is called in the case of
  366. H.245 connections and the listen and accept sockets.
  367. status - This conveys the WIN32 error status.
  368. Return Values:
  369. This function does not return any error code. In case of an error,
  370. the call bridge machine is notified about the error in the callback.
  371. --*/
  372. {
  373. int locallen = sizeof(struct sockaddr_in);
  374. int remotelen = sizeof(struct sockaddr_in);
  375. struct sockaddr_in *pLocalAddr;
  376. struct sockaddr_in *pRemoteAddr;
  377. // If H.245 call the accept callback on overlapped processor
  378. // and free the accept I/O context.
  379. // The listening socket is closed by the Call bridge machine.
  380. if (status == NO_ERROR)
  381. {
  382. if (setsockopt(pAcceptCtxt->acceptSock,
  383. SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
  384. (char*)(&pAcceptCtxt->listenSock),
  385. sizeof(SOCKET)) == SOCKET_ERROR)
  386. {
  387. DebugF (_T("H323: 0x%x setsockopt SO_UPDATE_ACCEPT_CONTEXT failed acceptSock: %d listenSock: %d err: %d.\n"),
  388. &pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
  389. pAcceptCtxt->acceptSock,
  390. pAcceptCtxt->listenSock,
  391. WSAGetLastError());
  392. // make callback conveying the error
  393. SOCKADDR_IN LocalAddress;
  394. SOCKADDR_IN RemoteAddress;
  395. ZeroMemory (&LocalAddress, sizeof (SOCKADDR_IN));
  396. ZeroMemory (&RemoteAddress, sizeof (SOCKADDR_IN));
  397. pAcceptCtxt->ioCtxt.pOvProcessor->AcceptCallback(
  398. WSAGetLastError(),
  399. INVALID_SOCKET,
  400. &LocalAddress,
  401. &RemoteAddress);
  402. } else {
  403. // This function does not return anything
  404. GetAcceptExSockaddrs(pAcceptCtxt->addrBuf, 0,
  405. sizeof(struct sockaddr_in) + 16,
  406. sizeof(struct sockaddr_in) + 16,
  407. (struct sockaddr**)&pLocalAddr,
  408. &locallen,
  409. (struct sockaddr**)&pRemoteAddr,
  410. &remotelen);
  411. // make the callback
  412. pAcceptCtxt->ioCtxt.pOvProcessor->AcceptCallback(
  413. S_OK,
  414. pAcceptCtxt->acceptSock,
  415. pLocalAddr,
  416. pRemoteAddr);
  417. // ownership of pAcceptCtxt -> acceptSock has been transferred,
  418. // so we need to make sure the acceptSock won't be used
  419. pAcceptCtxt -> acceptSock = INVALID_SOCKET;
  420. }
  421. } // if (status == NO_ERROR)
  422. else
  423. {
  424. DebugF (_T("H245: 0x%x error %d on accept callback.\n"),
  425. &pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
  426. status);
  427. SOCKADDR_IN LocalAddress;
  428. SOCKADDR_IN RemoteAddress;
  429. ZeroMemory (&LocalAddress, sizeof (SOCKADDR_IN));
  430. ZeroMemory (&RemoteAddress, sizeof (SOCKADDR_IN));
  431. // make callback conveying the error
  432. pAcceptCtxt->ioCtxt.pOvProcessor->AcceptCallback(
  433. HRESULT_FROM_WIN32_ERROR_CODE(status),
  434. INVALID_SOCKET,
  435. &LocalAddress,
  436. &RemoteAddress);
  437. }
  438. EventMgrFreeAcceptContext (pAcceptCtxt);
  439. } // HandleAcceptCompletion(