[csproj] Fix diff rendering when XML comments appear in the diff (#8642)
[mono-project.git] / mono / metadata / w32socket-unix.c
blobd675b53e66a93ad51a2b23a5fd446904ba43bfbe
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 #include <arpa/inet.h>
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #include <errno.h>
30 #include <fcntl.h>
31 #ifdef HAVE_SYS_UIO_H
32 #include <sys/uio.h>
33 #endif
34 #ifdef HAVE_SYS_IOCTL_H
35 #include <sys/ioctl.h>
36 #endif
37 #ifdef HAVE_SYS_FILIO_H
38 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
39 #endif
40 #ifdef HAVE_SYS_SOCKIO_H
41 #include <sys/sockio.h> /* defines SIOCATMARK */
42 #endif
43 #ifndef HAVE_MSG_NOSIGNAL
44 #include <signal.h>
45 #endif
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"
59 typedef struct {
60 MonoFDHandle fdhandle;
61 gint domain;
62 gint type;
63 gint protocol;
64 gint saved_error;
65 gint still_readable;
66 } SocketHandle;
68 static SocketHandle*
69 socket_data_create (MonoFDType type, gint fd)
71 SocketHandle *sockethandle;
73 sockethandle = g_new0 (SocketHandle, 1);
74 mono_fdhandle_init ((MonoFDHandle*) sockethandle, type, fd);
76 return sockethandle;
79 static void
80 socket_data_close (MonoFDHandle *fdhandle)
82 MonoThreadInfo *info;
83 SocketHandle* sockethandle;
84 gint ret;
86 sockethandle = (SocketHandle*) fdhandle;
87 g_assert (sockethandle);
89 info = mono_thread_info_current ();
91 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: closing fd %d", __func__, ((MonoFDHandle*) sockethandle)->fd);
93 /* Shutdown the socket for reading, to interrupt any potential
94 * receives that may be blocking for data. See bug 75705. */
95 MONO_ENTER_GC_SAFE;
96 shutdown (((MonoFDHandle*) sockethandle)->fd, SHUT_RD);
97 MONO_EXIT_GC_SAFE;
99 retry_close:
100 MONO_ENTER_GC_SAFE;
101 ret = close (((MonoFDHandle*) sockethandle)->fd);
102 MONO_EXIT_GC_SAFE;
103 if (ret == -1) {
104 if (errno == EINTR && !mono_thread_info_is_interrupt_state (info))
105 goto retry_close;
108 sockethandle->saved_error = 0;
111 static void
112 socket_data_destroy (MonoFDHandle *fdhandle)
114 SocketHandle *sockethandle;
116 sockethandle = (SocketHandle*) fdhandle;
117 g_assert (sockethandle);
119 g_free (sockethandle);
122 void
123 mono_w32socket_initialize (void)
125 MonoFDHandleCallback socket_data_callbacks = {
126 .close = socket_data_close,
127 .destroy = socket_data_destroy
130 mono_fdhandle_register (MONO_FDTYPE_SOCKET, &socket_data_callbacks);
133 void
134 mono_w32socket_cleanup (void)
138 SOCKET
139 mono_w32socket_accept (SOCKET sock, struct sockaddr *addr, socklen_t *addrlen, gboolean blocking)
141 SocketHandle *sockethandle, *accepted_socket_data;
142 MonoThreadInfo *info;
143 gint accepted_fd;
145 if (addr != NULL && *addrlen < sizeof(struct sockaddr)) {
146 mono_w32socket_set_last_error (WSAEFAULT);
147 return INVALID_SOCKET;
150 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
151 mono_w32error_set_last (WSAENOTSOCK);
152 return INVALID_SOCKET;
155 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
156 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
157 mono_w32error_set_last (WSAENOTSOCK);
158 return INVALID_SOCKET;
161 info = mono_thread_info_current ();
163 do {
164 MONO_ENTER_GC_SAFE;
165 accepted_fd = accept (((MonoFDHandle*) sockethandle)->fd, addr, addrlen);
166 MONO_EXIT_GC_SAFE;
167 } while (accepted_fd == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
169 if (accepted_fd == -1) {
170 gint error = mono_w32socket_convert_error (errno);
171 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: accept error: %s", __func__, g_strerror(errno));
172 mono_w32socket_set_last_error (error);
173 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
174 return INVALID_SOCKET;
177 accepted_socket_data = socket_data_create (MONO_FDTYPE_SOCKET, accepted_fd);
178 accepted_socket_data->domain = sockethandle->domain;
179 accepted_socket_data->type = sockethandle->type;
180 accepted_socket_data->protocol = sockethandle->protocol;
181 accepted_socket_data->still_readable = 1;
183 mono_fdhandle_insert ((MonoFDHandle*) accepted_socket_data);
185 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));
187 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
188 return ((MonoFDHandle*) accepted_socket_data)->fd;
192 mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, int addrlen, gboolean blocking)
194 SocketHandle *sockethandle;
195 gint ret;
197 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
198 mono_w32error_set_last (WSAENOTSOCK);
199 return SOCKET_ERROR;
202 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
203 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
204 mono_w32error_set_last (WSAENOTSOCK);
205 return SOCKET_ERROR;
208 MONO_ENTER_GC_SAFE;
209 ret = connect (((MonoFDHandle*) sockethandle)->fd, addr, addrlen);
210 MONO_EXIT_GC_SAFE;
211 if (ret == -1) {
212 MonoThreadInfo *info;
213 mono_pollfd fds;
214 gint errnum, so_error;
215 socklen_t len;
217 errnum = errno;
219 if (errno != EINTR) {
220 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect error: %s", __func__,
221 g_strerror (errnum));
223 errnum = mono_w32socket_convert_error (errnum);
224 if (errnum == WSAEINPROGRESS)
225 errnum = WSAEWOULDBLOCK; /* see bug #73053 */
227 mono_w32socket_set_last_error (errnum);
230 * On solaris x86 getsockopt (SO_ERROR) is not set after
231 * connect () fails so we need to save this error.
233 * But don't do this for EWOULDBLOCK (bug 317315)
235 if (errnum != WSAEWOULDBLOCK) {
236 /* ECONNRESET means the socket was closed by another thread */
237 /* Async close on mac raises ECONNABORTED. */
238 sockethandle->saved_error = errnum;
240 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
241 return SOCKET_ERROR;
244 info = mono_thread_info_current ();
246 fds.fd = ((MonoFDHandle*) sockethandle)->fd;
247 fds.events = MONO_POLLOUT;
248 for (;;) {
249 MONO_ENTER_GC_SAFE;
250 ret = mono_poll (&fds, 1, -1);
251 MONO_EXIT_GC_SAFE;
252 if (ret != -1 || mono_thread_info_is_interrupt_state (info))
253 break;
255 if (errno != EINTR) {
256 gint errnum = errno;
257 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect poll error: %s", __func__, g_strerror (errno));
258 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
259 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
260 return SOCKET_ERROR;
264 len = sizeof(so_error);
265 MONO_ENTER_GC_SAFE;
266 ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_ERROR, &so_error, &len);
267 MONO_EXIT_GC_SAFE;
268 if (ret == -1) {
269 gint errnum = errno;
270 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect getsockopt error: %s", __func__, g_strerror (errno));
271 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
272 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
273 return SOCKET_ERROR;
276 if (so_error != 0) {
277 gint errnum = mono_w32socket_convert_error (so_error);
279 /* Need to save this socket error */
280 sockethandle->saved_error = errnum;
282 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect getsockopt returned error: %s",
283 __func__, g_strerror (so_error));
285 mono_w32socket_set_last_error (errnum);
286 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
287 return SOCKET_ERROR;
291 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
292 return 0;
296 mono_w32socket_recv (SOCKET sock, char *buf, int len, int flags, gboolean blocking)
298 return mono_w32socket_recvfrom (sock, buf, len, flags, NULL, 0, blocking);
302 mono_w32socket_recvfrom (SOCKET sock, char *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, gboolean blocking)
304 SocketHandle *sockethandle;
305 int ret;
306 MonoThreadInfo *info;
308 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
309 mono_w32error_set_last (WSAENOTSOCK);
310 return SOCKET_ERROR;
313 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
314 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
315 mono_w32error_set_last (WSAENOTSOCK);
316 return SOCKET_ERROR;
319 info = mono_thread_info_current ();
321 do {
322 MONO_ENTER_GC_SAFE;
323 ret = recvfrom (((MonoFDHandle*) sockethandle)->fd, buf, len, flags, from, fromlen);
324 MONO_EXIT_GC_SAFE;
325 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
327 if (ret == 0 && len > 0) {
328 /* According to the Linux man page, recvfrom only
329 * returns 0 when the socket has been shut down
330 * cleanly. Turn this into an EINTR to simulate win32
331 * behaviour of returning EINTR when a socket is
332 * closed while the recvfrom is blocking (we use a
333 * shutdown() in socket_close() to trigger this.) See
334 * bug 75705.
336 /* Distinguish between the socket being shut down at
337 * the local or remote ends, and reads that request 0
338 * bytes to be read
341 /* If this returns FALSE, it means the socket has been
342 * closed locally. If it returns TRUE, but
343 * still_readable != 1 then shutdown
344 * (SHUT_RD|SHUT_RDWR) has been called locally.
346 if (sockethandle->still_readable != 1) {
347 ret = -1;
348 errno = EINTR;
352 if (ret == -1) {
353 gint errnum = errno;
354 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: recv error: %s", __func__, g_strerror(errno));
355 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
356 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
357 return SOCKET_ERROR;
359 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
360 return ret;
363 static void
364 wsabuf_to_msghdr (WSABUF *buffers, guint32 count, struct msghdr *hdr)
366 guint32 i;
368 memset (hdr, 0, sizeof (struct msghdr));
369 hdr->msg_iovlen = count;
370 hdr->msg_iov = g_new0 (struct iovec, count);
371 for (i = 0; i < count; i++) {
372 hdr->msg_iov [i].iov_base = buffers [i].buf;
373 hdr->msg_iov [i].iov_len = buffers [i].len;
377 static void
378 msghdr_iov_free (struct msghdr *hdr)
380 g_free (hdr->msg_iov);
384 mono_w32socket_recvbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *received, guint32 *flags, gpointer overlapped, gpointer complete, gboolean blocking)
386 SocketHandle *sockethandle;
387 MonoThreadInfo *info;
388 gint ret;
389 struct msghdr hdr;
391 g_assert (overlapped == NULL);
392 g_assert (complete == NULL);
394 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
395 mono_w32error_set_last (WSAENOTSOCK);
396 return SOCKET_ERROR;
399 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
400 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
401 mono_w32error_set_last (WSAENOTSOCK);
402 return SOCKET_ERROR;
405 info = mono_thread_info_current ();
407 wsabuf_to_msghdr (buffers, count, &hdr);
409 do {
410 MONO_ENTER_GC_SAFE;
411 ret = recvmsg (((MonoFDHandle*) sockethandle)->fd, &hdr, *flags);
412 MONO_EXIT_GC_SAFE;
413 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
415 msghdr_iov_free (&hdr);
417 if (ret == 0) {
418 /* see mono_w32socket_recvfrom */
419 if (sockethandle->still_readable != 1) {
420 ret = -1;
421 errno = EINTR;
425 if (ret == -1) {
426 gint errnum = errno;
427 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: recvmsg error: %s", __func__, g_strerror(errno));
428 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
429 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
430 return SOCKET_ERROR;
433 *received = ret;
434 *flags = hdr.msg_flags;
436 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
437 return 0;
441 mono_w32socket_send (SOCKET sock, char *buf, int len, int flags, gboolean blocking)
443 SocketHandle *sockethandle;
444 int ret;
445 MonoThreadInfo *info;
447 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
448 mono_w32error_set_last (WSAENOTSOCK);
449 return SOCKET_ERROR;
452 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
453 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
454 mono_w32error_set_last (WSAENOTSOCK);
455 return SOCKET_ERROR;
458 info = mono_thread_info_current ();
460 do {
461 MONO_ENTER_GC_SAFE;
462 ret = send (((MonoFDHandle*) sockethandle)->fd, buf, len, flags);
463 MONO_EXIT_GC_SAFE;
464 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
466 if (ret == -1) {
467 gint errnum = errno;
468 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: send error: %s", __func__, g_strerror (errno));
470 #ifdef O_NONBLOCK
471 /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on
472 * a blocking socket. See bug #599488 */
473 if (errnum == EAGAIN) {
474 MONO_ENTER_GC_SAFE;
475 ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_GETFL, 0);
476 MONO_EXIT_GC_SAFE;
477 if (ret != -1 && (ret & O_NONBLOCK) == 0)
478 errnum = ETIMEDOUT;
480 #endif /* O_NONBLOCK */
481 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
482 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
483 return SOCKET_ERROR;
485 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
486 return ret;
490 mono_w32socket_sendto (SOCKET sock, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking)
492 SocketHandle *sockethandle;
493 int ret;
494 MonoThreadInfo *info;
496 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
497 mono_w32error_set_last (WSAENOTSOCK);
498 return SOCKET_ERROR;
501 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
502 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
503 mono_w32error_set_last (WSAENOTSOCK);
504 return SOCKET_ERROR;
507 info = mono_thread_info_current ();
509 do {
510 MONO_ENTER_GC_SAFE;
511 ret = sendto (((MonoFDHandle*) sockethandle)->fd, buf, len, flags, to, tolen);
512 MONO_EXIT_GC_SAFE;
513 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
515 if (ret == -1) {
516 gint errnum = errno;
517 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: send error: %s", __func__, g_strerror (errno));
518 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
519 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
520 return SOCKET_ERROR;
522 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
523 return ret;
527 mono_w32socket_sendbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *sent, guint32 flags, gpointer overlapped, gpointer complete, gboolean blocking)
529 struct msghdr hdr;
530 MonoThreadInfo *info;
531 SocketHandle *sockethandle;
532 gint ret;
534 g_assert (overlapped == NULL);
535 g_assert (complete == NULL);
537 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
538 mono_w32error_set_last (WSAENOTSOCK);
539 return SOCKET_ERROR;
542 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
543 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
544 mono_w32error_set_last (WSAENOTSOCK);
545 return SOCKET_ERROR;
548 info = mono_thread_info_current ();
550 wsabuf_to_msghdr (buffers, count, &hdr);
552 do {
553 MONO_ENTER_GC_SAFE;
554 ret = sendmsg (((MonoFDHandle*) sockethandle)->fd, &hdr, flags);
555 MONO_EXIT_GC_SAFE;
556 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
558 msghdr_iov_free (&hdr);
560 if (ret == -1) {
561 gint errnum = errno;
562 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: sendmsg error: %s", __func__, g_strerror (errno));
563 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
564 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
565 return SOCKET_ERROR;
568 *sent = ret;
569 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
570 return 0;
573 #define SF_BUFFER_SIZE 16384
575 BOOL
576 mono_w32socket_transmit_file (SOCKET sock, gpointer file_handle, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags, gboolean blocking)
578 MonoThreadInfo *info;
579 SocketHandle *sockethandle;
580 gint file;
581 gssize ret;
582 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
583 struct stat statbuf;
584 #else
585 gchar *buffer;
586 #endif
588 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
589 mono_w32error_set_last (WSAENOTSOCK);
590 return SOCKET_ERROR;
593 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
594 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
595 mono_w32error_set_last (WSAENOTSOCK);
596 return SOCKET_ERROR;
599 /* Write the header */
600 if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) {
601 ret = mono_w32socket_send (((MonoFDHandle*) sockethandle)->fd, buffers->Head, buffers->HeadLength, 0, FALSE);
602 if (ret == SOCKET_ERROR) {
603 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
604 return FALSE;
608 info = mono_thread_info_current ();
610 file = GPOINTER_TO_INT (file_handle);
612 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
613 MONO_ENTER_GC_SAFE;
614 ret = fstat (file, &statbuf);
615 MONO_EXIT_GC_SAFE;
616 if (ret == -1) {
617 gint errnum = errno;
618 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
619 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
620 return SOCKET_ERROR;
623 do {
624 MONO_ENTER_GC_SAFE;
625 #ifdef __linux__
626 ret = sendfile (((MonoFDHandle*) sockethandle)->fd, file, NULL, statbuf.st_size);
627 #elif defined(DARWIN)
628 /* TODO: header/tail could be sent in the 5th argument */
629 /* TODO: Might not send the entire file for non-blocking sockets */
630 ret = sendfile (file, ((MonoFDHandle*) sockethandle)->fd, 0, &statbuf.st_size, NULL, 0);
631 #endif
632 MONO_EXIT_GC_SAFE;
633 } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
634 #else
635 buffer = g_malloc (SF_BUFFER_SIZE);
637 do {
638 do {
639 MONO_ENTER_GC_SAFE;
640 ret = read (file, buffer, SF_BUFFER_SIZE);
641 MONO_EXIT_GC_SAFE;
642 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
644 if (ret == -1 || ret == 0)
645 break;
647 do {
648 MONO_ENTER_GC_SAFE;
649 ret = send (((MonoFDHandle*) sockethandle)->fd, buffer, ret, 0); /* short sends? enclose this in a loop? */
650 MONO_EXIT_GC_SAFE;
651 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
652 } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
654 g_free (buffer);
655 #endif
657 if (ret == -1) {
658 gint errnum = errno;
659 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
660 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
661 return FALSE;
664 /* Write the tail */
665 if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) {
666 ret = mono_w32socket_send (((MonoFDHandle*) sockethandle)->fd, buffers->Tail, buffers->TailLength, 0, FALSE);
667 if (ret == SOCKET_ERROR) {
668 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
669 return FALSE;
673 if ((flags & TF_DISCONNECT) == TF_DISCONNECT)
674 mono_w32socket_close (((MonoFDHandle*) sockethandle)->fd);
676 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
677 return TRUE;
680 SOCKET
681 mono_w32socket_socket (int domain, int type, int protocol)
683 SocketHandle *sockethandle;
684 gint fd;
686 retry_socket:
687 MONO_ENTER_GC_SAFE;
688 fd = socket (domain, type, protocol);
689 MONO_EXIT_GC_SAFE;
690 if (fd == -1) {
691 if (domain == AF_INET && type == SOCK_RAW && protocol == 0) {
692 /* Retry with protocol == 4 (see bug #54565) */
693 // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565
694 protocol = 4;
695 goto retry_socket;
698 gint errnum = errno;
699 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: socket error: %s", __func__, g_strerror (errno));
700 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
701 return INVALID_SOCKET;
704 sockethandle = socket_data_create(MONO_FDTYPE_SOCKET, fd);
705 sockethandle->domain = domain;
706 sockethandle->type = type;
707 sockethandle->protocol = protocol;
708 sockethandle->still_readable = 1;
710 /* .net seems to set this by default for SOCK_STREAM, not for
711 * SOCK_DGRAM (see bug #36322)
712 * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322
714 * It seems winsock has a rather different idea of what
715 * SO_REUSEADDR means. If it's set, then a new socket can be
716 * bound over an existing listening socket. There's a new
717 * windows-specific option called SO_EXCLUSIVEADDRUSE but
718 * using that means the socket MUST be closed properly, or a
719 * denial of service can occur. Luckily for us, winsock
720 * behaves as though any other system would when SO_REUSEADDR
721 * is true, so we don't need to do anything else here. See
722 * bug 53992.
723 * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992
726 int ret, true_ = 1;
728 MONO_ENTER_GC_SAFE;
729 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_REUSEADDR, &true_, sizeof (true_));
730 MONO_EXIT_GC_SAFE;
731 if (ret == -1) {
732 gint errnum = errno;
733 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: Error setting SO_REUSEADDR", __func__);
734 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
736 MONO_ENTER_GC_SAFE;
737 close (((MonoFDHandle*) sockethandle)->fd);
738 MONO_EXIT_GC_SAFE;
740 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
741 return INVALID_SOCKET;
745 mono_fdhandle_insert ((MonoFDHandle*) sockethandle);
747 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: returning socket handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) sockethandle)->fd));
749 return ((MonoFDHandle*) sockethandle)->fd;
752 gint
753 mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen)
755 SocketHandle *sockethandle;
756 int ret;
758 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
759 mono_w32error_set_last (WSAENOTSOCK);
760 return SOCKET_ERROR;
763 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
764 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
765 mono_w32error_set_last (WSAENOTSOCK);
766 return SOCKET_ERROR;
769 MONO_ENTER_GC_SAFE;
770 ret = bind (((MonoFDHandle*) sockethandle)->fd, addr, addrlen);
771 MONO_EXIT_GC_SAFE;
772 if (ret == -1) {
773 gint errnum = errno;
774 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: bind error: %s", __func__, g_strerror(errno));
775 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
776 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
777 return SOCKET_ERROR;
780 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
781 return 0;
784 gint
785 mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
787 SocketHandle *sockethandle;
788 gint ret;
790 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
791 mono_w32error_set_last (WSAENOTSOCK);
792 return SOCKET_ERROR;
795 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
796 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
797 mono_w32error_set_last (WSAENOTSOCK);
798 return SOCKET_ERROR;
801 MONO_ENTER_GC_SAFE;
802 ret = getpeername (((MonoFDHandle*) sockethandle)->fd, name, namelen);
803 MONO_EXIT_GC_SAFE;
804 if (ret == -1) {
805 gint errnum = errno;
806 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getpeername error: %s", __func__, g_strerror (errno));
807 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
808 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
809 return SOCKET_ERROR;
812 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
813 return 0;
816 gint
817 mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
819 SocketHandle *sockethandle;
820 gint ret;
822 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
823 mono_w32error_set_last (WSAENOTSOCK);
824 return SOCKET_ERROR;
827 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
828 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
829 mono_w32error_set_last (WSAENOTSOCK);
830 return SOCKET_ERROR;
833 MONO_ENTER_GC_SAFE;
834 ret = getsockname (((MonoFDHandle*) sockethandle)->fd, name, namelen);
835 MONO_EXIT_GC_SAFE;
836 if (ret == -1) {
837 gint errnum = errno;
838 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockname error: %s", __func__, g_strerror (errno));
839 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
840 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
841 return SOCKET_ERROR;
844 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
845 return 0;
848 gint
849 mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen)
851 SocketHandle *sockethandle;
852 gint ret;
853 struct timeval tv;
854 gpointer tmp_val;
856 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
857 mono_w32error_set_last (WSAENOTSOCK);
858 return SOCKET_ERROR;
861 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
862 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
863 mono_w32error_set_last (WSAENOTSOCK);
864 return SOCKET_ERROR;
867 tmp_val = optval;
868 if (level == SOL_SOCKET &&
869 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
870 tmp_val = &tv;
871 *optlen = sizeof (tv);
874 MONO_ENTER_GC_SAFE;
875 ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, level, optname, tmp_val, optlen);
876 MONO_EXIT_GC_SAFE;
877 if (ret == -1) {
878 gint errnum = errno;
879 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockopt error: %s", __func__, g_strerror (errno));
880 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
881 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
882 return SOCKET_ERROR;
885 if (level == SOL_SOCKET && (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
886 *((int *) optval) = tv.tv_sec * 1000 + (tv.tv_usec / 1000); // milli from micro
887 *optlen = sizeof (int);
890 if (optname == SO_ERROR) {
891 if (*((int *)optval) != 0) {
892 *((int *) optval) = mono_w32socket_convert_error (*((int *)optval));
893 sockethandle->saved_error = *((int *)optval);
894 } else {
895 *((int *)optval) = sockethandle->saved_error;
899 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
900 return 0;
903 gint
904 mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, const gpointer optval, socklen_t optlen)
906 SocketHandle *sockethandle;
907 gint ret;
908 gpointer tmp_val;
909 #if defined (__linux__)
910 /* This has its address taken so it cannot be moved to the if block which uses it */
911 gint bufsize = 0;
912 #endif
913 struct timeval tv;
915 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
916 mono_w32error_set_last (WSAENOTSOCK);
917 return SOCKET_ERROR;
920 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
921 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
922 mono_w32error_set_last (WSAENOTSOCK);
923 return SOCKET_ERROR;
926 tmp_val = optval;
927 if (level == SOL_SOCKET &&
928 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
929 int ms = *((int *) optval);
930 tv.tv_sec = ms / 1000;
931 tv.tv_usec = (ms % 1000) * 1000; // micro from milli
932 tmp_val = &tv;
933 optlen = sizeof (tv);
935 #if defined (__linux__)
936 else if (level == SOL_SOCKET &&
937 (optname == SO_SNDBUF || optname == SO_RCVBUF)) {
938 /* According to socket(7) the Linux kernel doubles the
939 * buffer sizes "to allow space for bookkeeping
940 * overhead."
942 bufsize = *((int *) optval);
944 bufsize /= 2;
945 tmp_val = &bufsize;
947 #endif
949 MONO_ENTER_GC_SAFE;
950 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, level, optname, tmp_val, optlen);
951 MONO_EXIT_GC_SAFE;
952 if (ret == -1) {
953 gint errnum = errno;
954 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: setsockopt error: %s", __func__, g_strerror (errno));
955 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
956 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
957 return SOCKET_ERROR;
960 #if defined (SO_REUSEPORT)
961 /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */
962 if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
963 int type;
964 socklen_t type_len = sizeof (type);
966 MONO_ENTER_GC_SAFE;
967 ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, level, SO_TYPE, &type, &type_len);
968 MONO_EXIT_GC_SAFE;
969 if (!ret) {
970 if (type == SOCK_DGRAM || type == SOCK_STREAM) {
971 MONO_ENTER_GC_SAFE;
972 setsockopt (((MonoFDHandle*) sockethandle)->fd, level, SO_REUSEPORT, tmp_val, optlen);
973 MONO_EXIT_GC_SAFE;
977 #endif
979 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
980 return ret;
983 gint
984 mono_w32socket_listen (SOCKET sock, gint backlog)
986 SocketHandle *sockethandle;
987 gint ret;
989 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
990 mono_w32error_set_last (WSAENOTSOCK);
991 return SOCKET_ERROR;
994 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
995 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
996 mono_w32error_set_last (WSAENOTSOCK);
997 return SOCKET_ERROR;
1000 MONO_ENTER_GC_SAFE;
1001 ret = listen (((MonoFDHandle*) sockethandle)->fd, backlog);
1002 MONO_EXIT_GC_SAFE;
1003 if (ret == -1) {
1004 gint errnum = errno;
1005 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: listen error: %s", __func__, g_strerror (errno));
1006 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1007 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1008 return SOCKET_ERROR;
1011 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1012 return 0;
1015 gint
1016 mono_w32socket_shutdown (SOCKET sock, gint how)
1018 SocketHandle *sockethandle;
1019 gint ret;
1021 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1022 mono_w32error_set_last (WSAENOTSOCK);
1023 return SOCKET_ERROR;
1026 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1027 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1028 mono_w32error_set_last (WSAENOTSOCK);
1029 return SOCKET_ERROR;
1032 if (how == SHUT_RD || how == SHUT_RDWR)
1033 sockethandle->still_readable = 0;
1035 MONO_ENTER_GC_SAFE;
1036 ret = shutdown (((MonoFDHandle*) sockethandle)->fd, how);
1037 MONO_EXIT_GC_SAFE;
1038 if (ret == -1) {
1039 gint errnum = errno;
1040 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: shutdown error: %s", __func__, g_strerror (errno));
1041 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1042 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1043 return SOCKET_ERROR;
1046 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1047 return ret;
1050 gint
1051 mono_w32socket_disconnect (SOCKET sock, gboolean reuse)
1053 SocketHandle *sockethandle;
1054 SOCKET newsock;
1055 gint ret;
1057 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: called on socket %d!", __func__, sock);
1059 /* We could check the socket type here and fail unless its
1060 * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn)
1061 * if we really wanted to */
1063 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1064 mono_w32error_set_last (WSAENOTSOCK);
1065 return SOCKET_ERROR;
1068 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1069 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1070 mono_w32error_set_last (WSAENOTSOCK);
1071 return SOCKET_ERROR;
1074 MONO_ENTER_GC_SAFE;
1075 newsock = socket (sockethandle->domain, sockethandle->type, sockethandle->protocol);
1076 MONO_EXIT_GC_SAFE;
1077 if (newsock == -1) {
1078 gint errnum = errno;
1079 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: socket error: %s", __func__, g_strerror (errnum));
1080 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1081 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1082 return SOCKET_ERROR;
1085 /* According to Stevens "Advanced Programming in the UNIX
1086 * Environment: UNIX File I/O" dup2() is atomic so there
1087 * should not be a race condition between the old fd being
1088 * closed and the new socket fd being copied over */
1089 do {
1090 MONO_ENTER_GC_SAFE;
1091 ret = dup2 (newsock, ((MonoFDHandle*) sockethandle)->fd);
1092 MONO_EXIT_GC_SAFE;
1093 } while (ret == -1 && errno == EAGAIN);
1095 if (ret == -1) {
1096 gint errnum = errno;
1097 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: dup2 error: %s", __func__, g_strerror (errnum));
1098 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1099 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1100 return SOCKET_ERROR;
1103 MONO_ENTER_GC_SAFE;
1104 close (newsock);
1105 MONO_EXIT_GC_SAFE;
1107 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1108 return 0;
1111 static gboolean
1112 extension_disconect (SOCKET sock, OVERLAPPED *overlapped, guint32 flags, guint32 reserved)
1114 gboolean ret;
1115 MONO_ENTER_GC_UNSAFE;
1116 ret = mono_w32socket_disconnect (sock, flags & TF_REUSE_SOCKET) == 0;
1117 MONO_EXIT_GC_UNSAFE;
1118 return ret;
1121 static gboolean
1122 extension_transmit_file (SOCKET sock, gpointer file_handle, guint32 bytes_to_write, guint32 bytes_per_send,
1123 OVERLAPPED *ol, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags)
1125 gboolean ret;
1126 MONO_ENTER_GC_UNSAFE;
1127 ret = mono_w32socket_transmit_file (sock, file_handle, buffers, flags, FALSE);
1128 MONO_EXIT_GC_UNSAFE;
1129 return ret;
1132 static struct {
1133 GUID guid;
1134 gpointer func;
1135 } extension_functions[] = {
1136 { {0x7fda2e11,0x8630,0x436f,{0xa0,0x31,0xf5,0x36,0xa6,0xee,0xc1,0x57}} /* WSAID_DISCONNECTEX */, extension_disconect },
1137 { {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} /* WSAID_TRANSMITFILE */, extension_transmit_file },
1138 { {0} , NULL },
1141 gint
1142 mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written)
1144 SocketHandle *sockethandle;
1145 gint ret;
1146 gchar *buffer;
1148 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1149 mono_w32error_set_last (WSAENOTSOCK);
1150 return SOCKET_ERROR;
1153 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1154 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1155 mono_w32error_set_last (WSAENOTSOCK);
1156 return SOCKET_ERROR;
1159 if (command == 0xC8000006 /* SIO_GET_EXTENSION_FUNCTION_POINTER */) {
1160 gint i;
1161 GUID *guid;
1163 if (inputlen < sizeof(GUID)) {
1164 /* As far as I can tell, windows doesn't
1165 * actually set an error here...
1167 mono_w32socket_set_last_error (WSAEINVAL);
1168 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1169 return SOCKET_ERROR;
1172 if (outputlen < sizeof(gpointer)) {
1173 /* Or here... */
1174 mono_w32socket_set_last_error (WSAEINVAL);
1175 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1176 return SOCKET_ERROR;
1179 if (output == NULL) {
1180 /* Or here */
1181 mono_w32socket_set_last_error (WSAEINVAL);
1182 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1183 return SOCKET_ERROR;
1186 guid = (GUID*) input;
1187 for (i = 0; extension_functions[i].func; i++) {
1188 if (memcmp (guid, &extension_functions[i].guid, sizeof(GUID)) == 0) {
1189 memcpy (output, &extension_functions[i].func, sizeof(gpointer));
1190 *written = sizeof(gpointer);
1191 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1192 return 0;
1196 mono_w32socket_set_last_error (WSAEINVAL);
1197 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1198 return SOCKET_ERROR;
1201 if (command == 0x98000004 /* SIO_KEEPALIVE_VALS */) {
1202 guint32 onoff;
1204 if (inputlen < 3 * sizeof (guint32)) {
1205 mono_w32socket_set_last_error (WSAEINVAL);
1206 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1207 return SOCKET_ERROR;
1210 onoff = *((guint32*) input);
1212 MONO_ENTER_GC_SAFE;
1213 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (guint32));
1214 MONO_EXIT_GC_SAFE;
1215 if (ret < 0) {
1216 mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
1217 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1218 return SOCKET_ERROR;
1221 #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
1222 if (onoff != 0) {
1223 /* Values are in ms, but we need s */
1224 guint32 keepalivetime, keepaliveinterval, rem;
1226 keepalivetime = *(((guint32*) input) + 1);
1227 keepaliveinterval = *(((guint32*) input) + 2);
1229 /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */
1230 rem = keepalivetime % 1000;
1231 keepalivetime /= 1000;
1232 if (keepalivetime == 0 || rem >= 500)
1233 keepalivetime++;
1234 MONO_ENTER_GC_SAFE;
1235 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (guint32));
1236 MONO_EXIT_GC_SAFE;
1237 if (ret == 0) {
1238 rem = keepaliveinterval % 1000;
1239 keepaliveinterval /= 1000;
1240 if (keepaliveinterval == 0 || rem >= 500)
1241 keepaliveinterval++;
1242 MONO_ENTER_GC_SAFE;
1243 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (guint32));
1244 MONO_EXIT_GC_SAFE;
1246 if (ret != 0) {
1247 mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
1248 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1249 return SOCKET_ERROR;
1252 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1253 return 0;
1255 #endif
1257 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1258 return 0;
1261 buffer = inputlen > 0 ? (gchar*) g_memdup (input, inputlen) : NULL;
1263 MONO_ENTER_GC_SAFE;
1264 ret = ioctl (((MonoFDHandle*) sockethandle)->fd, command, buffer);
1265 MONO_EXIT_GC_SAFE;
1266 if (ret == -1) {
1267 g_free (buffer);
1269 gint errnum = errno;
1270 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: WSAIoctl error: %s", __func__, g_strerror (errno));
1271 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1272 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1273 return SOCKET_ERROR;
1276 if (!buffer) {
1277 *written = 0;
1278 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1279 return 0;
1282 /* We just copy the buffer to the output. Some ioctls
1283 * don't even output any data, but, well...
1285 * NB windows returns WSAEFAULT if outputlen is too small */
1286 inputlen = (inputlen > outputlen) ? outputlen : inputlen;
1288 if (inputlen > 0 && output != NULL)
1289 memcpy (output, buffer, inputlen);
1291 g_free (buffer);
1292 *written = inputlen;
1294 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1295 return 0;
1298 gboolean
1299 mono_w32socket_close (SOCKET sock)
1301 if (!mono_fdhandle_close (sock)) {
1302 mono_w32error_set_last (ERROR_INVALID_HANDLE);
1303 return FALSE;
1306 return TRUE;
1309 gint
1310 mono_w32socket_set_blocking (SOCKET sock, gboolean blocking)
1312 #ifdef O_NONBLOCK
1313 SocketHandle *sockethandle;
1314 gint ret;
1316 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1317 mono_w32error_set_last (WSAENOTSOCK);
1318 return SOCKET_ERROR;
1321 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1322 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1323 mono_w32error_set_last (WSAENOTSOCK);
1324 return SOCKET_ERROR;
1327 /* This works better than ioctl(...FIONBIO...)
1328 * on Linux (it causes connect to return
1329 * EINPROGRESS, but the ioctl doesn't seem to) */
1330 MONO_ENTER_GC_SAFE;
1331 ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_GETFL, 0);
1332 MONO_EXIT_GC_SAFE;
1333 if (ret == -1) {
1334 gint errnum = mono_w32socket_convert_error (errno);
1335 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: fcntl(F_GETFL) error: %s", __func__, g_strerror (errno));
1336 mono_w32socket_set_last_error (errnum);
1337 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1338 return SOCKET_ERROR;
1341 MONO_ENTER_GC_SAFE;
1342 ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_SETFL, blocking ? (ret & (~O_NONBLOCK)) : (ret | (O_NONBLOCK)));
1343 MONO_EXIT_GC_SAFE;
1344 if (ret == -1) {
1345 gint errnum = mono_w32socket_convert_error (errno);
1346 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: fcntl(F_SETFL) error: %s", __func__, g_strerror (errno));
1347 mono_w32socket_set_last_error (errnum);
1348 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1349 return SOCKET_ERROR;
1352 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1353 return 0;
1354 #else
1355 mono_w32socket_set_last_error (ERROR_NOT_SUPPORTED);
1356 return SOCKET_ERROR;
1357 #endif /* O_NONBLOCK */
1360 gint
1361 mono_w32socket_get_available (SOCKET sock, guint64 *amount)
1363 SocketHandle *sockethandle;
1364 gint ret;
1366 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1367 mono_w32error_set_last (WSAENOTSOCK);
1368 return SOCKET_ERROR;
1371 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1372 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1373 mono_w32error_set_last (WSAENOTSOCK);
1374 return SOCKET_ERROR;
1377 #if defined (HOST_DARWIN)
1378 // ioctl (socket, FIONREAD, XXX) returns the size of
1379 // the UDP header as well on Darwin.
1381 // Use getsockopt SO_NREAD instead to get the
1382 // right values for TCP and UDP.
1384 // ai_canonname can be null in some cases on darwin,
1385 // where the runtime assumes it will be the value of
1386 // the ip buffer.
1388 socklen_t optlen = sizeof (int);
1389 MONO_ENTER_GC_SAFE;
1390 ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_NREAD, (gulong*) amount, &optlen);
1391 MONO_EXIT_GC_SAFE;
1392 if (ret == -1) {
1393 gint errnum = mono_w32socket_convert_error (errno);
1394 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockopt error: %s", __func__, g_strerror (errno));
1395 mono_w32socket_set_last_error (errnum);
1396 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1397 return SOCKET_ERROR;
1399 #else
1400 MONO_ENTER_GC_SAFE;
1401 ret = ioctl (((MonoFDHandle*) sockethandle)->fd, FIONREAD, (gulong*) amount);
1402 MONO_EXIT_GC_SAFE;
1403 if (ret == -1) {
1404 gint errnum = mono_w32socket_convert_error (errno);
1405 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: ioctl error: %s", __func__, g_strerror (errno));
1406 mono_w32socket_set_last_error (errnum);
1407 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1408 return SOCKET_ERROR;
1410 #endif
1412 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1413 return 0;
1416 void
1417 mono_w32socket_set_last_error (gint32 error)
1419 mono_w32error_set_last (error);
1422 gint32
1423 mono_w32socket_get_last_error (void)
1425 return mono_w32error_get_last ();
1428 gint32
1429 mono_w32socket_convert_error (gint error)
1431 switch (error) {
1432 case 0: return ERROR_SUCCESS;
1433 case EACCES: return WSAEACCES;
1434 #ifdef EADDRINUSE
1435 case EADDRINUSE: return WSAEADDRINUSE;
1436 #endif
1437 #ifdef EAFNOSUPPORT
1438 case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
1439 #endif
1440 #if EAGAIN != EWOULDBLOCK
1441 case EAGAIN: return WSAEWOULDBLOCK;
1442 #endif
1443 #ifdef EALREADY
1444 case EALREADY: return WSAEALREADY;
1445 #endif
1446 case EBADF: return WSAENOTSOCK;
1447 #ifdef ECONNABORTED
1448 case ECONNABORTED: return WSAENETDOWN;
1449 #endif
1450 #ifdef ECONNREFUSED
1451 case ECONNREFUSED: return WSAECONNREFUSED;
1452 #endif
1453 #ifdef ECONNRESET
1454 case ECONNRESET: return WSAECONNRESET;
1455 #endif
1456 case EFAULT: return WSAEFAULT;
1457 #ifdef EHOSTUNREACH
1458 case EHOSTUNREACH: return WSAEHOSTUNREACH;
1459 #endif
1460 #ifdef EINPROGRESS
1461 case EINPROGRESS: return WSAEINPROGRESS;
1462 #endif
1463 case EINTR: return WSAEINTR;
1464 case EINVAL: return WSAEINVAL;
1465 /*FIXME: case EIO: return WSAE????; */
1466 #ifdef EISCONN
1467 case EISCONN: return WSAEISCONN;
1468 #endif
1469 /* FIXME: case ELOOP: return WSA????; */
1470 case EMFILE: return WSAEMFILE;
1471 #ifdef EMSGSIZE
1472 case EMSGSIZE: return WSAEMSGSIZE;
1473 #endif
1474 /* FIXME: case ENAMETOOLONG: return WSAEACCES; */
1475 #ifdef ENETUNREACH
1476 case ENETUNREACH: return WSAENETUNREACH;
1477 #endif
1478 #ifdef ENOBUFS
1479 case ENOBUFS: return WSAENOBUFS; /* not documented */
1480 #endif
1481 /* case ENOENT: return WSAE????; */
1482 case ENOMEM: return WSAENOBUFS;
1483 #ifdef ENOPROTOOPT
1484 case ENOPROTOOPT: return WSAENOPROTOOPT;
1485 #endif
1486 #ifdef ENOSR
1487 case ENOSR: return WSAENETDOWN;
1488 #endif
1489 #ifdef ENOTCONN
1490 case ENOTCONN: return WSAENOTCONN;
1491 #endif
1492 /*FIXME: case ENOTDIR: return WSAE????; */
1493 #ifdef ENOTSOCK
1494 case ENOTSOCK: return WSAENOTSOCK;
1495 #endif
1496 case ENOTTY: return WSAENOTSOCK;
1497 #ifdef EOPNOTSUPP
1498 case EOPNOTSUPP: return WSAEOPNOTSUPP;
1499 #endif
1500 case EPERM: return WSAEACCES;
1501 case EPIPE: return WSAESHUTDOWN;
1502 #ifdef EPROTONOSUPPORT
1503 case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
1504 #endif
1505 #if ERESTARTSYS
1506 case ERESTARTSYS: return WSAENETDOWN;
1507 #endif
1508 /*FIXME: case EROFS: return WSAE????; */
1509 #ifdef ESOCKTNOSUPPORT
1510 case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
1511 #endif
1512 #ifdef ETIMEDOUT
1513 case ETIMEDOUT: return WSAETIMEDOUT;
1514 #endif
1515 #ifdef EWOULDBLOCK
1516 case EWOULDBLOCK: return WSAEWOULDBLOCK;
1517 #endif
1518 #ifdef EADDRNOTAVAIL
1519 case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
1520 #endif
1521 /* This might happen with unix sockets */
1522 case ENOENT: return WSAECONNREFUSED;
1523 #ifdef EDESTADDRREQ
1524 case EDESTADDRREQ: return WSAEDESTADDRREQ;
1525 #endif
1526 #ifdef EHOSTDOWN
1527 case EHOSTDOWN: return WSAEHOSTDOWN;
1528 #endif
1529 #ifdef ENETDOWN
1530 case ENETDOWN: return WSAENETDOWN;
1531 #endif
1532 case ENODEV: return WSAENETDOWN;
1533 #ifdef EPROTOTYPE
1534 case EPROTOTYPE: return WSAEPROTOTYPE;
1535 #endif
1536 #ifdef ENXIO
1537 case ENXIO: return WSAENXIO;
1538 #endif
1539 default:
1540 g_error ("%s: no translation into winsock error for (%d) \"%s\"", __func__, error, g_strerror (error));
1544 gboolean
1545 ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto, MonoError *error)
1547 error_init (error);
1548 #if defined (SO_REUSEPORT)
1549 return TRUE;
1550 #else
1551 #ifdef __linux__
1552 /* Linux always supports double binding for UDP, even on older kernels. */
1553 if (proto == ProtocolType_Udp)
1554 return TRUE;
1555 #endif
1556 return FALSE;
1557 #endif
1560 gboolean
1561 mono_w32socket_duplicate (gpointer handle, gint32 targetProcessId, gpointer *duplicate_handle)
1563 SocketHandle *sockethandle;
1565 if (!mono_fdhandle_lookup_and_ref (GPOINTER_TO_INT(handle), (MonoFDHandle**) &sockethandle)) {
1566 mono_w32error_set_last (ERROR_INVALID_HANDLE);
1567 return FALSE;
1570 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1571 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1572 mono_w32error_set_last (ERROR_INVALID_HANDLE);
1573 return FALSE;
1576 *duplicate_handle = handle;
1577 return TRUE;