Source code of Windows XP (NT5)
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.

543 lines
17 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. // Bind the socket to the listen address
  82. if (bind(listenSock,
  83. (struct sockaddr *)pBindAddress,
  84. sizeof(struct sockaddr_in)) == SOCKET_ERROR)
  85. {
  86. Error = WSAGetLastError ();
  87. DebugF (_T("H323: 0x%x bind() failed error: %d.\n"),
  88. &pOvProcessor -> GetCallBridge (),
  89. Error);
  90. closesocket(listenSock);
  91. listenSock = INVALID_SOCKET;
  92. return HRESULT_FROM_WIN32 (Error);
  93. }
  94. // Set keepalive on the socket
  95. KeepaliveOption = TRUE;
  96. if (SOCKET_ERROR == setsockopt(listenSock, SOL_SOCKET,
  97. SO_KEEPALIVE, (PCHAR) &KeepaliveOption, sizeof (KeepaliveOption)))
  98. {
  99. Error = WSAGetLastError ();
  100. DebugF (_T("H323: 0x%x failed to set keepalive on listen socket. Error %d.\n"),
  101. &pOvProcessor -> GetCallBridge (),
  102. Error);
  103. closesocket(listenSock);
  104. listenSock = INVALID_SOCKET;
  105. return HRESULT_FROM_WIN32 (Error);
  106. }
  107. // Bind the socket handle to the I/O completion port
  108. if (EventMgrBindIoHandle(listenSock) != S_OK)
  109. {
  110. DebugF (_T("H323: 0x%x binding socket:%d to IOCP failed.\n"),
  111. &pOvProcessor -> GetCallBridge (),
  112. listenSock);
  113. closesocket(listenSock);
  114. listenSock = INVALID_SOCKET;
  115. return E_FAIL;
  116. }
  117. if (listen(listenSock, MAX_LISTEN_BACKLOG) == SOCKET_ERROR)
  118. {
  119. Error = WSAGetLastError ();
  120. DebugF (_T("H323: 0x%x listen() failed: 0x%x pOvProcessor; %p.\n"),
  121. &pOvProcessor -> GetCallBridge (),
  122. Error, pOvProcessor);
  123. closesocket(listenSock);
  124. listenSock = INVALID_SOCKET;
  125. return HRESULT_FROM_WIN32 (Error);
  126. }
  127. // Allocate memory from a private heap for accept contexts
  128. pAcceptCtxt = (PAcceptContext) HeapAlloc (GetProcessHeap (),
  129. 0, // No Flags
  130. sizeof(AcceptContext));
  131. if (!pAcceptCtxt)
  132. {
  133. DebugF (_T("H323: 0x%x could not allocate Accept context.\n"),
  134. &pOvProcessor -> GetCallBridge ());
  135. closesocket(listenSock);
  136. listenSock = INVALID_SOCKET;
  137. return E_OUTOFMEMORY;
  138. }
  139. memset(pAcceptCtxt, 0, sizeof(AcceptContext));
  140. pAcceptCtxt->ioCtxt.reqType = EMGR_OV_IO_REQ_ACCEPT;
  141. pAcceptCtxt->ioCtxt.pOvProcessor = pOvProcessor;
  142. pAcceptCtxt->listenSock = listenSock;
  143. pAcceptCtxt->acceptSock = INVALID_SOCKET;
  144. *ppAcceptCtxt = pAcceptCtxt;
  145. return S_OK;
  146. } // EventMgrCreateAcceptContext
  147. void
  148. EventMgrFreeAcceptContext (
  149. PAcceptContext pAcceptCtxt
  150. )
  151. /*++
  152. Routine Description:
  153. This function frees the pAcceptCtxt.
  154. OvProcessor is owned by the Call Bridge Machine and
  155. so we do not free it.
  156. Arguments:
  157. pAcceptCtxt - pointer to the AcceptCtxt to be freed.
  158. Return Values:
  159. This function has not return value.
  160. --*/
  161. {
  162. if (pAcceptCtxt->acceptSock != INVALID_SOCKET)
  163. {
  164. closesocket(pAcceptCtxt->acceptSock);
  165. pAcceptCtxt -> acceptSock = INVALID_SOCKET;
  166. }
  167. HeapFree (GetProcessHeap (),
  168. 0, // no flags
  169. pAcceptCtxt);
  170. } // EventMgrFreeAcceptContext
  171. HRESULT
  172. EventMgrIssueAcceptHelperFn(
  173. PAcceptContext pAcceptCtxt
  174. )
  175. /*++
  176. Routine Description:
  177. This function issues an Asynchronous overlapped accept using
  178. AcceptEx(). The accept socket is created and stored in the
  179. Accept context before making the call to AcceptEx().
  180. In case of an error, the caller needs to free pAcceptCtxt.
  181. Arguments:
  182. pAcceptCtxt - pointer to the Accept I/O context.
  183. Return Values:
  184. This function returns S_OK in case of success or E_FAIL
  185. in case of an error.
  186. CODEWORK: Need to convert Winsock errors to HRESULT and
  187. return them instead.
  188. --*/
  189. {
  190. SOCKET acceptSock;
  191. DWORD lastError, bytesRead;
  192. HRESULT Result;
  193. BOOL KeepaliveOption;
  194. _ASSERTE(pAcceptCtxt);
  195. // create an overlapped socket
  196. acceptSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
  197. NULL, 0,
  198. WSA_FLAG_OVERLAPPED);
  199. if (acceptSock == INVALID_SOCKET)
  200. {
  201. DebugF (_T("H323: 0x%x error creating accept socket: %d.\n"),
  202. &pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
  203. WSAGetLastError());
  204. return E_FAIL;
  205. }
  206. pAcceptCtxt->acceptSock = acceptSock;
  207. // Bind the socket handle to the I/O completion port
  208. if (EventMgrBindIoHandle(acceptSock) != S_OK)
  209. {
  210. DebugF (_T("H323: 0x%x binding socket:%d to IOCP failed.\n"),
  211. &pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
  212. acceptSock);
  213. return E_FAIL;
  214. }
  215. memset(&pAcceptCtxt->ioCtxt.ov, 0, sizeof(OVERLAPPED));
  216. // Set keepalive on the socket
  217. KeepaliveOption = TRUE;
  218. if (SOCKET_ERROR == setsockopt (acceptSock, SOL_SOCKET,
  219. SO_KEEPALIVE, (PCHAR) &KeepaliveOption, sizeof (KeepaliveOption)))
  220. {
  221. DebugF (_T("H323: 0x%x failed to set keepalive on accept socket. Error %d.\n"),
  222. &pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
  223. WSAGetLastError());
  224. return E_FAIL;
  225. }
  226. pAcceptCtxt->ioCtxt.pOvProcessor->GetCallBridge().AddRef();
  227. // Issue overlapped accept
  228. if (!AcceptEx(pAcceptCtxt->listenSock,
  229. acceptSock,
  230. pAcceptCtxt->addrBuf,
  231. 0, // Read nothing from socket
  232. sizeof(struct sockaddr_in) + 16,
  233. sizeof(struct sockaddr_in) + 16,
  234. &bytesRead,
  235. &pAcceptCtxt->ioCtxt.ov))
  236. {
  237. lastError = WSAGetLastError();
  238. if (lastError != ERROR_IO_PENDING)
  239. {
  240. pAcceptCtxt->ioCtxt.pOvProcessor->GetCallBridge().Release();
  241. // This means the overlapped AcceptEx() failed
  242. DebugF(_T("H323: 0x%x AcceptEx() failed error: %d listenSock: %d acceptSock: %d.\n"),
  243. &pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
  244. lastError, pAcceptCtxt->listenSock,
  245. pAcceptCtxt->acceptSock);
  246. return E_FAIL;
  247. }
  248. }
  249. return S_OK;
  250. }
  251. HRESULT
  252. EventMgrIssueAccept(
  253. IN DWORD bindIPAddress,
  254. IN OVERLAPPED_PROCESSOR &rOvProcessor,
  255. OUT WORD& rBindPort,
  256. OUT SOCKET& rListenSock
  257. )
  258. /*++
  259. Routine Description:
  260. This function is exported to the Call Bridge machine for
  261. making an asynchronous accept request for H.245 connections.
  262. Once the accept is completed, the accept callback function on
  263. rOvProcessor is called.
  264. This function calls bind() with on IP address "bindIPAddress"
  265. and port 0. Winsock allocates a free port which is got using
  266. getsockname(). This port is returned using the OUT param
  267. rBindPort.
  268. This function also returns the listen socket using the OUT
  269. param rListenSock. The Call Bridge machine can use this
  270. socket to cancel the asynchronous Accept() request.
  271. Once this function succeeds only the Call bridge frees the
  272. listen socket.
  273. Arguments:
  274. bindIPAddress - This is the IP address to listen on.
  275. This is in host byte order.
  276. rOvProcessor - A reference to the Overlapped processor. This
  277. is stored in the Accept I/O context. Once the accept
  278. completes the AcceptCallback() on this object is called.
  279. rBindPort - The port on which the listen is issued is returned
  280. through this OUT param. This function calls bind() with on
  281. IP address "bindIPAddress" and port 0. Winsock allocates a
  282. free port which is got using getsockname(). This port is
  283. returned using the OUT param rBindPort.
  284. The port returned is in host byte order.
  285. rListenSock - The listening socket is returned through this OUT
  286. param. The Call Bridge machine can use this socket to cancel
  287. the asynchronous Accept() request. Once this function succeeds
  288. only the Call bridge frees the listen socket.
  289. Return Values:
  290. This function returns S_OK in case of success or E_FAIL
  291. in case of a failure.
  292. --*/
  293. {
  294. PAcceptContext pAcceptCtxt;
  295. struct sockaddr_in bindAddress;
  296. HRESULT hRes;
  297. int bindAddressLen = sizeof(struct sockaddr_in);
  298. memset(&bindAddress, 0, sizeof(bindAddress));
  299. bindAddress.sin_family = AF_INET;
  300. bindAddress.sin_addr.s_addr = htonl(bindIPAddress);
  301. bindAddress.sin_port = htons(0);
  302. hRes = EventMgrCreateAcceptContext(&rOvProcessor,
  303. &bindAddress, &pAcceptCtxt);
  304. if (hRes != S_OK)
  305. return hRes;
  306. if (!pAcceptCtxt)
  307. return E_FAIL;
  308. // Get the port
  309. if (getsockname(pAcceptCtxt->listenSock,
  310. (struct sockaddr *)&bindAddress,
  311. &bindAddressLen))
  312. {
  313. closesocket(pAcceptCtxt->listenSock);
  314. pAcceptCtxt->listenSock = INVALID_SOCKET;
  315. EventMgrFreeAcceptContext(pAcceptCtxt);
  316. return E_FAIL;
  317. }
  318. rBindPort = ntohs(bindAddress.sin_port);
  319. hRes = EventMgrIssueAcceptHelperFn(pAcceptCtxt);
  320. if (hRes != S_OK)
  321. {
  322. closesocket(pAcceptCtxt->listenSock);
  323. pAcceptCtxt->listenSock = INVALID_SOCKET;
  324. EventMgrFreeAcceptContext(pAcceptCtxt);
  325. return hRes;
  326. }
  327. rListenSock = pAcceptCtxt->listenSock;
  328. return S_OK;
  329. } // EventMgrIssueAccept
  330. void
  331. HandleAcceptCompletion(
  332. PAcceptContext pAcceptCtxt,
  333. DWORD status
  334. )
  335. /*++
  336. Routine Description:
  337. This function is called by the event loop when an accept I/O completes.
  338. The Call Bridge Machine's accept callback function is called for
  339. H.245 connections.
  340. This function always frees pAcceptCtxt if another accept is not issued.
  341. Arguments:
  342. pAcceptCtxt - The Accept I/O context. This contains the overlapped
  343. context on which the accept callback is called in the case of
  344. H.245 connections and the listen and accept sockets.
  345. status - This conveys the WIN32 error status.
  346. Return Values:
  347. This function does not return any error code. In case of an error,
  348. the call bridge machine is notified about the error in the callback.
  349. --*/
  350. {
  351. int locallen = sizeof(struct sockaddr_in);
  352. int remotelen = sizeof(struct sockaddr_in);
  353. struct sockaddr_in *pLocalAddr;
  354. struct sockaddr_in *pRemoteAddr;
  355. // If H.245 call the accept callback on overlapped processor
  356. // and free the accept I/O context.
  357. // The listening socket is closed by the Call bridge machine.
  358. if (status == NO_ERROR)
  359. {
  360. if (setsockopt(pAcceptCtxt->acceptSock,
  361. SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
  362. (char*)(&pAcceptCtxt->listenSock),
  363. sizeof(SOCKET)) == SOCKET_ERROR)
  364. {
  365. DebugF (_T("H323: 0x%x setsockopt SO_UPDATE_ACCEPT_CONTEXT failed acceptSock: %d listenSock: %d err: %d.\n"),
  366. &pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
  367. pAcceptCtxt->acceptSock,
  368. pAcceptCtxt->listenSock,
  369. WSAGetLastError());
  370. // make callback conveying the error
  371. SOCKADDR_IN LocalAddress;
  372. SOCKADDR_IN RemoteAddress;
  373. ZeroMemory (&LocalAddress, sizeof (SOCKADDR_IN));
  374. ZeroMemory (&RemoteAddress, sizeof (SOCKADDR_IN));
  375. pAcceptCtxt->ioCtxt.pOvProcessor->AcceptCallback(
  376. WSAGetLastError(),
  377. INVALID_SOCKET,
  378. &LocalAddress,
  379. &RemoteAddress);
  380. } else {
  381. // This function does not return anything
  382. GetAcceptExSockaddrs(pAcceptCtxt->addrBuf, 0,
  383. sizeof(struct sockaddr_in) + 16,
  384. sizeof(struct sockaddr_in) + 16,
  385. (struct sockaddr**)&pLocalAddr,
  386. &locallen,
  387. (struct sockaddr**)&pRemoteAddr,
  388. &remotelen);
  389. // make the callback
  390. pAcceptCtxt->ioCtxt.pOvProcessor->AcceptCallback(
  391. S_OK,
  392. pAcceptCtxt->acceptSock,
  393. pLocalAddr,
  394. pRemoteAddr);
  395. // ownership of pAcceptCtxt -> acceptSock has been transferred,
  396. // so we need to make sure the acceptSock won't be used
  397. pAcceptCtxt -> acceptSock = INVALID_SOCKET;
  398. }
  399. } // if (status == NO_ERROR)
  400. else
  401. {
  402. DebugF (_T("H245: 0x%x error %d on accept callback.\n"),
  403. &pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
  404. status);
  405. SOCKADDR_IN LocalAddress;
  406. SOCKADDR_IN RemoteAddress;
  407. ZeroMemory (&LocalAddress, sizeof (SOCKADDR_IN));
  408. ZeroMemory (&RemoteAddress, sizeof (SOCKADDR_IN));
  409. // make callback conveying the error
  410. pAcceptCtxt->ioCtxt.pOvProcessor->AcceptCallback(
  411. HRESULT_FROM_WIN32_ERROR_CODE(status),
  412. INVALID_SOCKET,
  413. &LocalAddress,
  414. &RemoteAddress);
  415. }
  416. EventMgrFreeAcceptContext (pAcceptCtxt);
  417. } // HandleAcceptCompletion(