PageRenderTime 42ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/deps/uv/src/win/winsock.c

https://github.com/prabhuNatarajan/node
C | 554 lines | 392 code | 106 blank | 56 comment | 77 complexity | 252773bd4e858f5a7ef6602f7ceefbb9 MD5 | raw file
Possible License(s): 0BSD, Apache-2.0, MIT, WTFPL, BSD-3-Clause, ISC
  1. /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to
  5. * deal in the Software without restriction, including without limitation the
  6. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  7. * sell copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  19. * IN THE SOFTWARE.
  20. */
  21. #include <assert.h>
  22. #include "uv.h"
  23. #include "internal.h"
  24. /* Whether there are any non-IFS LSPs stacked on TCP */
  25. int uv_tcp_non_ifs_lsp_ipv4;
  26. int uv_tcp_non_ifs_lsp_ipv6;
  27. /* Ip address used to bind to any port at any interface */
  28. struct sockaddr_in uv_addr_ip4_any_;
  29. struct sockaddr_in6 uv_addr_ip6_any_;
  30. /*
  31. * Retrieves the pointer to a winsock extension function.
  32. */
  33. static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
  34. void **target) {
  35. DWORD result, bytes;
  36. result = WSAIoctl(socket,
  37. SIO_GET_EXTENSION_FUNCTION_POINTER,
  38. &guid,
  39. sizeof(guid),
  40. (void*)target,
  41. sizeof(*target),
  42. &bytes,
  43. NULL,
  44. NULL);
  45. if (result == SOCKET_ERROR) {
  46. *target = NULL;
  47. return FALSE;
  48. } else {
  49. return TRUE;
  50. }
  51. }
  52. BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) {
  53. const GUID wsaid_acceptex = WSAID_ACCEPTEX;
  54. return uv_get_extension_function(socket, wsaid_acceptex, (void**)target);
  55. }
  56. BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) {
  57. const GUID wsaid_connectex = WSAID_CONNECTEX;
  58. return uv_get_extension_function(socket, wsaid_connectex, (void**)target);
  59. }
  60. static int error_means_no_support(DWORD error) {
  61. return error == WSAEPROTONOSUPPORT || error == WSAESOCKTNOSUPPORT ||
  62. error == WSAEPFNOSUPPORT || error == WSAEAFNOSUPPORT;
  63. }
  64. void uv_winsock_init() {
  65. WSADATA wsa_data;
  66. int errorno;
  67. SOCKET dummy;
  68. WSAPROTOCOL_INFOW protocol_info;
  69. int opt_len;
  70. /* Initialize winsock */
  71. errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
  72. if (errorno != 0) {
  73. uv_fatal_error(errorno, "WSAStartup");
  74. }
  75. /* Set implicit binding address used by connectEx */
  76. uv_addr_ip4_any_ = uv_ip4_addr("0.0.0.0", 0);
  77. uv_addr_ip6_any_ = uv_ip6_addr("::", 0);
  78. /* Detect non-IFS LSPs */
  79. dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  80. if (dummy != INVALID_SOCKET) {
  81. opt_len = (int) sizeof protocol_info;
  82. if (!getsockopt(dummy,
  83. SOL_SOCKET,
  84. SO_PROTOCOL_INFOW,
  85. (char*) &protocol_info,
  86. &opt_len) == SOCKET_ERROR)
  87. uv_fatal_error(WSAGetLastError(), "getsockopt");
  88. if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
  89. uv_tcp_non_ifs_lsp_ipv4 = 1;
  90. if (closesocket(dummy) == SOCKET_ERROR)
  91. uv_fatal_error(WSAGetLastError(), "closesocket");
  92. } else if (!error_means_no_support(WSAGetLastError())) {
  93. /* Any error other than "socket type not supported" is fatal. */
  94. uv_fatal_error(WSAGetLastError(), "socket");
  95. }
  96. /* Detect IPV6 support and non-IFS LSPs */
  97. dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
  98. if (dummy != INVALID_SOCKET) {
  99. opt_len = (int) sizeof protocol_info;
  100. if (!getsockopt(dummy,
  101. SOL_SOCKET,
  102. SO_PROTOCOL_INFOW,
  103. (char*) &protocol_info,
  104. &opt_len) == SOCKET_ERROR)
  105. uv_fatal_error(WSAGetLastError(), "getsockopt");
  106. if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
  107. uv_tcp_non_ifs_lsp_ipv6 = 1;
  108. if (closesocket(dummy) == SOCKET_ERROR)
  109. uv_fatal_error(WSAGetLastError(), "closesocket");
  110. } else if (!error_means_no_support(WSAGetLastError())) {
  111. /* Any error other than "socket type not supported" is fatal. */
  112. uv_fatal_error(WSAGetLastError(), "socket");
  113. }
  114. }
  115. int uv_ntstatus_to_winsock_error(NTSTATUS status) {
  116. switch (status) {
  117. case STATUS_SUCCESS:
  118. return ERROR_SUCCESS;
  119. case STATUS_PENDING:
  120. return ERROR_IO_PENDING;
  121. case STATUS_INVALID_HANDLE:
  122. case STATUS_OBJECT_TYPE_MISMATCH:
  123. return WSAENOTSOCK;
  124. case STATUS_INSUFFICIENT_RESOURCES:
  125. case STATUS_PAGEFILE_QUOTA:
  126. case STATUS_COMMITMENT_LIMIT:
  127. case STATUS_WORKING_SET_QUOTA:
  128. case STATUS_NO_MEMORY:
  129. case STATUS_CONFLICTING_ADDRESSES:
  130. case STATUS_QUOTA_EXCEEDED:
  131. case STATUS_TOO_MANY_PAGING_FILES:
  132. case STATUS_REMOTE_RESOURCES:
  133. case STATUS_TOO_MANY_ADDRESSES:
  134. return WSAENOBUFS;
  135. case STATUS_SHARING_VIOLATION:
  136. case STATUS_ADDRESS_ALREADY_EXISTS:
  137. return WSAEADDRINUSE;
  138. case STATUS_LINK_TIMEOUT:
  139. case STATUS_IO_TIMEOUT:
  140. case STATUS_TIMEOUT:
  141. return WSAETIMEDOUT;
  142. case STATUS_GRACEFUL_DISCONNECT:
  143. return WSAEDISCON;
  144. case STATUS_REMOTE_DISCONNECT:
  145. case STATUS_CONNECTION_RESET:
  146. case STATUS_LINK_FAILED:
  147. case STATUS_CONNECTION_DISCONNECTED:
  148. case STATUS_PORT_UNREACHABLE:
  149. case STATUS_HOPLIMIT_EXCEEDED:
  150. return WSAECONNRESET;
  151. case STATUS_LOCAL_DISCONNECT:
  152. case STATUS_TRANSACTION_ABORTED:
  153. case STATUS_CONNECTION_ABORTED:
  154. return WSAECONNABORTED;
  155. case STATUS_BAD_NETWORK_PATH:
  156. case STATUS_NETWORK_UNREACHABLE:
  157. case STATUS_PROTOCOL_UNREACHABLE:
  158. return WSAENETUNREACH;
  159. case STATUS_HOST_UNREACHABLE:
  160. return WSAEHOSTUNREACH;
  161. case STATUS_CANCELLED:
  162. case STATUS_REQUEST_ABORTED:
  163. return WSAEINTR;
  164. case STATUS_BUFFER_OVERFLOW:
  165. case STATUS_INVALID_BUFFER_SIZE:
  166. return WSAEMSGSIZE;
  167. case STATUS_BUFFER_TOO_SMALL:
  168. case STATUS_ACCESS_VIOLATION:
  169. return WSAEFAULT;
  170. case STATUS_DEVICE_NOT_READY:
  171. case STATUS_REQUEST_NOT_ACCEPTED:
  172. return WSAEWOULDBLOCK;
  173. case STATUS_INVALID_NETWORK_RESPONSE:
  174. case STATUS_NETWORK_BUSY:
  175. case STATUS_NO_SUCH_DEVICE:
  176. case STATUS_NO_SUCH_FILE:
  177. case STATUS_OBJECT_PATH_NOT_FOUND:
  178. case STATUS_OBJECT_NAME_NOT_FOUND:
  179. case STATUS_UNEXPECTED_NETWORK_ERROR:
  180. return WSAENETDOWN;
  181. case STATUS_INVALID_CONNECTION:
  182. return WSAENOTCONN;
  183. case STATUS_REMOTE_NOT_LISTENING:
  184. case STATUS_CONNECTION_REFUSED:
  185. return WSAECONNREFUSED;
  186. case STATUS_PIPE_DISCONNECTED:
  187. return WSAESHUTDOWN;
  188. case STATUS_INVALID_ADDRESS:
  189. case STATUS_INVALID_ADDRESS_COMPONENT:
  190. return WSAEADDRNOTAVAIL;
  191. case STATUS_NOT_SUPPORTED:
  192. case STATUS_NOT_IMPLEMENTED:
  193. return WSAEOPNOTSUPP;
  194. case STATUS_ACCESS_DENIED:
  195. return WSAEACCES;
  196. default:
  197. if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) &&
  198. (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) {
  199. /* It's a windows error that has been previously mapped to an */
  200. /* ntstatus code. */
  201. return (DWORD) (status & 0xffff);
  202. } else {
  203. /* The default fallback for unmappable ntstatus codes. */
  204. return WSAEINVAL;
  205. }
  206. }
  207. }
  208. /*
  209. * This function provides a workaround for a bug in the winsock implementation
  210. * of WSARecv. The problem is that when SetFileCompletionNotificationModes is
  211. * used to avoid IOCP notifications of completed reads, WSARecv does not
  212. * reliably indicate whether we can expect a completion package to be posted
  213. * when the receive buffer is smaller than the received datagram.
  214. *
  215. * However it is desirable to use SetFileCompletionNotificationModes because
  216. * it yields a massive performance increase.
  217. *
  218. * This function provides a workaround for that bug, but it only works for the
  219. * specific case that we need it for. E.g. it assumes that the "avoid iocp"
  220. * bit has been set, and supports only overlapped operation. It also requires
  221. * the user to use the default msafd driver, doesn't work when other LSPs are
  222. * stacked on top of it.
  223. */
  224. int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
  225. DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
  226. LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
  227. NTSTATUS status;
  228. void* apc_context;
  229. IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
  230. AFD_RECV_INFO info;
  231. DWORD error;
  232. if (overlapped == NULL || completion_routine != NULL) {
  233. WSASetLastError(WSAEINVAL);
  234. return SOCKET_ERROR;
  235. }
  236. info.BufferArray = buffers;
  237. info.BufferCount = buffer_count;
  238. info.AfdFlags = AFD_OVERLAPPED;
  239. info.TdiFlags = TDI_RECEIVE_NORMAL;
  240. if (*flags & MSG_PEEK) {
  241. info.TdiFlags |= TDI_RECEIVE_PEEK;
  242. }
  243. if (*flags & MSG_PARTIAL) {
  244. info.TdiFlags |= TDI_RECEIVE_PARTIAL;
  245. }
  246. if (!((intptr_t) overlapped->hEvent & 1)) {
  247. apc_context = (void*) overlapped;
  248. } else {
  249. apc_context = NULL;
  250. }
  251. iosb->Status = STATUS_PENDING;
  252. iosb->Pointer = 0;
  253. status = pNtDeviceIoControlFile((HANDLE) socket,
  254. overlapped->hEvent,
  255. NULL,
  256. apc_context,
  257. iosb,
  258. IOCTL_AFD_RECEIVE,
  259. &info,
  260. sizeof(info),
  261. NULL,
  262. 0);
  263. *flags = 0;
  264. *bytes = (DWORD) iosb->Information;
  265. switch (status) {
  266. case STATUS_SUCCESS:
  267. error = ERROR_SUCCESS;
  268. break;
  269. case STATUS_PENDING:
  270. error = WSA_IO_PENDING;
  271. break;
  272. case STATUS_BUFFER_OVERFLOW:
  273. error = WSAEMSGSIZE;
  274. break;
  275. case STATUS_RECEIVE_EXPEDITED:
  276. error = ERROR_SUCCESS;
  277. *flags = MSG_OOB;
  278. break;
  279. case STATUS_RECEIVE_PARTIAL_EXPEDITED:
  280. error = ERROR_SUCCESS;
  281. *flags = MSG_PARTIAL | MSG_OOB;
  282. break;
  283. case STATUS_RECEIVE_PARTIAL:
  284. error = ERROR_SUCCESS;
  285. *flags = MSG_PARTIAL;
  286. break;
  287. default:
  288. error = uv_ntstatus_to_winsock_error(status);
  289. break;
  290. }
  291. WSASetLastError(error);
  292. if (error == ERROR_SUCCESS) {
  293. return 0;
  294. } else {
  295. return SOCKET_ERROR;
  296. }
  297. }
  298. /* See description of uv_wsarecv_workaround. */
  299. int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
  300. DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
  301. int* addr_len, WSAOVERLAPPED *overlapped,
  302. LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
  303. NTSTATUS status;
  304. void* apc_context;
  305. IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
  306. AFD_RECV_DATAGRAM_INFO info;
  307. DWORD error;
  308. if (overlapped == NULL || addr == NULL || addr_len == NULL ||
  309. completion_routine != NULL) {
  310. WSASetLastError(WSAEINVAL);
  311. return SOCKET_ERROR;
  312. }
  313. info.BufferArray = buffers;
  314. info.BufferCount = buffer_count;
  315. info.AfdFlags = AFD_OVERLAPPED;
  316. info.TdiFlags = TDI_RECEIVE_NORMAL;
  317. info.Address = addr;
  318. info.AddressLength = addr_len;
  319. if (*flags & MSG_PEEK) {
  320. info.TdiFlags |= TDI_RECEIVE_PEEK;
  321. }
  322. if (*flags & MSG_PARTIAL) {
  323. info.TdiFlags |= TDI_RECEIVE_PARTIAL;
  324. }
  325. if (!((intptr_t) overlapped->hEvent & 1)) {
  326. apc_context = (void*) overlapped;
  327. } else {
  328. apc_context = NULL;
  329. }
  330. iosb->Status = STATUS_PENDING;
  331. iosb->Pointer = 0;
  332. status = pNtDeviceIoControlFile((HANDLE) socket,
  333. overlapped->hEvent,
  334. NULL,
  335. apc_context,
  336. iosb,
  337. IOCTL_AFD_RECEIVE_DATAGRAM,
  338. &info,
  339. sizeof(info),
  340. NULL,
  341. 0);
  342. *flags = 0;
  343. *bytes = (DWORD) iosb->Information;
  344. switch (status) {
  345. case STATUS_SUCCESS:
  346. error = ERROR_SUCCESS;
  347. break;
  348. case STATUS_PENDING:
  349. error = WSA_IO_PENDING;
  350. break;
  351. case STATUS_BUFFER_OVERFLOW:
  352. error = WSAEMSGSIZE;
  353. break;
  354. case STATUS_RECEIVE_EXPEDITED:
  355. error = ERROR_SUCCESS;
  356. *flags = MSG_OOB;
  357. break;
  358. case STATUS_RECEIVE_PARTIAL_EXPEDITED:
  359. error = ERROR_SUCCESS;
  360. *flags = MSG_PARTIAL | MSG_OOB;
  361. break;
  362. case STATUS_RECEIVE_PARTIAL:
  363. error = ERROR_SUCCESS;
  364. *flags = MSG_PARTIAL;
  365. break;
  366. default:
  367. error = uv_ntstatus_to_winsock_error(status);
  368. break;
  369. }
  370. WSASetLastError(error);
  371. if (error == ERROR_SUCCESS) {
  372. return 0;
  373. } else {
  374. return SOCKET_ERROR;
  375. }
  376. }
  377. int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info,
  378. OVERLAPPED* overlapped) {
  379. IO_STATUS_BLOCK iosb;
  380. IO_STATUS_BLOCK* iosb_ptr;
  381. HANDLE event = NULL;
  382. void* apc_context;
  383. NTSTATUS status;
  384. DWORD error;
  385. if (overlapped != NULL) {
  386. /* Overlapped operation. */
  387. iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal;
  388. event = overlapped->hEvent;
  389. /* Do not report iocp completion if hEvent is tagged. */
  390. if ((uintptr_t) event & 1) {
  391. event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1);
  392. apc_context = NULL;
  393. } else {
  394. apc_context = overlapped;
  395. }
  396. } else {
  397. /* Blocking operation. */
  398. iosb_ptr = &iosb;
  399. event = CreateEvent(NULL, FALSE, FALSE, NULL);
  400. if (event == NULL) {
  401. return SOCKET_ERROR;
  402. }
  403. apc_context = NULL;
  404. }
  405. iosb_ptr->Status = STATUS_PENDING;
  406. status = pNtDeviceIoControlFile((HANDLE) socket,
  407. event,
  408. NULL,
  409. apc_context,
  410. iosb_ptr,
  411. IOCTL_AFD_POLL,
  412. info,
  413. sizeof *info,
  414. info,
  415. sizeof *info);
  416. if (overlapped == NULL) {
  417. /* If this is a blocking operation, wait for the event to become */
  418. /* signaled, and then grab the real status from the io status block. */
  419. if (status == STATUS_PENDING) {
  420. DWORD r = WaitForSingleObject(event, INFINITE);
  421. if (r == WAIT_FAILED) {
  422. DWORD saved_error = GetLastError();
  423. CloseHandle(event);
  424. WSASetLastError(saved_error);
  425. return SOCKET_ERROR;
  426. }
  427. status = iosb.Status;
  428. }
  429. CloseHandle(event);
  430. }
  431. switch (status) {
  432. case STATUS_SUCCESS:
  433. error = ERROR_SUCCESS;
  434. break;
  435. case STATUS_PENDING:
  436. error = WSA_IO_PENDING;
  437. break;
  438. default:
  439. error = uv_ntstatus_to_winsock_error(status);
  440. break;
  441. }
  442. WSASetLastError(error);
  443. if (error == ERROR_SUCCESS) {
  444. return 0;
  445. } else {
  446. return SOCKET_ERROR;
  447. }
  448. }