[2020-02] Fix leak in assembly-specific dllmap lookups (#21053)
[mono-project.git] / mono / metadata / w32socket-unix.c
blobac3bd0f85ff2a1c1d7b454dd369c050de1c1edac
1 /**
2 * \file
3 * Unix specific socket code.
5 * Copyright 2016 Microsoft
6 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
7 */
9 #include <config.h>
10 #include <glib.h>
12 #include <pthread.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #ifdef HAVE_SYS_IOCTL_H
18 #include <sys/ioctl.h>
19 #endif
20 #include <netinet/in.h>
21 #include <netinet/tcp.h>
22 #ifdef HAVE_NETDB_H
23 #include <netdb.h>
24 #endif
25 #ifdef HAVE_NETINET_TCP_H
26 #include <arpa/inet.h>
27 #endif
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #include <errno.h>
32 #include <fcntl.h>
33 #ifdef HAVE_SYS_UIO_H
34 #include <sys/uio.h>
35 #endif
36 #ifdef HAVE_SYS_IOCTL_H
37 #include <sys/ioctl.h>
38 #endif
39 #ifdef HAVE_SYS_FILIO_H
40 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
41 #endif
42 #ifdef HAVE_SYS_SOCKIO_H
43 #include <sys/sockio.h> /* defines SIOCATMARK */
44 #endif
45 #include <signal.h>
46 #ifdef HAVE_SYS_SENDFILE_H
47 #include <sys/sendfile.h>
48 #endif
49 #include <sys/stat.h>
51 #include "w32socket.h"
52 #include "w32socket-internals.h"
53 #include "w32error.h"
54 #include "fdhandle.h"
55 #include "utils/mono-logger-internals.h"
56 #include "utils/mono-poll.h"
57 #include "utils/mono-compiler.h"
58 #include "icall-decl.h"
59 #include "utils/mono-errno.h"
61 typedef struct {
62 MonoFDHandle fdhandle;
63 gint domain;
64 gint type;
65 gint protocol;
66 gint saved_error;
67 gint still_readable;
68 } SocketHandle;
70 static SocketHandle*
71 socket_data_create (MonoFDType type, gint fd)
73 SocketHandle *sockethandle;
75 sockethandle = g_new0 (SocketHandle, 1);
76 mono_fdhandle_init ((MonoFDHandle*) sockethandle, type, fd);
78 return sockethandle;
81 static void
82 socket_data_close (MonoFDHandle *fdhandle)
84 MonoThreadInfo *info;
85 SocketHandle* sockethandle;
86 gint ret;
88 sockethandle = (SocketHandle*) fdhandle;
89 g_assert (sockethandle);
91 info = mono_thread_info_current ();
93 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: closing fd %d", __func__, ((MonoFDHandle*) sockethandle)->fd);
95 /* Shutdown the socket for reading, to interrupt any potential
96 * receives that may be blocking for data. See bug 75705. */
97 MONO_ENTER_GC_SAFE;
98 shutdown (((MonoFDHandle*) sockethandle)->fd, SHUT_RD);
99 MONO_EXIT_GC_SAFE;
101 retry_close:
102 MONO_ENTER_GC_SAFE;
103 ret = close (((MonoFDHandle*) sockethandle)->fd);
104 MONO_EXIT_GC_SAFE;
105 if (ret == -1) {
106 if (errno == EINTR && !mono_thread_info_is_interrupt_state (info))
107 goto retry_close;
110 sockethandle->saved_error = 0;
113 static void
114 socket_data_destroy (MonoFDHandle *fdhandle)
116 SocketHandle *sockethandle;
118 sockethandle = (SocketHandle*) fdhandle;
119 g_assert (sockethandle);
121 g_free (sockethandle);
124 void
125 mono_w32socket_initialize (void)
127 MonoFDHandleCallback socket_data_callbacks;
128 memset (&socket_data_callbacks, 0, sizeof (socket_data_callbacks));
129 socket_data_callbacks.close = socket_data_close;
130 socket_data_callbacks.destroy = socket_data_destroy;
132 mono_fdhandle_register (MONO_FDTYPE_SOCKET, &socket_data_callbacks);
135 void
136 mono_w32socket_cleanup (void)
140 SOCKET
141 mono_w32socket_accept (SOCKET sock, struct sockaddr *addr, socklen_t *addrlen, gboolean blocking)
143 SocketHandle *sockethandle, *accepted_socket_data;
144 MonoThreadInfo *info;
145 gint accepted_fd;
147 if (addr != NULL && *addrlen < sizeof(struct sockaddr)) {
148 mono_w32socket_set_last_error (WSAEFAULT);
149 return INVALID_SOCKET;
152 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
153 mono_w32error_set_last (WSAENOTSOCK);
154 return INVALID_SOCKET;
157 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
158 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
159 mono_w32error_set_last (WSAENOTSOCK);
160 return INVALID_SOCKET;
163 info = mono_thread_info_current ();
165 do {
166 MONO_ENTER_GC_SAFE;
167 accepted_fd = accept (((MonoFDHandle*) sockethandle)->fd, addr, addrlen);
168 MONO_EXIT_GC_SAFE;
169 } while (accepted_fd == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
171 if (accepted_fd == -1) {
172 gint error = mono_w32socket_convert_error (errno);
173 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: accept error: %s", __func__, g_strerror(errno));
174 mono_w32socket_set_last_error (error);
175 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
176 return INVALID_SOCKET;
179 accepted_socket_data = socket_data_create (MONO_FDTYPE_SOCKET, accepted_fd);
180 accepted_socket_data->domain = sockethandle->domain;
181 accepted_socket_data->type = sockethandle->type;
182 accepted_socket_data->protocol = sockethandle->protocol;
183 accepted_socket_data->still_readable = 1;
185 mono_fdhandle_insert ((MonoFDHandle*) accepted_socket_data);
187 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: returning accepted handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) accepted_socket_data)->fd));
189 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
190 return ((MonoFDHandle*) accepted_socket_data)->fd;
194 mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, int addrlen, gboolean blocking)
196 SocketHandle *sockethandle;
197 gint ret;
199 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
200 mono_w32error_set_last (WSAENOTSOCK);
201 return SOCKET_ERROR;
204 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
205 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
206 mono_w32error_set_last (WSAENOTSOCK);
207 return SOCKET_ERROR;
210 MONO_ENTER_GC_SAFE;
211 ret = connect (((MonoFDHandle*) sockethandle)->fd, addr, addrlen);
212 MONO_EXIT_GC_SAFE;
213 if (ret == -1) {
214 MonoThreadInfo *info;
215 mono_pollfd fds;
216 gint errnum, so_error;
217 socklen_t len;
219 errnum = errno;
221 if (errno != EINTR) {
222 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect error: %s", __func__,
223 g_strerror (errnum));
225 errnum = mono_w32socket_convert_error (errnum);
226 if (errnum == WSAEINPROGRESS)
227 errnum = WSAEWOULDBLOCK; /* see bug #73053 */
229 mono_w32socket_set_last_error (errnum);
232 * On solaris x86 getsockopt (SO_ERROR) is not set after
233 * connect () fails so we need to save this error.
235 * But don't do this for EWOULDBLOCK (bug 317315)
237 if (errnum != WSAEWOULDBLOCK) {
238 /* ECONNRESET means the socket was closed by another thread */
239 /* Async close on mac raises ECONNABORTED. */
240 sockethandle->saved_error = errnum;
242 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
243 return SOCKET_ERROR;
246 info = mono_thread_info_current ();
248 fds.fd = ((MonoFDHandle*) sockethandle)->fd;
249 fds.events = MONO_POLLOUT;
250 for (;;) {
251 MONO_ENTER_GC_SAFE;
252 ret = mono_poll (&fds, 1, -1);
253 MONO_EXIT_GC_SAFE;
254 if (ret != -1 || mono_thread_info_is_interrupt_state (info))
255 break;
257 if (errno != EINTR) {
258 gint errnum = errno;
259 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect poll error: %s", __func__, g_strerror (errno));
260 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
261 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
262 return SOCKET_ERROR;
266 len = sizeof(so_error);
267 MONO_ENTER_GC_SAFE;
268 ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_ERROR, &so_error, &len);
269 MONO_EXIT_GC_SAFE;
270 if (ret == -1) {
271 gint errnum = errno;
272 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect getsockopt error: %s", __func__, g_strerror (errno));
273 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
274 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
275 return SOCKET_ERROR;
278 if (so_error != 0) {
279 gint errnum = mono_w32socket_convert_error (so_error);
281 /* Need to save this socket error */
282 sockethandle->saved_error = errnum;
284 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect getsockopt returned error: %s",
285 __func__, g_strerror (so_error));
287 mono_w32socket_set_last_error (errnum);
288 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
289 return SOCKET_ERROR;
293 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
294 return 0;
298 mono_w32socket_recv (SOCKET sock, char *buf, int len, int flags, gboolean blocking)
300 return mono_w32socket_recvfrom (sock, buf, len, flags, NULL, 0, blocking);
304 mono_w32socket_recvfrom (SOCKET sock, char *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, gboolean blocking)
306 SocketHandle *sockethandle;
307 int ret;
308 MonoThreadInfo *info;
310 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
311 mono_w32error_set_last (WSAENOTSOCK);
312 return SOCKET_ERROR;
315 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
316 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
317 mono_w32error_set_last (WSAENOTSOCK);
318 return SOCKET_ERROR;
321 info = mono_thread_info_current ();
323 do {
324 MONO_ENTER_GC_SAFE;
325 ret = recvfrom (((MonoFDHandle*) sockethandle)->fd, buf, len, flags, from, fromlen);
326 MONO_EXIT_GC_SAFE;
327 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
329 if (ret == 0 && len > 0) {
330 /* According to the Linux man page, recvfrom only
331 * returns 0 when the socket has been shut down
332 * cleanly. Turn this into an EINTR to simulate win32
333 * behaviour of returning EINTR when a socket is
334 * closed while the recvfrom is blocking (we use a
335 * shutdown() in socket_close() to trigger this.) See
336 * bug 75705.
338 /* Distinguish between the socket being shut down at
339 * the local or remote ends, and reads that request 0
340 * bytes to be read
343 /* If this returns FALSE, it means the socket has been
344 * closed locally. If it returns TRUE, but
345 * still_readable != 1 then shutdown
346 * (SHUT_RD|SHUT_RDWR) has been called locally.
348 if (sockethandle->still_readable != 1) {
349 ret = -1;
350 mono_set_errno (EINTR);
354 if (ret == -1) {
355 gint errnum = errno;
356 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: recv error: %s", __func__, g_strerror(errno));
357 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
358 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
359 return SOCKET_ERROR;
361 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
362 return ret;
365 static void
366 wsabuf_to_msghdr (WSABUF *buffers, guint32 count, struct msghdr *hdr)
368 guint32 i;
370 memset (hdr, 0, sizeof (struct msghdr));
371 hdr->msg_iovlen = count;
372 hdr->msg_iov = g_new0 (struct iovec, count);
373 for (i = 0; i < count; i++) {
374 hdr->msg_iov [i].iov_base = buffers [i].buf;
375 hdr->msg_iov [i].iov_len = buffers [i].len;
379 static void
380 msghdr_iov_free (struct msghdr *hdr)
382 g_free (hdr->msg_iov);
386 mono_w32socket_recvbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *received, guint32 *flags, gpointer overlapped, gpointer complete, gboolean blocking)
388 SocketHandle *sockethandle;
389 MonoThreadInfo *info;
390 gint ret;
391 struct msghdr hdr;
393 g_assert (overlapped == NULL);
394 g_assert (complete == NULL);
396 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
397 mono_w32error_set_last (WSAENOTSOCK);
398 return SOCKET_ERROR;
401 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
402 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
403 mono_w32error_set_last (WSAENOTSOCK);
404 return SOCKET_ERROR;
407 info = mono_thread_info_current ();
409 wsabuf_to_msghdr (buffers, count, &hdr);
411 do {
412 MONO_ENTER_GC_SAFE;
413 ret = recvmsg (((MonoFDHandle*) sockethandle)->fd, &hdr, *flags);
414 MONO_EXIT_GC_SAFE;
415 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
417 msghdr_iov_free (&hdr);
419 if (ret == 0) {
420 /* see mono_w32socket_recvfrom */
421 if (sockethandle->still_readable != 1) {
422 ret = -1;
423 mono_set_errno (EINTR);
427 if (ret == -1) {
428 gint errnum = errno;
429 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: recvmsg error: %s", __func__, g_strerror(errno));
430 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
431 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
432 return SOCKET_ERROR;
435 *received = ret;
436 *flags = hdr.msg_flags;
438 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
439 return 0;
443 mono_w32socket_send (SOCKET sock, void *buf, int len, int flags, gboolean blocking)
445 SocketHandle *sockethandle;
446 int ret;
447 MonoThreadInfo *info;
449 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
450 mono_w32error_set_last (WSAENOTSOCK);
451 return SOCKET_ERROR;
454 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
455 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
456 mono_w32error_set_last (WSAENOTSOCK);
457 return SOCKET_ERROR;
460 info = mono_thread_info_current ();
462 do {
463 MONO_ENTER_GC_SAFE;
464 ret = send (((MonoFDHandle*) sockethandle)->fd, buf, len, flags);
465 MONO_EXIT_GC_SAFE;
466 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
468 if (ret == -1) {
469 gint errnum = errno;
470 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: send error: %s", __func__, g_strerror (errno));
472 #ifdef O_NONBLOCK
473 /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on
474 * a blocking socket. See bug #599488 */
475 if (errnum == EAGAIN) {
476 MONO_ENTER_GC_SAFE;
477 ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_GETFL, 0);
478 MONO_EXIT_GC_SAFE;
479 if (ret != -1 && (ret & O_NONBLOCK) == 0)
480 errnum = ETIMEDOUT;
482 #endif /* O_NONBLOCK */
483 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
484 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
485 return SOCKET_ERROR;
487 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
488 return ret;
492 mono_w32socket_sendto (SOCKET sock, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking)
494 SocketHandle *sockethandle;
495 int ret;
496 MonoThreadInfo *info;
498 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
499 mono_w32error_set_last (WSAENOTSOCK);
500 return SOCKET_ERROR;
503 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
504 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
505 mono_w32error_set_last (WSAENOTSOCK);
506 return SOCKET_ERROR;
509 info = mono_thread_info_current ();
511 do {
512 MONO_ENTER_GC_SAFE;
513 ret = sendto (((MonoFDHandle*) sockethandle)->fd, buf, len, flags, to, tolen);
514 MONO_EXIT_GC_SAFE;
515 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
517 if (ret == -1) {
518 gint errnum = errno;
519 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: send error: %s", __func__, g_strerror (errno));
520 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
521 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
522 return SOCKET_ERROR;
524 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
525 return ret;
529 mono_w32socket_sendbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *sent, guint32 flags, gpointer overlapped, gpointer complete, gboolean blocking)
531 struct msghdr hdr;
532 MonoThreadInfo *info;
533 SocketHandle *sockethandle;
534 gint ret;
536 g_assert (overlapped == NULL);
537 g_assert (complete == NULL);
539 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
540 mono_w32error_set_last (WSAENOTSOCK);
541 return SOCKET_ERROR;
544 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
545 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
546 mono_w32error_set_last (WSAENOTSOCK);
547 return SOCKET_ERROR;
550 info = mono_thread_info_current ();
552 wsabuf_to_msghdr (buffers, count, &hdr);
554 do {
555 MONO_ENTER_GC_SAFE;
556 ret = sendmsg (((MonoFDHandle*) sockethandle)->fd, &hdr, flags);
557 MONO_EXIT_GC_SAFE;
558 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
560 msghdr_iov_free (&hdr);
562 if (ret == -1) {
563 gint errnum = errno;
564 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: sendmsg error: %s", __func__, g_strerror (errno));
565 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
566 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
567 return SOCKET_ERROR;
570 *sent = ret;
571 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
572 return 0;
575 #define SF_BUFFER_SIZE 16384
577 BOOL
578 mono_w32socket_transmit_file (SOCKET sock, gpointer file_handle, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags, gboolean blocking)
580 MonoThreadInfo *info;
581 SocketHandle *sockethandle;
582 gint file;
583 gssize ret;
584 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
585 struct stat statbuf;
586 #else
587 gpointer buffer;
588 #endif
590 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
591 mono_w32error_set_last (WSAENOTSOCK);
592 return FALSE;
595 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
596 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
597 mono_w32error_set_last (WSAENOTSOCK);
598 return FALSE;
601 /* Write the header */
602 if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) {
603 ret = mono_w32socket_send (((MonoFDHandle*) sockethandle)->fd, buffers->Head, buffers->HeadLength, 0, FALSE);
604 if (ret == SOCKET_ERROR) {
605 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
606 return FALSE;
610 info = mono_thread_info_current ();
612 file = GPOINTER_TO_INT (file_handle);
614 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
615 MONO_ENTER_GC_SAFE;
616 ret = fstat (file, &statbuf);
617 MONO_EXIT_GC_SAFE;
618 if (ret == -1) {
619 gint errnum = errno;
620 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
621 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
622 return FALSE;
625 do {
626 MONO_ENTER_GC_SAFE;
627 #ifdef __linux__
628 ret = sendfile (((MonoFDHandle*) sockethandle)->fd, file, NULL, statbuf.st_size);
629 #elif defined(DARWIN)
630 /* TODO: header/tail could be sent in the 5th argument */
631 /* TODO: Might not send the entire file for non-blocking sockets */
632 ret = sendfile (file, ((MonoFDHandle*) sockethandle)->fd, 0, &statbuf.st_size, NULL, 0);
633 #endif
634 MONO_EXIT_GC_SAFE;
635 } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
636 #else
637 buffer = g_malloc (SF_BUFFER_SIZE);
639 do {
640 do {
641 MONO_ENTER_GC_SAFE;
642 ret = read (file, buffer, SF_BUFFER_SIZE);
643 MONO_EXIT_GC_SAFE;
644 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
646 if (ret == -1 || ret == 0)
647 break;
649 do {
650 MONO_ENTER_GC_SAFE;
651 ret = send (((MonoFDHandle*) sockethandle)->fd, buffer, ret, 0); /* short sends? enclose this in a loop? */
652 MONO_EXIT_GC_SAFE;
653 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
654 } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
656 g_free (buffer);
657 #endif
659 if (ret == -1) {
660 gint errnum = errno;
661 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
662 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
663 return FALSE;
666 /* Write the tail */
667 if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) {
668 ret = mono_w32socket_send (((MonoFDHandle*) sockethandle)->fd, buffers->Tail, buffers->TailLength, 0, FALSE);
669 if (ret == SOCKET_ERROR) {
670 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
671 return FALSE;
675 if ((flags & TF_DISCONNECT) == TF_DISCONNECT)
676 mono_w32socket_close (((MonoFDHandle*) sockethandle)->fd);
678 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
679 return TRUE;
682 SOCKET
683 mono_w32socket_socket (int domain, int type, int protocol)
685 SocketHandle *sockethandle;
686 gint fd;
688 retry_socket:
689 MONO_ENTER_GC_SAFE;
690 fd = socket (domain, type, protocol);
691 MONO_EXIT_GC_SAFE;
692 if (fd == -1) {
693 if (domain == AF_INET && type == SOCK_RAW && protocol == 0) {
694 /* Retry with protocol == 4 (see bug #54565) */
695 // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565
696 protocol = 4;
697 goto retry_socket;
700 gint errnum = errno;
701 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: socket error: %s", __func__, g_strerror (errno));
702 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
703 return INVALID_SOCKET;
706 sockethandle = socket_data_create(MONO_FDTYPE_SOCKET, fd);
707 sockethandle->domain = domain;
708 sockethandle->type = type;
709 sockethandle->protocol = protocol;
710 sockethandle->still_readable = 1;
712 /* .net seems to set this by default for SOCK_STREAM, not for
713 * SOCK_DGRAM (see bug #36322)
714 * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322
716 * It seems winsock has a rather different idea of what
717 * SO_REUSEADDR means. If it's set, then a new socket can be
718 * bound over an existing listening socket. There's a new
719 * windows-specific option called SO_EXCLUSIVEADDRUSE but
720 * using that means the socket MUST be closed properly, or a
721 * denial of service can occur. Luckily for us, winsock
722 * behaves as though any other system would when SO_REUSEADDR
723 * is true, so we don't need to do anything else here. See
724 * bug 53992.
725 * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992
728 int ret;
729 const int true_ = 1;
731 MONO_ENTER_GC_SAFE;
732 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_REUSEADDR, &true_, sizeof (true_));
733 MONO_EXIT_GC_SAFE;
734 if (ret == -1) {
735 gint errnum = errno;
736 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: Error setting SO_REUSEADDR", __func__);
737 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
739 MONO_ENTER_GC_SAFE;
740 close (((MonoFDHandle*) sockethandle)->fd);
741 MONO_EXIT_GC_SAFE;
743 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
744 return INVALID_SOCKET;
748 mono_fdhandle_insert ((MonoFDHandle*) sockethandle);
750 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: returning socket handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) sockethandle)->fd));
752 return ((MonoFDHandle*) sockethandle)->fd;
755 gint
756 mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen)
758 SocketHandle *sockethandle;
759 int ret;
761 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
762 mono_w32error_set_last (WSAENOTSOCK);
763 return SOCKET_ERROR;
766 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
767 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
768 mono_w32error_set_last (WSAENOTSOCK);
769 return SOCKET_ERROR;
772 MONO_ENTER_GC_SAFE;
773 ret = bind (((MonoFDHandle*) sockethandle)->fd, addr, addrlen);
774 MONO_EXIT_GC_SAFE;
775 if (ret == -1) {
776 gint errnum = errno;
777 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: bind error: %s", __func__, g_strerror(errno));
778 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
779 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
780 return SOCKET_ERROR;
783 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
784 return 0;
787 gint
788 mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
790 SocketHandle *sockethandle;
791 gint ret;
793 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
794 mono_w32error_set_last (WSAENOTSOCK);
795 return SOCKET_ERROR;
798 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
799 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
800 mono_w32error_set_last (WSAENOTSOCK);
801 return SOCKET_ERROR;
804 #ifdef HAVE_GETPEERNAME
805 MONO_ENTER_GC_SAFE;
806 ret = getpeername (((MonoFDHandle*) sockethandle)->fd, name, namelen);
807 MONO_EXIT_GC_SAFE;
808 #else
809 ret = -1;
810 #endif
811 if (ret == -1) {
812 gint errnum = errno;
813 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getpeername error: %s", __func__, g_strerror (errno));
814 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
815 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
816 return SOCKET_ERROR;
819 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
820 return 0;
823 gint
824 mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
826 SocketHandle *sockethandle;
827 gint ret;
829 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
830 mono_w32error_set_last (WSAENOTSOCK);
831 return SOCKET_ERROR;
834 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
835 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
836 mono_w32error_set_last (WSAENOTSOCK);
837 return SOCKET_ERROR;
840 MONO_ENTER_GC_SAFE;
841 ret = getsockname (((MonoFDHandle*) sockethandle)->fd, name, namelen);
842 MONO_EXIT_GC_SAFE;
843 if (ret == -1) {
844 gint errnum = errno;
845 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockname error: %s", __func__, g_strerror (errno));
846 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
847 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
848 return SOCKET_ERROR;
851 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
852 return 0;
855 gint
856 mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen)
858 SocketHandle *sockethandle;
859 gint ret;
860 struct timeval tv;
861 gpointer tmp_val;
863 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
864 mono_w32error_set_last (WSAENOTSOCK);
865 return SOCKET_ERROR;
868 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
869 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
870 mono_w32error_set_last (WSAENOTSOCK);
871 return SOCKET_ERROR;
874 tmp_val = optval;
875 if (level == SOL_SOCKET &&
876 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
877 tmp_val = &tv;
878 *optlen = sizeof (tv);
881 MONO_ENTER_GC_SAFE;
882 ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, level, optname, tmp_val, optlen);
883 MONO_EXIT_GC_SAFE;
884 if (ret == -1) {
885 gint errnum = errno;
886 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockopt error: %s", __func__, g_strerror (errno));
887 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
888 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
889 return SOCKET_ERROR;
892 if (level == SOL_SOCKET && (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
893 *((int *) optval) = tv.tv_sec * 1000 + (tv.tv_usec / 1000); // milli from micro
894 *optlen = sizeof (int);
897 if (optname == SO_ERROR) {
898 if (*((int *)optval) != 0) {
899 *((int *) optval) = mono_w32socket_convert_error (*((int *)optval));
900 sockethandle->saved_error = *((int *)optval);
901 } else {
902 *((int *)optval) = sockethandle->saved_error;
906 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
907 return 0;
910 gint
911 mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, gconstpointer optval, socklen_t optlen)
913 SocketHandle *sockethandle;
914 gint ret;
915 gconstpointer tmp_val;
916 #if defined (__linux__)
917 /* This has its address taken so it cannot be moved to the if block which uses it */
918 gint bufsize = 0;
919 #endif
920 struct timeval tv;
922 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
923 mono_w32error_set_last (WSAENOTSOCK);
924 return SOCKET_ERROR;
927 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
928 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
929 mono_w32error_set_last (WSAENOTSOCK);
930 return SOCKET_ERROR;
933 tmp_val = optval;
934 if (level == SOL_SOCKET &&
935 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
936 int ms = *((int *) optval);
937 tv.tv_sec = ms / 1000;
938 tv.tv_usec = (ms % 1000) * 1000; // micro from milli
939 tmp_val = &tv;
940 optlen = sizeof (tv);
942 #if defined (__linux__)
943 else if (level == SOL_SOCKET &&
944 (optname == SO_SNDBUF || optname == SO_RCVBUF)) {
945 /* According to socket(7) the Linux kernel doubles the
946 * buffer sizes "to allow space for bookkeeping
947 * overhead."
949 bufsize = *((int *) optval);
951 bufsize /= 2;
952 tmp_val = &bufsize;
954 #endif
956 MONO_ENTER_GC_SAFE;
957 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, level, optname, tmp_val, optlen);
958 MONO_EXIT_GC_SAFE;
959 if (ret == -1) {
960 gint errnum = errno;
961 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: setsockopt error: %s", __func__, g_strerror (errno));
962 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
963 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
964 return SOCKET_ERROR;
967 #if defined (SO_REUSEPORT)
968 /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */
969 if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
970 int type;
971 socklen_t type_len = sizeof (type);
973 MONO_ENTER_GC_SAFE;
974 ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, level, SO_TYPE, &type, &type_len);
975 MONO_EXIT_GC_SAFE;
976 if (!ret) {
977 if (type == SOCK_DGRAM || type == SOCK_STREAM) {
978 MONO_ENTER_GC_SAFE;
979 setsockopt (((MonoFDHandle*) sockethandle)->fd, level, SO_REUSEPORT, tmp_val, optlen);
980 MONO_EXIT_GC_SAFE;
984 #endif
986 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
987 return ret;
990 gint
991 mono_w32socket_listen (SOCKET sock, gint backlog)
993 SocketHandle *sockethandle;
994 gint ret;
996 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
997 mono_w32error_set_last (WSAENOTSOCK);
998 return SOCKET_ERROR;
1001 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1002 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1003 mono_w32error_set_last (WSAENOTSOCK);
1004 return SOCKET_ERROR;
1007 MONO_ENTER_GC_SAFE;
1008 ret = listen (((MonoFDHandle*) sockethandle)->fd, backlog);
1009 MONO_EXIT_GC_SAFE;
1010 if (ret == -1) {
1011 gint errnum = errno;
1012 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: listen error: %s", __func__, g_strerror (errno));
1013 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1014 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1015 return SOCKET_ERROR;
1018 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1019 return 0;
1022 gint
1023 mono_w32socket_shutdown (SOCKET sock, gint how)
1025 SocketHandle *sockethandle;
1026 gint ret;
1028 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1029 mono_w32error_set_last (WSAENOTSOCK);
1030 return SOCKET_ERROR;
1033 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1034 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1035 mono_w32error_set_last (WSAENOTSOCK);
1036 return SOCKET_ERROR;
1039 if (how == SHUT_RD || how == SHUT_RDWR)
1040 sockethandle->still_readable = 0;
1042 MONO_ENTER_GC_SAFE;
1043 ret = shutdown (((MonoFDHandle*) sockethandle)->fd, how);
1044 MONO_EXIT_GC_SAFE;
1045 if (ret == -1) {
1046 gint errnum = errno;
1047 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: shutdown error: %s", __func__, g_strerror (errno));
1048 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1049 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1050 return SOCKET_ERROR;
1053 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1054 return ret;
1057 gint
1058 mono_w32socket_disconnect (SOCKET sock, gboolean reuse)
1060 SocketHandle *sockethandle;
1061 SOCKET newsock;
1062 gint ret;
1064 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: called on socket %d!", __func__, sock);
1066 /* We could check the socket type here and fail unless its
1067 * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn)
1068 * if we really wanted to */
1070 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1071 mono_w32error_set_last (WSAENOTSOCK);
1072 return SOCKET_ERROR;
1075 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1076 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1077 mono_w32error_set_last (WSAENOTSOCK);
1078 return SOCKET_ERROR;
1081 MONO_ENTER_GC_SAFE;
1082 newsock = socket (sockethandle->domain, sockethandle->type, sockethandle->protocol);
1083 MONO_EXIT_GC_SAFE;
1084 if (newsock == -1) {
1085 gint errnum = errno;
1086 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: socket error: %s", __func__, g_strerror (errnum));
1087 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1088 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1089 return SOCKET_ERROR;
1092 /* According to Stevens "Advanced Programming in the UNIX
1093 * Environment: UNIX File I/O" dup2() is atomic so there
1094 * should not be a race condition between the old fd being
1095 * closed and the new socket fd being copied over */
1096 do {
1097 MONO_ENTER_GC_SAFE;
1098 ret = dup2 (newsock, ((MonoFDHandle*) sockethandle)->fd);
1099 MONO_EXIT_GC_SAFE;
1100 } while (ret == -1 && errno == EAGAIN);
1102 if (ret == -1) {
1103 gint errnum = errno;
1104 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: dup2 error: %s", __func__, g_strerror (errnum));
1105 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1106 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1107 return SOCKET_ERROR;
1110 MONO_ENTER_GC_SAFE;
1111 close (newsock);
1112 MONO_EXIT_GC_SAFE;
1114 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1115 return 0;
1118 static gboolean
1119 extension_disconect (SOCKET sock, OVERLAPPED *overlapped, guint32 flags, guint32 reserved)
1121 gboolean ret;
1122 MONO_ENTER_GC_UNSAFE;
1123 ret = mono_w32socket_disconnect (sock, flags & TF_REUSE_SOCKET) == 0;
1124 MONO_EXIT_GC_UNSAFE;
1125 return ret;
1128 static gboolean
1129 extension_transmit_file (SOCKET sock, gpointer file_handle, guint32 bytes_to_write, guint32 bytes_per_send,
1130 OVERLAPPED *ol, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags)
1132 gboolean ret;
1133 MONO_ENTER_GC_UNSAFE;
1134 ret = mono_w32socket_transmit_file (sock, file_handle, buffers, flags, FALSE);
1135 MONO_EXIT_GC_UNSAFE;
1136 return ret;
1139 const
1140 static struct {
1141 GUID guid;
1142 gpointer func;
1143 } extension_functions[] = {
1144 { {0x7fda2e11,0x8630,0x436f,{0xa0,0x31,0xf5,0x36,0xa6,0xee,0xc1,0x57}} /* WSAID_DISCONNECTEX */, (gpointer)extension_disconect },
1145 { {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} /* WSAID_TRANSMITFILE */, (gpointer)extension_transmit_file },
1146 { {0} , NULL },
1149 gint
1150 mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written)
1152 SocketHandle *sockethandle;
1153 gint ret;
1154 gpointer buffer;
1156 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1157 mono_w32error_set_last (WSAENOTSOCK);
1158 return SOCKET_ERROR;
1161 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1162 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1163 mono_w32error_set_last (WSAENOTSOCK);
1164 return SOCKET_ERROR;
1167 if (command == 0xC8000006 /* SIO_GET_EXTENSION_FUNCTION_POINTER */) {
1168 gint i;
1169 GUID *guid;
1171 if (inputlen < sizeof(GUID)) {
1172 /* As far as I can tell, windows doesn't
1173 * actually set an error here...
1175 mono_w32socket_set_last_error (WSAEINVAL);
1176 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1177 return SOCKET_ERROR;
1180 if (outputlen < sizeof(gpointer)) {
1181 /* Or here... */
1182 mono_w32socket_set_last_error (WSAEINVAL);
1183 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1184 return SOCKET_ERROR;
1187 if (output == NULL) {
1188 /* Or here */
1189 mono_w32socket_set_last_error (WSAEINVAL);
1190 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1191 return SOCKET_ERROR;
1194 guid = (GUID*) input;
1195 for (i = 0; extension_functions[i].func; i++) {
1196 if (memcmp (guid, &extension_functions[i].guid, sizeof(GUID)) == 0) {
1197 memcpy (output, &extension_functions[i].func, sizeof(gpointer));
1198 *written = sizeof(gpointer);
1199 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1200 return 0;
1204 mono_w32socket_set_last_error (WSAEINVAL);
1205 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1206 return SOCKET_ERROR;
1209 if (command == 0x98000004 /* SIO_KEEPALIVE_VALS */) {
1210 guint32 onoff;
1212 if (inputlen < 3 * sizeof (guint32)) {
1213 mono_w32socket_set_last_error (WSAEINVAL);
1214 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1215 return SOCKET_ERROR;
1218 onoff = *((guint32*) input);
1220 MONO_ENTER_GC_SAFE;
1221 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (guint32));
1222 MONO_EXIT_GC_SAFE;
1223 if (ret < 0) {
1224 mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
1225 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1226 return SOCKET_ERROR;
1229 #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
1230 if (onoff != 0) {
1231 /* Values are in ms, but we need s */
1232 guint32 keepalivetime, keepaliveinterval, rem;
1234 keepalivetime = *(((guint32*) input) + 1);
1235 keepaliveinterval = *(((guint32*) input) + 2);
1237 /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */
1238 rem = keepalivetime % 1000;
1239 keepalivetime /= 1000;
1240 if (keepalivetime == 0 || rem >= 500)
1241 keepalivetime++;
1242 MONO_ENTER_GC_SAFE;
1243 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (guint32));
1244 MONO_EXIT_GC_SAFE;
1245 if (ret == 0) {
1246 rem = keepaliveinterval % 1000;
1247 keepaliveinterval /= 1000;
1248 if (keepaliveinterval == 0 || rem >= 500)
1249 keepaliveinterval++;
1250 MONO_ENTER_GC_SAFE;
1251 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (guint32));
1252 MONO_EXIT_GC_SAFE;
1254 if (ret != 0) {
1255 mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
1256 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1257 return SOCKET_ERROR;
1260 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1261 return 0;
1263 #endif
1265 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1266 return 0;
1269 buffer = inputlen > 0 ? (gchar*) g_memdup (input, inputlen) : NULL;
1271 MONO_ENTER_GC_SAFE;
1272 ret = ioctl (((MonoFDHandle*) sockethandle)->fd, command, buffer);
1273 MONO_EXIT_GC_SAFE;
1274 if (ret == -1) {
1275 g_free (buffer);
1277 gint errnum = errno;
1278 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: WSAIoctl error: %s", __func__, g_strerror (errno));
1279 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1280 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1281 return SOCKET_ERROR;
1284 if (!buffer) {
1285 *written = 0;
1286 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1287 return 0;
1290 /* We just copy the buffer to the output. Some ioctls
1291 * don't even output any data, but, well...
1293 * NB windows returns WSAEFAULT if outputlen is too small */
1294 inputlen = (inputlen > outputlen) ? outputlen : inputlen;
1296 if (inputlen > 0 && output != NULL)
1297 memcpy (output, buffer, inputlen);
1299 g_free (buffer);
1300 *written = inputlen;
1302 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1303 return 0;
1306 gboolean
1307 mono_w32socket_close (SOCKET sock)
1309 if (!mono_fdhandle_close (sock)) {
1310 mono_w32error_set_last (ERROR_INVALID_HANDLE);
1311 return FALSE;
1314 return TRUE;
1317 gint
1318 mono_w32socket_set_blocking (SOCKET sock, gboolean blocking)
1320 #ifdef O_NONBLOCK
1321 SocketHandle *sockethandle;
1322 gint ret;
1324 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1325 mono_w32error_set_last (WSAENOTSOCK);
1326 return SOCKET_ERROR;
1329 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1330 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1331 mono_w32error_set_last (WSAENOTSOCK);
1332 return SOCKET_ERROR;
1335 /* This works better than ioctl(...FIONBIO...)
1336 * on Linux (it causes connect to return
1337 * EINPROGRESS, but the ioctl doesn't seem to) */
1338 MONO_ENTER_GC_SAFE;
1339 ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_GETFL, 0);
1340 MONO_EXIT_GC_SAFE;
1341 if (ret == -1) {
1342 gint errnum = mono_w32socket_convert_error (errno);
1343 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: fcntl(F_GETFL) error: %s", __func__, g_strerror (errno));
1344 mono_w32socket_set_last_error (errnum);
1345 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1346 return SOCKET_ERROR;
1349 MONO_ENTER_GC_SAFE;
1350 ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_SETFL, blocking ? (ret & (~O_NONBLOCK)) : (ret | (O_NONBLOCK)));
1351 MONO_EXIT_GC_SAFE;
1352 if (ret == -1) {
1353 gint errnum = mono_w32socket_convert_error (errno);
1354 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: fcntl(F_SETFL) error: %s", __func__, g_strerror (errno));
1355 mono_w32socket_set_last_error (errnum);
1356 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1357 return SOCKET_ERROR;
1360 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1361 return 0;
1362 #else
1363 mono_w32socket_set_last_error (ERROR_NOT_SUPPORTED);
1364 return SOCKET_ERROR;
1365 #endif /* O_NONBLOCK */
1368 gint
1369 mono_w32socket_get_available (SOCKET sock, guint64 *amount)
1371 SocketHandle *sockethandle;
1372 gint ret;
1374 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1375 mono_w32error_set_last (WSAENOTSOCK);
1376 return SOCKET_ERROR;
1379 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1380 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1381 mono_w32error_set_last (WSAENOTSOCK);
1382 return SOCKET_ERROR;
1385 #if defined (HOST_DARWIN)
1386 // ioctl (socket, FIONREAD, XXX) returns the size of
1387 // the UDP header as well on Darwin.
1389 // Use getsockopt SO_NREAD instead to get the
1390 // right values for TCP and UDP.
1392 // ai_canonname can be null in some cases on darwin,
1393 // where the runtime assumes it will be the value of
1394 // the ip buffer.
1396 socklen_t optlen = sizeof (int);
1397 MONO_ENTER_GC_SAFE;
1398 ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_NREAD, (gulong*) amount, &optlen);
1399 MONO_EXIT_GC_SAFE;
1400 if (ret == -1) {
1401 gint errnum = mono_w32socket_convert_error (errno);
1402 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockopt error: %s", __func__, g_strerror (errno));
1403 mono_w32socket_set_last_error (errnum);
1404 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1405 return SOCKET_ERROR;
1407 #else
1408 MONO_ENTER_GC_SAFE;
1409 ret = ioctl (((MonoFDHandle*) sockethandle)->fd, FIONREAD, (gulong*) amount);
1410 MONO_EXIT_GC_SAFE;
1411 if (ret == -1) {
1412 gint errnum = mono_w32socket_convert_error (errno);
1413 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: ioctl error: %s", __func__, g_strerror (errno));
1414 mono_w32socket_set_last_error (errnum);
1415 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1416 return SOCKET_ERROR;
1418 #endif
1420 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1421 return 0;
1424 void
1425 mono_w32socket_set_last_error (gint32 error)
1427 mono_w32error_set_last (error);
1430 gint32
1431 mono_w32socket_get_last_error (void)
1433 return mono_w32error_get_last ();
1436 gint32
1437 mono_w32socket_convert_error (gint error)
1439 switch (error) {
1440 case 0: return ERROR_SUCCESS;
1441 case EACCES: return WSAEACCES;
1442 #ifdef EADDRINUSE
1443 case EADDRINUSE: return WSAEADDRINUSE;
1444 #endif
1445 #ifdef EAFNOSUPPORT
1446 case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
1447 #endif
1448 #if EAGAIN != EWOULDBLOCK
1449 case EAGAIN: return WSAEWOULDBLOCK;
1450 #endif
1451 #ifdef EALREADY
1452 case EALREADY: return WSAEALREADY;
1453 #endif
1454 case EBADF: return WSAENOTSOCK;
1455 #ifdef ECONNABORTED
1456 case ECONNABORTED: return WSAENETDOWN;
1457 #endif
1458 #ifdef ECONNREFUSED
1459 case ECONNREFUSED: return WSAECONNREFUSED;
1460 #endif
1461 #ifdef ECONNRESET
1462 case ECONNRESET: return WSAECONNRESET;
1463 #endif
1464 case EDOM: return WSAEINVAL; /* not a precise match, best wecan do. */
1465 case EFAULT: return WSAEFAULT;
1466 #ifdef EHOSTUNREACH
1467 case EHOSTUNREACH: return WSAEHOSTUNREACH;
1468 #endif
1469 #ifdef EINPROGRESS
1470 case EINPROGRESS: return WSAEINPROGRESS;
1471 #endif
1472 case EINTR: return WSAEINTR;
1473 case EINVAL: return WSAEINVAL;
1474 case EIO: return WSA_INVALID_HANDLE; /* not a precise match, best we can do. */
1475 #ifdef EISCONN
1476 case EISCONN: return WSAEISCONN;
1477 #endif
1478 case ELOOP: return WSAELOOP;
1479 case ENFILE: return WSAEMFILE; /* not a precise match, best we can do. */
1480 case EMFILE: return WSAEMFILE;
1481 #ifdef EMSGSIZE
1482 case EMSGSIZE: return WSAEMSGSIZE;
1483 #endif
1484 case ENAMETOOLONG: return WSAENAMETOOLONG;
1485 #ifdef ENETUNREACH
1486 case ENETUNREACH: return WSAENETUNREACH;
1487 #endif
1488 #ifdef ENOBUFS
1489 case ENOBUFS: return WSAENOBUFS; /* not documented */
1490 #endif
1491 case ENOMEM: return WSAENOBUFS;
1492 #ifdef ENOPROTOOPT
1493 case ENOPROTOOPT: return WSAENOPROTOOPT;
1494 #endif
1495 #ifdef ENOSR
1496 case ENOSR: return WSAENETDOWN;
1497 #endif
1498 #ifdef ENOTCONN
1499 case ENOTCONN: return WSAENOTCONN;
1500 #endif
1501 case ENOTDIR: return WSA_INVALID_PARAMETER; /* not a precise match, best we can do. */
1502 #ifdef ENOTSOCK
1503 case ENOTSOCK: return WSAENOTSOCK;
1504 #endif
1505 case ENOTTY: return WSAENOTSOCK;
1506 #ifdef EOPNOTSUPP
1507 case EOPNOTSUPP: return WSAEOPNOTSUPP;
1508 #endif
1509 case EPERM: return WSAEACCES;
1510 case EPIPE: return WSAESHUTDOWN;
1511 #ifdef EPROTONOSUPPORT
1512 case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
1513 #endif
1514 #if ERESTARTSYS
1515 case ERESTARTSYS: return WSAENETDOWN;
1516 #endif
1517 /*FIXME: case EROFS: return WSAE????; */
1518 #ifdef ESOCKTNOSUPPORT
1519 case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
1520 #endif
1521 #ifdef ETIMEDOUT
1522 case ETIMEDOUT: return WSAETIMEDOUT;
1523 #endif
1524 #ifdef EWOULDBLOCK
1525 case EWOULDBLOCK: return WSAEWOULDBLOCK;
1526 #endif
1527 #ifdef EADDRNOTAVAIL
1528 case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
1529 #endif
1530 /* This might happen with unix sockets */
1531 case ENOENT: return WSAECONNREFUSED;
1532 #ifdef EDESTADDRREQ
1533 case EDESTADDRREQ: return WSAEDESTADDRREQ;
1534 #endif
1535 #ifdef EHOSTDOWN
1536 case EHOSTDOWN: return WSAEHOSTDOWN;
1537 #endif
1538 #ifdef ENETDOWN
1539 case ENETDOWN: return WSAENETDOWN;
1540 #endif
1541 case ENODEV: return WSAENETDOWN;
1542 #ifdef EPROTOTYPE
1543 case EPROTOTYPE: return WSAEPROTOTYPE;
1544 #endif
1545 #ifdef ENXIO
1546 case ENXIO: return WSAENXIO;
1547 #endif
1548 #ifdef ENONET
1549 case ENONET: return WSAENETUNREACH;
1550 #endif
1551 default:
1552 g_error ("%s: no translation into winsock error for (%d) \"%s\"", __func__, error, g_strerror (error));
1556 #ifndef ENABLE_NETCORE
1557 MonoBoolean
1558 ves_icall_System_Net_Sockets_Socket_SupportPortReuse_icall (MonoProtocolType proto)
1560 #if defined (SO_REUSEPORT)
1561 return TRUE;
1562 #else
1563 #ifdef __linux__
1564 /* Linux always supports double binding for UDP, even on older kernels. */
1565 if (proto == ProtocolType_Udp)
1566 return TRUE;
1567 #endif
1568 return FALSE;
1569 #endif
1571 #endif
1573 gboolean
1574 mono_w32socket_duplicate (gpointer handle, gint32 targetProcessId, gpointer *duplicate_handle)
1576 SocketHandle *sockethandle;
1578 if (!mono_fdhandle_lookup_and_ref (GPOINTER_TO_INT(handle), (MonoFDHandle**) &sockethandle)) {
1579 mono_w32error_set_last (ERROR_INVALID_HANDLE);
1580 return FALSE;
1583 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1584 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1585 mono_w32error_set_last (ERROR_INVALID_HANDLE);
1586 return FALSE;
1589 *duplicate_handle = handle;
1590 return TRUE;