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.

453 lines
12 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. //
  80. // Set RCV and SND buffers to zero
  81. // Yes, it is ugly and bad practice but this is a QFE
  82. // for details look up bug# WinSE 31054, 691666 (read both 35928 and 33546).
  83. //
  84. ULONG Option = 0;
  85. setsockopt( AcceptSocket, SOL_SOCKET, SO_SNDBUF,
  86. (PCHAR)&Option, sizeof(Option) );
  87. Option = 0;
  88. setsockopt( AcceptSocket, SOL_SOCKET, SO_SNDBUF,
  89. (PCHAR)&Option, sizeof(Option) );
  90. if (bind (AcceptSocket, (SOCKADDR *) SocketAddress, sizeof (SOCKADDR_IN))) {
  91. Result = GetLastErrorAsResult ();
  92. DebugLastErrorF (_T("ASYNC_ACCEPT::StartIoLocked: failed to bind accept socket to address %08X:%04X\n"),
  93. ntohl (SocketAddress -> sin_addr.s_addr),
  94. ntohs (SocketAddress -> sin_port));
  95. } else {
  96. // Set keepalive on the socket
  97. KeepaliveOption = TRUE;
  98. if (SOCKET_ERROR == setsockopt (AcceptSocket, SOL_SOCKET,
  99. SO_KEEPALIVE, (PCHAR) &KeepaliveOption, sizeof (KeepaliveOption)))
  100. {
  101. Result = GetLastErrorAsResult ();
  102. DebugLastError (_T("ASYNC_ACCEPT: Failed to set keepalive on accept socket.\n"));
  103. } else {
  104. if (listen (AcceptSocket, 10)) {
  105. Result = GetLastErrorAsResult ();
  106. DebugLastError (_T("ASYNC_ACCEPT::StartIoLocked: failed to listen on accept socket\n"));
  107. } else {
  108. if (!BindIoCompletionCallback ((HANDLE) AcceptSocket, ASYNC_ACCEPT::IoCompletionCallback, 0)) {
  109. Result = GetLastErrorAsResult ();
  110. DebugLastError (_T("ASYNC_ACCEPT::StartIoLocked: failed to bind i/o completion callback\n"));
  111. } else {
  112. Result = IssueAccept ();
  113. if (Result == S_OK) {
  114. return Result;
  115. }
  116. }
  117. }
  118. }
  119. }
  120. closesocket (AcceptSocket);
  121. AcceptSocket = INVALID_SOCKET;
  122. }
  123. CloseHandle (StopNotifyEvent);
  124. StopNotifyEvent = NULL;
  125. }
  126. return Result;
  127. }
  128. HRESULT ASYNC_ACCEPT::GetListenSocketAddress (
  129. OUT SOCKADDR_IN * ReturnSocketAddress)
  130. {
  131. HRESULT Result;
  132. INT SocketAddressLength;
  133. Lock();
  134. if (AcceptSocket != INVALID_SOCKET) {
  135. SocketAddressLength = sizeof (SOCKADDR_IN);
  136. if (getsockname (AcceptSocket, (SOCKADDR *) ReturnSocketAddress, &SocketAddressLength) == SOCKET_ERROR) {
  137. Result = GetLastErrorAsResult();
  138. }
  139. else {
  140. Result = S_OK;
  141. }
  142. }
  143. else {
  144. Result = E_INVALIDARG;
  145. }
  146. Unlock();
  147. return Result;
  148. }
  149. HRESULT ASYNC_ACCEPT::IssueAccept (void)
  150. {
  151. HRESULT Result;
  152. BOOL KeepaliveOption;
  153. AssertLocked();
  154. assert (ClientSocket == INVALID_SOCKET);
  155. // assert (ReferenceCount == 0);
  156. ClientSocket = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
  157. if (ClientSocket == INVALID_SOCKET) {
  158. Result = GetLastErrorAsResult ();
  159. DebugLastError (_T("ASYNC_ACCEPT::IssueAccept: failed to create client socket.\n"));
  160. return Result;
  161. }
  162. //
  163. // Set RCV and SND buffers to zero
  164. // Yes, it is ugly and bad practice but this is a QFE
  165. // for details look up bug# WinSE 31054, 691666 (read both 35928 and 33546).
  166. //
  167. ULONG Option = 0;
  168. setsockopt( ClientSocket, SOL_SOCKET, SO_SNDBUF,
  169. (PCHAR)&Option, sizeof(Option) );
  170. Option = 0;
  171. setsockopt( ClientSocket, SOL_SOCKET, SO_SNDBUF,
  172. (PCHAR)&Option, sizeof(Option) );
  173. ZeroMemory (&Overlapped, sizeof (OVERLAPPED));
  174. AddRef();
  175. if (!AcceptEx (AcceptSocket,
  176. ClientSocket,
  177. ClientInfoBuffer,
  178. 0,
  179. sizeof (SOCKADDR_IN) + 0x10,
  180. sizeof (SOCKADDR_IN) + 0x10,
  181. &ClientInfoBufferLength,
  182. &Overlapped)) {
  183. if (WSAGetLastError() != WSA_IO_PENDING) {
  184. // an error occurred
  185. Release ();
  186. Result = GetLastErrorAsResult ();
  187. DebugLastError (_T("ASYNC_ACCEPT::IssueAccept: failed to issue accept.\n"));
  188. return Result;
  189. }
  190. // Set keepalive on the socket
  191. KeepaliveOption = TRUE;
  192. if (SOCKET_ERROR == setsockopt (ClientSocket, SOL_SOCKET,
  193. SO_KEEPALIVE, (PCHAR) &KeepaliveOption, sizeof (KeepaliveOption)))
  194. {
  195. Release ();
  196. Result = GetLastErrorAsResult ();
  197. DebugLastError (_T("ASYNC_ACCEPT: IssueAccept: Failed to set keepalive on client socket.\n"));
  198. return Result;
  199. }
  200. }
  201. return S_OK;
  202. }
  203. // static
  204. void ASYNC_ACCEPT::IoCompletionCallback (DWORD Status, DWORD BytesTransferred, LPOVERLAPPED Overlapped)
  205. {
  206. ASYNC_ACCEPT * AsyncAccept;
  207. AsyncAccept = CONTAINING_RECORD (Overlapped, ASYNC_ACCEPT, Overlapped);
  208. AsyncAccept -> IoComplete (Status, BytesTransferred);
  209. AsyncAccept -> Release ();
  210. }
  211. void ASYNC_ACCEPT::IoComplete (DWORD Status, DWORD BytesTransferred)
  212. {
  213. ASYNC_ACCEPT_FUNC LocalAcceptFunc;
  214. PVOID LocalAcceptFuncContext;
  215. SOCKADDR_IN LocalAddressCopy;
  216. SOCKADDR_IN RemoteAddressCopy;
  217. SOCKET LocalClientSocket;
  218. SOCKADDR * LocalAddress;
  219. INT LocalAddressLength;
  220. SOCKADDR * RemoteAddress;
  221. INT RemoteAddressLength;
  222. INT Result;
  223. Lock();
  224. assert (ClientSocket != INVALID_SOCKET);
  225. assert (ReferenceCount > 0);
  226. if (AcceptSocket == INVALID_SOCKET) {
  227. // Stop has been called
  228. // just immediately disconnect the client
  229. // we'll deal with object lifetime below
  230. closesocket (ClientSocket);
  231. ClientSocket = INVALID_SOCKET;
  232. }
  233. else {
  234. // the context is in the normal state
  235. // continue processing
  236. if (Status == ERROR_SUCCESS) {
  237. // a client has successfully connected
  238. GetAcceptExSockaddrs (
  239. ClientInfoBuffer,
  240. 0, // no initial recv
  241. sizeof (SOCKADDR_IN) + 0x10,
  242. sizeof (SOCKADDR_IN) + 0x10,
  243. &LocalAddress,
  244. &LocalAddressLength,
  245. &RemoteAddress,
  246. &RemoteAddressLength);
  247. // copy information out of the context
  248. // so that it will be valid after we issue a new accept and unlock
  249. LocalAddressCopy = *(SOCKADDR_IN *) LocalAddress;
  250. RemoteAddressCopy = *(SOCKADDR_IN *) RemoteAddress;
  251. LocalClientSocket = ClientSocket;
  252. LocalAcceptFunc = AcceptFunc;
  253. LocalAcceptFuncContext = AcceptFuncContext;
  254. ClientSocket = INVALID_SOCKET;
  255. // update the accept context
  256. Result = setsockopt (ClientSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
  257. reinterpret_cast <char *> (&AcceptSocket), sizeof (SOCKET));
  258. // issue a new accept
  259. IssueAccept();
  260. Unlock();
  261. (*LocalAcceptFunc) (LocalAcceptFuncContext, LocalClientSocket, &LocalAddressCopy, &RemoteAddressCopy);
  262. Lock();
  263. }
  264. else {
  265. // some error has occurred
  266. // this is usually (but not always) fatal
  267. assert (ClientSocket != INVALID_SOCKET);
  268. closesocket (ClientSocket);
  269. ClientSocket = INVALID_SOCKET;
  270. switch (Status) {
  271. case STATUS_CANCELLED:
  272. Debug (_T("ASYNC_ACCEPT::IoComplete: accept failed, STATUS_CANCELED, original thread probably exited, resubmitting request...\n"));
  273. break;
  274. default:
  275. DebugError (Status, _T("AsyncAccept: async accept FAILED, sleeping 2000ms and retrying...\n"));
  276. Sleep (2000);
  277. break;
  278. }
  279. IssueAccept();
  280. }
  281. }
  282. Unlock();
  283. }
  284. void ASYNC_ACCEPT::StopWait (void)
  285. {
  286. DWORD Status;
  287. Lock();
  288. if (AcceptSocket != INVALID_SOCKET) {
  289. // closing the socket cancels all pending i/o
  290. // we do NOT close the ClientSocket
  291. // only the i/o completion callback path may do that
  292. closesocket (AcceptSocket);
  293. AcceptSocket = INVALID_SOCKET;
  294. AcceptFunc = NULL;
  295. AcceptFuncContext = NULL;
  296. if (ClientSocket != INVALID_SOCKET) {
  297. // an accept is still pending. it may complete successfully,
  298. // or it may complete with STATUS_CANCELED (since we just closed AcceptSocket)
  299. // in either case, we must wait for the i/o complete callback to run.
  300. // AcceptSocket = INVALID_SOCKET is an indicator to the completion callback
  301. // that it should abort / return immediately.
  302. assert (StopNotifyEvent);
  303. Unlock ();
  304. // This is the counterpart to the AddRef called in
  305. // StartIoLocked (see comment there)
  306. Release ();
  307. DebugF (_T("ASYNC_ACCEPT::StopWait: waiting for i/o completion thread...\n"));
  308. Status = WaitForSingleObject (StopNotifyEvent, INFINITE);
  309. assert (Status == WAIT_OBJECT_0);
  310. Lock ();
  311. }
  312. }
  313. else {
  314. assert (!AcceptFunc);
  315. assert (!AcceptFuncContext);
  316. }
  317. if (StopNotifyEvent) {
  318. CloseHandle (StopNotifyEvent);
  319. StopNotifyEvent = NULL;
  320. }
  321. Unlock();
  322. }
  323. void ASYNC_ACCEPT::AddRef (void) {
  324. assert (ReferenceCount >= 0L);
  325. InterlockedIncrement (&ReferenceCount);
  326. }
  327. void ASYNC_ACCEPT::Release (void) {
  328. LONG Count;
  329. assert (ReferenceCount >= 0L);
  330. Count = InterlockedDecrement (&ReferenceCount);
  331. if (Count == 0L) {
  332. DebugF (_T("ASYNC_ACCEPT::Release -- Reference count dropped to zero. (this is %x)\n"), this);
  333. if (StopNotifyEvent) {
  334. SetEvent (StopNotifyEvent);
  335. }
  336. else {
  337. DebugF (_T("ASYNC_ACCEPT::Release � notify-event object was NULL (%x)\n"), this);
  338. }
  339. }
  340. }