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.

424 lines
10 KiB

  1. #include "stdafx.h"
  2. #include "gkwsock.h"
  3. // ASYNC_ACCEPT --------------------------------------------------------------------------
  4. ASYNC_ACCEPT::ASYNC_ACCEPT (void)
  5. {
  6. AcceptSocket = INVALID_SOCKET;
  7. ClientSocket = INVALID_SOCKET;
  8. AcceptFunc = NULL;
  9. AcceptFuncContext = NULL;
  10. ReferenceCount = 0L;
  11. StopNotifyEvent = NULL;
  12. }
  13. ASYNC_ACCEPT::~ASYNC_ACCEPT (void)
  14. {
  15. assert (AcceptSocket == INVALID_SOCKET);
  16. assert (ClientSocket == INVALID_SOCKET);
  17. assert (ReferenceCount == 0L);
  18. assert (!StopNotifyEvent);
  19. }
  20. HRESULT ASYNC_ACCEPT::StartIo (
  21. IN SOCKADDR_IN * SocketAddress,
  22. IN ASYNC_ACCEPT_FUNC ArgAcceptFunc,
  23. IN PVOID ArgAcceptContext)
  24. {
  25. HRESULT Result;
  26. assert (SocketAddress);
  27. assert (ArgAcceptFunc);
  28. Lock ();
  29. if (AcceptSocket == INVALID_SOCKET && ReferenceCount == 0L) {
  30. // this object is not currently in use
  31. // so, it's acceptable to use it
  32. assert (!AcceptFunc);
  33. assert (!AcceptFuncContext);
  34. assert (!StopNotifyEvent);
  35. // This increase in reference count is needed
  36. // to shut down the service gracefully
  37. // Reference count on ASYNC_ACCEPT objects
  38. // will never drop to zero unless StopWait is called.
  39. // StopWait will call matching Release, which will
  40. // bring the reference count to the expected value of 0.
  41. AddRef ();
  42. Result = StartIoLocked (SocketAddress);
  43. if (Result == S_OK) {
  44. assert (AcceptSocket != INVALID_SOCKET);
  45. AcceptFunc = ArgAcceptFunc;
  46. AcceptFuncContext = ArgAcceptContext;
  47. }
  48. else {
  49. Release ();
  50. }
  51. }
  52. else {
  53. Debug (_T("ASYNC_ACCEPT::StartIo: this object is already in use, must first call Stop and wait for sync counter\n"));
  54. Result = E_FAIL;
  55. }
  56. Unlock();
  57. return Result;
  58. }
  59. HRESULT ASYNC_ACCEPT::StartIoLocked (
  60. IN SOCKADDR_IN * SocketAddress)
  61. {
  62. HRESULT Result;
  63. BOOL KeepaliveOption;
  64. assert (SocketAddress);
  65. assert (AcceptSocket == INVALID_SOCKET);
  66. assert (ClientSocket == INVALID_SOCKET);
  67. assert (ReferenceCount == 1);
  68. assert (!StopNotifyEvent);
  69. StopNotifyEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
  70. if (!StopNotifyEvent) {
  71. Result = GetLastErrorAsResult ();
  72. DebugLastError (_T("ASYNC_ACCEPT::StartIoLocked: failed to create stop notify event\n"));
  73. } else {
  74. AcceptSocket = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
  75. if (AcceptSocket == INVALID_SOCKET) {
  76. Result = GetLastErrorAsResult ();
  77. DebugLastError (_T("ASYNC_ACCEPT::StartIoLocked: failed to create accept socket\n"));
  78. } else {
  79. if (bind (AcceptSocket, (SOCKADDR *) SocketAddress, sizeof (SOCKADDR_IN))) {
  80. Result = GetLastErrorAsResult ();
  81. DebugLastErrorF (_T("ASYNC_ACCEPT::StartIoLocked: failed to bind accept socket to address %08X:%04X\n"),
  82. ntohl (SocketAddress -> sin_addr.s_addr),
  83. ntohs (SocketAddress -> sin_port));
  84. } else {
  85. // Set keepalive on the socket
  86. KeepaliveOption = TRUE;
  87. if (SOCKET_ERROR == setsockopt (AcceptSocket, SOL_SOCKET,
  88. SO_KEEPALIVE, (PCHAR) &KeepaliveOption, sizeof (KeepaliveOption)))
  89. {
  90. Result = GetLastErrorAsResult ();
  91. DebugLastError (_T("ASYNC_ACCEPT: Failed to set keepalive on accept socket.\n"));
  92. } else {
  93. if (listen (AcceptSocket, 10)) {
  94. Result = GetLastErrorAsResult ();
  95. DebugLastError (_T("ASYNC_ACCEPT::StartIoLocked: failed to listen on accept socket\n"));
  96. } else {
  97. if (!BindIoCompletionCallback ((HANDLE) AcceptSocket, ASYNC_ACCEPT::IoCompletionCallback, 0)) {
  98. Result = GetLastErrorAsResult ();
  99. DebugLastError (_T("ASYNC_ACCEPT::StartIoLocked: failed to bind i/o completion callback\n"));
  100. } else {
  101. Result = IssueAccept ();
  102. if (Result == S_OK) {
  103. return Result;
  104. }
  105. }
  106. }
  107. }
  108. }
  109. closesocket (AcceptSocket);
  110. AcceptSocket = INVALID_SOCKET;
  111. }
  112. CloseHandle (StopNotifyEvent);
  113. StopNotifyEvent = NULL;
  114. }
  115. return Result;
  116. }
  117. HRESULT ASYNC_ACCEPT::GetListenSocketAddress (
  118. OUT SOCKADDR_IN * ReturnSocketAddress)
  119. {
  120. HRESULT Result;
  121. INT SocketAddressLength;
  122. Lock();
  123. if (AcceptSocket != INVALID_SOCKET) {
  124. SocketAddressLength = sizeof (SOCKADDR_IN);
  125. if (getsockname (AcceptSocket, (SOCKADDR *) ReturnSocketAddress, &SocketAddressLength) == SOCKET_ERROR) {
  126. Result = GetLastErrorAsResult();
  127. }
  128. else {
  129. Result = S_OK;
  130. }
  131. }
  132. else {
  133. Result = E_INVALIDARG;
  134. }
  135. Unlock();
  136. return Result;
  137. }
  138. HRESULT ASYNC_ACCEPT::IssueAccept (void)
  139. {
  140. HRESULT Result;
  141. BOOL KeepaliveOption;
  142. AssertLocked();
  143. assert (ClientSocket == INVALID_SOCKET);
  144. // assert (ReferenceCount == 0);
  145. ClientSocket = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
  146. if (ClientSocket == INVALID_SOCKET) {
  147. Result = GetLastErrorAsResult ();
  148. DebugLastError (_T("ASYNC_ACCEPT::IssueAccept: failed to create client socket.\n"));
  149. return Result;
  150. }
  151. ZeroMemory (&Overlapped, sizeof (OVERLAPPED));
  152. AddRef();
  153. if (!AcceptEx (AcceptSocket,
  154. ClientSocket,
  155. ClientInfoBuffer,
  156. 0,
  157. sizeof (SOCKADDR_IN) + 0x10,
  158. sizeof (SOCKADDR_IN) + 0x10,
  159. &ClientInfoBufferLength,
  160. &Overlapped)) {
  161. if (WSAGetLastError() != WSA_IO_PENDING) {
  162. // an error occurred
  163. Release ();
  164. Result = GetLastErrorAsResult ();
  165. DebugLastError (_T("ASYNC_ACCEPT::IssueAccept: failed to issue accept.\n"));
  166. return Result;
  167. }
  168. // Set keepalive on the socket
  169. KeepaliveOption = TRUE;
  170. if (SOCKET_ERROR == setsockopt (ClientSocket, SOL_SOCKET,
  171. SO_KEEPALIVE, (PCHAR) &KeepaliveOption, sizeof (KeepaliveOption)))
  172. {
  173. Release ();
  174. Result = GetLastErrorAsResult ();
  175. DebugLastError (_T("ASYNC_ACCEPT: IssueAccept: Failed to set keepalive on client socket.\n"));
  176. return Result;
  177. }
  178. }
  179. return S_OK;
  180. }
  181. // static
  182. void ASYNC_ACCEPT::IoCompletionCallback (DWORD Status, DWORD BytesTransferred, LPOVERLAPPED Overlapped)
  183. {
  184. ASYNC_ACCEPT * AsyncAccept;
  185. AsyncAccept = CONTAINING_RECORD (Overlapped, ASYNC_ACCEPT, Overlapped);
  186. AsyncAccept -> IoComplete (Status, BytesTransferred);
  187. AsyncAccept -> Release ();
  188. }
  189. void ASYNC_ACCEPT::IoComplete (DWORD Status, DWORD BytesTransferred)
  190. {
  191. ASYNC_ACCEPT_FUNC LocalAcceptFunc;
  192. PVOID LocalAcceptFuncContext;
  193. SOCKADDR_IN LocalAddressCopy;
  194. SOCKADDR_IN RemoteAddressCopy;
  195. SOCKET LocalClientSocket;
  196. SOCKADDR * LocalAddress;
  197. INT LocalAddressLength;
  198. SOCKADDR * RemoteAddress;
  199. INT RemoteAddressLength;
  200. INT Result;
  201. Lock();
  202. assert (ClientSocket != INVALID_SOCKET);
  203. assert (ReferenceCount > 0);
  204. if (AcceptSocket == INVALID_SOCKET) {
  205. // Stop has been called
  206. // just immediately disconnect the client
  207. // we'll deal with object lifetime below
  208. closesocket (ClientSocket);
  209. ClientSocket = INVALID_SOCKET;
  210. }
  211. else {
  212. // the context is in the normal state
  213. // continue processing
  214. if (Status == ERROR_SUCCESS) {
  215. // a client has successfully connected
  216. GetAcceptExSockaddrs (
  217. ClientInfoBuffer,
  218. 0, // no initial recv
  219. sizeof (SOCKADDR_IN) + 0x10,
  220. sizeof (SOCKADDR_IN) + 0x10,
  221. &LocalAddress,
  222. &LocalAddressLength,
  223. &RemoteAddress,
  224. &RemoteAddressLength);
  225. // copy information out of the context
  226. // so that it will be valid after we issue a new accept and unlock
  227. LocalAddressCopy = *(SOCKADDR_IN *) LocalAddress;
  228. RemoteAddressCopy = *(SOCKADDR_IN *) RemoteAddress;
  229. LocalClientSocket = ClientSocket;
  230. LocalAcceptFunc = AcceptFunc;
  231. LocalAcceptFuncContext = AcceptFuncContext;
  232. ClientSocket = INVALID_SOCKET;
  233. // update the accept context
  234. Result = setsockopt (ClientSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
  235. reinterpret_cast <char *> (&AcceptSocket), sizeof (SOCKET));
  236. // issue a new accept
  237. IssueAccept();
  238. Unlock();
  239. (*LocalAcceptFunc) (LocalAcceptFuncContext, LocalClientSocket, &LocalAddressCopy, &RemoteAddressCopy);
  240. Lock();
  241. }
  242. else {
  243. // some error has occurred
  244. // this is usually (but not always) fatal
  245. assert (ClientSocket != INVALID_SOCKET);
  246. closesocket (ClientSocket);
  247. ClientSocket = INVALID_SOCKET;
  248. switch (Status) {
  249. case STATUS_CANCELLED:
  250. Debug (_T("ASYNC_ACCEPT::IoComplete: accept failed, STATUS_CANCELED, original thread probably exited, resubmitting request...\n"));
  251. break;
  252. default:
  253. DebugError (Status, _T("AsyncAccept: async accept FAILED, sleeping 2000ms and retrying...\n"));
  254. Sleep (2000);
  255. break;
  256. }
  257. IssueAccept();
  258. }
  259. }
  260. Unlock();
  261. }
  262. void ASYNC_ACCEPT::StopWait (void)
  263. {
  264. DWORD Status;
  265. Lock();
  266. if (AcceptSocket != INVALID_SOCKET) {
  267. // closing the socket cancels all pending i/o
  268. // we do NOT close the ClientSocket
  269. // only the i/o completion callback path may do that
  270. closesocket (AcceptSocket);
  271. AcceptSocket = INVALID_SOCKET;
  272. AcceptFunc = NULL;
  273. AcceptFuncContext = NULL;
  274. if (ClientSocket != INVALID_SOCKET) {
  275. // an accept is still pending. it may complete successfully,
  276. // or it may complete with STATUS_CANCELED (since we just closed AcceptSocket)
  277. // in either case, we must wait for the i/o complete callback to run.
  278. // AcceptSocket = INVALID_SOCKET is an indicator to the completion callback
  279. // that it should abort / return immediately.
  280. assert (StopNotifyEvent);
  281. Unlock ();
  282. // This is the counterpart to the AddRef called in
  283. // StartIoLocked (see comment there)
  284. Release ();
  285. DebugF (_T("ASYNC_ACCEPT::StopWait: waiting for i/o completion thread...\n"));
  286. Status = WaitForSingleObject (StopNotifyEvent, INFINITE);
  287. assert (Status == WAIT_OBJECT_0);
  288. Lock ();
  289. }
  290. }
  291. else {
  292. assert (!AcceptFunc);
  293. assert (!AcceptFuncContext);
  294. }
  295. if (StopNotifyEvent) {
  296. CloseHandle (StopNotifyEvent);
  297. StopNotifyEvent = NULL;
  298. }
  299. Unlock();
  300. }
  301. void ASYNC_ACCEPT::AddRef (void) {
  302. assert (ReferenceCount >= 0L);
  303. InterlockedIncrement (&ReferenceCount);
  304. }
  305. void ASYNC_ACCEPT::Release (void) {
  306. LONG Count;
  307. assert (ReferenceCount >= 0L);
  308. Count = InterlockedDecrement (&ReferenceCount);
  309. if (Count == 0L) {
  310. DebugF (_T("ASYNC_ACCEPT::Release -- Reference count dropped to zero. (this is %x)\n"), this);
  311. assert (StopNotifyEvent);
  312. SetEvent (StopNotifyEvent);
  313. }
  314. }