[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mono / metadata / w32socket-unix.c
blob58645ed4ef860cd6d9de0da38aae4d17ac95dfd8
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, socklen_t 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, gpointer lpTransmitBuffers, 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
589 TRANSMIT_FILE_BUFFERS *buffers = (TRANSMIT_FILE_BUFFERS *)lpTransmitBuffers;
591 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
592 mono_w32error_set_last (WSAENOTSOCK);
593 return FALSE;
596 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
597 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
598 mono_w32error_set_last (WSAENOTSOCK);
599 return FALSE;
602 /* Write the header */
603 if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) {
604 ret = mono_w32socket_send (((MonoFDHandle*) sockethandle)->fd, buffers->Head, buffers->HeadLength, 0, FALSE);
605 if (ret == SOCKET_ERROR) {
606 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
607 return FALSE;
611 info = mono_thread_info_current ();
613 file = GPOINTER_TO_INT (file_handle);
615 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
616 MONO_ENTER_GC_SAFE;
617 ret = fstat (file, &statbuf);
618 MONO_EXIT_GC_SAFE;
619 if (ret == -1) {
620 gint errnum = errno;
621 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
622 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
623 return FALSE;
626 do {
627 MONO_ENTER_GC_SAFE;
628 #ifdef __linux__
629 ret = sendfile (((MonoFDHandle*) sockethandle)->fd, file, NULL, statbuf.st_size);
630 #elif defined(DARWIN)
631 /* TODO: header/tail could be sent in the 5th argument */
632 /* TODO: Might not send the entire file for non-blocking sockets */
633 ret = sendfile (file, ((MonoFDHandle*) sockethandle)->fd, 0, &statbuf.st_size, NULL, 0);
634 #endif
635 MONO_EXIT_GC_SAFE;
636 } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
637 #else
638 buffer = g_malloc (SF_BUFFER_SIZE);
640 do {
641 do {
642 MONO_ENTER_GC_SAFE;
643 ret = read (file, buffer, SF_BUFFER_SIZE);
644 MONO_EXIT_GC_SAFE;
645 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
647 if (ret == -1 || ret == 0)
648 break;
650 do {
651 MONO_ENTER_GC_SAFE;
652 ret = send (((MonoFDHandle*) sockethandle)->fd, buffer, ret, 0); /* short sends? enclose this in a loop? */
653 MONO_EXIT_GC_SAFE;
654 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
655 } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
657 g_free (buffer);
658 #endif
660 if (ret == -1) {
661 gint errnum = errno;
662 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
663 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
664 return FALSE;
667 /* Write the tail */
668 if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) {
669 ret = mono_w32socket_send (((MonoFDHandle*) sockethandle)->fd, buffers->Tail, buffers->TailLength, 0, FALSE);
670 if (ret == SOCKET_ERROR) {
671 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
672 return FALSE;
676 if ((flags & TF_DISCONNECT) == TF_DISCONNECT)
677 mono_w32socket_close (((MonoFDHandle*) sockethandle)->fd);
679 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
680 return TRUE;
683 SOCKET
684 mono_w32socket_socket (int domain, int type, int protocol)
686 SocketHandle *sockethandle;
687 gint fd;
689 retry_socket:
690 MONO_ENTER_GC_SAFE;
691 fd = socket (domain, type, protocol);
692 MONO_EXIT_GC_SAFE;
693 if (fd == -1) {
694 if (domain == AF_INET && type == SOCK_RAW && protocol == 0) {
695 /* Retry with protocol == 4 (see bug #54565) */
696 // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565
697 protocol = 4;
698 goto retry_socket;
701 gint errnum = errno;
702 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: socket error: %s", __func__, g_strerror (errno));
703 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
704 return INVALID_SOCKET;
707 sockethandle = socket_data_create(MONO_FDTYPE_SOCKET, fd);
708 sockethandle->domain = domain;
709 sockethandle->type = type;
710 sockethandle->protocol = protocol;
711 sockethandle->still_readable = 1;
713 /* .net seems to set this by default for SOCK_STREAM, not for
714 * SOCK_DGRAM (see bug #36322)
715 * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322
717 * It seems winsock has a rather different idea of what
718 * SO_REUSEADDR means. If it's set, then a new socket can be
719 * bound over an existing listening socket. There's a new
720 * windows-specific option called SO_EXCLUSIVEADDRUSE but
721 * using that means the socket MUST be closed properly, or a
722 * denial of service can occur. Luckily for us, winsock
723 * behaves as though any other system would when SO_REUSEADDR
724 * is true, so we don't need to do anything else here. See
725 * bug 53992.
726 * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992
729 int ret;
730 const int true_ = 1;
732 MONO_ENTER_GC_SAFE;
733 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_REUSEADDR, &true_, sizeof (true_));
734 MONO_EXIT_GC_SAFE;
735 if (ret == -1) {
736 gint errnum = errno;
737 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: Error setting SO_REUSEADDR", __func__);
738 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
740 MONO_ENTER_GC_SAFE;
741 close (((MonoFDHandle*) sockethandle)->fd);
742 MONO_EXIT_GC_SAFE;
744 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
745 return INVALID_SOCKET;
749 mono_fdhandle_insert ((MonoFDHandle*) sockethandle);
751 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: returning socket handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) sockethandle)->fd));
753 return ((MonoFDHandle*) sockethandle)->fd;
756 gint
757 mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen)
759 SocketHandle *sockethandle;
760 int ret;
762 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
763 mono_w32error_set_last (WSAENOTSOCK);
764 return SOCKET_ERROR;
767 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
768 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
769 mono_w32error_set_last (WSAENOTSOCK);
770 return SOCKET_ERROR;
773 MONO_ENTER_GC_SAFE;
774 ret = bind (((MonoFDHandle*) sockethandle)->fd, addr, addrlen);
775 MONO_EXIT_GC_SAFE;
776 if (ret == -1) {
777 gint errnum = errno;
778 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: bind error: %s", __func__, g_strerror(errno));
779 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
780 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
781 return SOCKET_ERROR;
784 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
785 return 0;
788 gint
789 mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
791 SocketHandle *sockethandle;
792 gint ret;
794 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
795 mono_w32error_set_last (WSAENOTSOCK);
796 return SOCKET_ERROR;
799 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
800 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
801 mono_w32error_set_last (WSAENOTSOCK);
802 return SOCKET_ERROR;
805 #ifdef HAVE_GETPEERNAME
806 MONO_ENTER_GC_SAFE;
807 ret = getpeername (((MonoFDHandle*) sockethandle)->fd, name, namelen);
808 MONO_EXIT_GC_SAFE;
809 #else
810 ret = -1;
811 #endif
812 if (ret == -1) {
813 gint errnum = errno;
814 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getpeername error: %s", __func__, g_strerror (errno));
815 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
816 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
817 return SOCKET_ERROR;
820 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
821 return 0;
824 gint
825 mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
827 SocketHandle *sockethandle;
828 gint ret;
830 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
831 mono_w32error_set_last (WSAENOTSOCK);
832 return SOCKET_ERROR;
835 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
836 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
837 mono_w32error_set_last (WSAENOTSOCK);
838 return SOCKET_ERROR;
841 MONO_ENTER_GC_SAFE;
842 ret = getsockname (((MonoFDHandle*) sockethandle)->fd, name, namelen);
843 MONO_EXIT_GC_SAFE;
844 if (ret == -1) {
845 gint errnum = errno;
846 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockname error: %s", __func__, g_strerror (errno));
847 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
848 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
849 return SOCKET_ERROR;
852 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
853 return 0;
856 gint
857 mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen)
859 SocketHandle *sockethandle;
860 gint ret;
861 struct timeval tv;
862 gpointer tmp_val;
864 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
865 mono_w32error_set_last (WSAENOTSOCK);
866 return SOCKET_ERROR;
869 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
870 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
871 mono_w32error_set_last (WSAENOTSOCK);
872 return SOCKET_ERROR;
875 tmp_val = optval;
876 if (level == SOL_SOCKET &&
877 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
878 tmp_val = &tv;
879 *optlen = sizeof (tv);
882 MONO_ENTER_GC_SAFE;
883 ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, level, optname, tmp_val, optlen);
884 MONO_EXIT_GC_SAFE;
885 if (ret == -1) {
886 gint errnum = errno;
887 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockopt error: %s", __func__, g_strerror (errno));
888 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
889 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
890 return SOCKET_ERROR;
893 if (level == SOL_SOCKET && (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
894 *((int *) optval) = tv.tv_sec * 1000 + (tv.tv_usec / 1000); // milli from micro
895 *optlen = sizeof (int);
898 if (optname == SO_ERROR) {
899 if (*((int *)optval) != 0) {
900 *((int *) optval) = mono_w32socket_convert_error (*((int *)optval));
901 sockethandle->saved_error = *((int *)optval);
902 } else {
903 *((int *)optval) = sockethandle->saved_error;
907 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
908 return 0;
911 gint
912 mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, gconstpointer optval, socklen_t optlen)
914 SocketHandle *sockethandle;
915 gint ret;
916 gconstpointer tmp_val;
917 #if defined (__linux__)
918 /* This has its address taken so it cannot be moved to the if block which uses it */
919 gint bufsize = 0;
920 #endif
921 struct timeval tv;
923 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
924 mono_w32error_set_last (WSAENOTSOCK);
925 return SOCKET_ERROR;
928 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
929 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
930 mono_w32error_set_last (WSAENOTSOCK);
931 return SOCKET_ERROR;
934 tmp_val = optval;
935 if (level == SOL_SOCKET &&
936 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
937 int ms = *((int *) optval);
938 tv.tv_sec = ms / 1000;
939 tv.tv_usec = (ms % 1000) * 1000; // micro from milli
940 tmp_val = &tv;
941 optlen = sizeof (tv);
943 #if defined (__linux__)
944 else if (level == SOL_SOCKET &&
945 (optname == SO_SNDBUF || optname == SO_RCVBUF)) {
946 /* According to socket(7) the Linux kernel doubles the
947 * buffer sizes "to allow space for bookkeeping
948 * overhead."
950 bufsize = *((int *) optval);
952 bufsize /= 2;
953 tmp_val = &bufsize;
955 #endif
957 MONO_ENTER_GC_SAFE;
958 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, level, optname, tmp_val, optlen);
959 MONO_EXIT_GC_SAFE;
960 if (ret == -1) {
961 gint errnum = errno;
962 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: setsockopt error: %s", __func__, g_strerror (errno));
963 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
964 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
965 return SOCKET_ERROR;
968 #if defined (SO_REUSEPORT)
969 /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */
970 if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
971 int type;
972 socklen_t type_len = sizeof (type);
974 MONO_ENTER_GC_SAFE;
975 ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, level, SO_TYPE, &type, &type_len);
976 MONO_EXIT_GC_SAFE;
977 if (!ret) {
978 if (type == SOCK_DGRAM || type == SOCK_STREAM) {
979 MONO_ENTER_GC_SAFE;
980 setsockopt (((MonoFDHandle*) sockethandle)->fd, level, SO_REUSEPORT, tmp_val, optlen);
981 MONO_EXIT_GC_SAFE;
985 #endif
987 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
988 return ret;
991 gint
992 mono_w32socket_listen (SOCKET sock, gint backlog)
994 SocketHandle *sockethandle;
995 gint ret;
997 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
998 mono_w32error_set_last (WSAENOTSOCK);
999 return SOCKET_ERROR;
1002 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1003 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1004 mono_w32error_set_last (WSAENOTSOCK);
1005 return SOCKET_ERROR;
1008 MONO_ENTER_GC_SAFE;
1009 ret = listen (((MonoFDHandle*) sockethandle)->fd, backlog);
1010 MONO_EXIT_GC_SAFE;
1011 if (ret == -1) {
1012 gint errnum = errno;
1013 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: listen error: %s", __func__, g_strerror (errno));
1014 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1015 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1016 return SOCKET_ERROR;
1019 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1020 return 0;
1023 gint
1024 mono_w32socket_shutdown (SOCKET sock, gint how)
1026 SocketHandle *sockethandle;
1027 gint ret;
1029 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1030 mono_w32error_set_last (WSAENOTSOCK);
1031 return SOCKET_ERROR;
1034 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1035 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1036 mono_w32error_set_last (WSAENOTSOCK);
1037 return SOCKET_ERROR;
1040 if (how == SHUT_RD || how == SHUT_RDWR)
1041 sockethandle->still_readable = 0;
1043 MONO_ENTER_GC_SAFE;
1044 ret = shutdown (((MonoFDHandle*) sockethandle)->fd, how);
1045 MONO_EXIT_GC_SAFE;
1046 if (ret == -1) {
1047 gint errnum = errno;
1048 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: shutdown error: %s", __func__, g_strerror (errno));
1049 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1050 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1051 return SOCKET_ERROR;
1054 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1055 return ret;
1058 gint
1059 mono_w32socket_disconnect (SOCKET sock, gboolean reuse)
1061 SocketHandle *sockethandle;
1062 SOCKET newsock;
1063 gint ret;
1065 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: called on socket %d!", __func__, sock);
1067 /* We could check the socket type here and fail unless its
1068 * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn)
1069 * if we really wanted to */
1071 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1072 mono_w32error_set_last (WSAENOTSOCK);
1073 return SOCKET_ERROR;
1076 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1077 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1078 mono_w32error_set_last (WSAENOTSOCK);
1079 return SOCKET_ERROR;
1082 MONO_ENTER_GC_SAFE;
1083 newsock = socket (sockethandle->domain, sockethandle->type, sockethandle->protocol);
1084 MONO_EXIT_GC_SAFE;
1085 if (newsock == -1) {
1086 gint errnum = errno;
1087 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: socket error: %s", __func__, g_strerror (errnum));
1088 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1089 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1090 return SOCKET_ERROR;
1093 /* According to Stevens "Advanced Programming in the UNIX
1094 * Environment: UNIX File I/O" dup2() is atomic so there
1095 * should not be a race condition between the old fd being
1096 * closed and the new socket fd being copied over */
1097 do {
1098 MONO_ENTER_GC_SAFE;
1099 ret = dup2 (newsock, ((MonoFDHandle*) sockethandle)->fd);
1100 MONO_EXIT_GC_SAFE;
1101 } while (ret == -1 && errno == EAGAIN);
1103 if (ret == -1) {
1104 gint errnum = errno;
1105 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: dup2 error: %s", __func__, g_strerror (errnum));
1106 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1107 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1108 return SOCKET_ERROR;
1111 MONO_ENTER_GC_SAFE;
1112 close (newsock);
1113 MONO_EXIT_GC_SAFE;
1115 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1116 return 0;
1119 static gboolean
1120 extension_disconect (SOCKET sock, OVERLAPPED *overlapped, guint32 flags, guint32 reserved)
1122 gboolean ret;
1123 MONO_ENTER_GC_UNSAFE;
1124 ret = mono_w32socket_disconnect (sock, flags & TF_REUSE_SOCKET) == 0;
1125 MONO_EXIT_GC_UNSAFE;
1126 return ret;
1129 static gboolean
1130 extension_transmit_file (SOCKET sock, gpointer file_handle, guint32 bytes_to_write, guint32 bytes_per_send,
1131 OVERLAPPED *ol, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags)
1133 gboolean ret;
1134 MONO_ENTER_GC_UNSAFE;
1135 ret = mono_w32socket_transmit_file (sock, file_handle, buffers, flags, FALSE);
1136 MONO_EXIT_GC_UNSAFE;
1137 return ret;
1140 const
1141 static struct {
1142 GUID guid;
1143 gpointer func;
1144 } extension_functions[] = {
1145 { {0x7fda2e11,0x8630,0x436f,{0xa0,0x31,0xf5,0x36,0xa6,0xee,0xc1,0x57}} /* WSAID_DISCONNECTEX */, (gpointer)extension_disconect },
1146 { {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} /* WSAID_TRANSMITFILE */, (gpointer)extension_transmit_file },
1147 { {0} , NULL },
1150 gint
1151 mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written)
1153 SocketHandle *sockethandle;
1154 gint ret;
1155 gpointer buffer;
1157 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1158 mono_w32error_set_last (WSAENOTSOCK);
1159 return SOCKET_ERROR;
1162 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1163 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1164 mono_w32error_set_last (WSAENOTSOCK);
1165 return SOCKET_ERROR;
1168 if (command == 0xC8000006 /* SIO_GET_EXTENSION_FUNCTION_POINTER */) {
1169 gint i;
1170 GUID *guid;
1172 if (inputlen < sizeof(GUID)) {
1173 /* As far as I can tell, windows doesn't
1174 * actually set an error here...
1176 mono_w32socket_set_last_error (WSAEINVAL);
1177 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1178 return SOCKET_ERROR;
1181 if (outputlen < sizeof(gpointer)) {
1182 /* Or here... */
1183 mono_w32socket_set_last_error (WSAEINVAL);
1184 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1185 return SOCKET_ERROR;
1188 if (output == NULL) {
1189 /* Or here */
1190 mono_w32socket_set_last_error (WSAEINVAL);
1191 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1192 return SOCKET_ERROR;
1195 guid = (GUID*) input;
1196 for (i = 0; extension_functions[i].func; i++) {
1197 if (memcmp (guid, &extension_functions[i].guid, sizeof(GUID)) == 0) {
1198 memcpy (output, &extension_functions[i].func, sizeof(gpointer));
1199 *written = sizeof(gpointer);
1200 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1201 return 0;
1205 mono_w32socket_set_last_error (WSAEINVAL);
1206 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1207 return SOCKET_ERROR;
1210 if (command == 0x98000004 /* SIO_KEEPALIVE_VALS */) {
1211 guint32 onoff;
1213 if (inputlen < 3 * sizeof (guint32)) {
1214 mono_w32socket_set_last_error (WSAEINVAL);
1215 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1216 return SOCKET_ERROR;
1219 onoff = *((guint32*) input);
1221 MONO_ENTER_GC_SAFE;
1222 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (guint32));
1223 MONO_EXIT_GC_SAFE;
1224 if (ret < 0) {
1225 mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
1226 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1227 return SOCKET_ERROR;
1230 #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
1231 if (onoff != 0) {
1232 /* Values are in ms, but we need s */
1233 guint32 keepalivetime, keepaliveinterval, rem;
1235 keepalivetime = *(((guint32*) input) + 1);
1236 keepaliveinterval = *(((guint32*) input) + 2);
1238 /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */
1239 rem = keepalivetime % 1000;
1240 keepalivetime /= 1000;
1241 if (keepalivetime == 0 || rem >= 500)
1242 keepalivetime++;
1243 MONO_ENTER_GC_SAFE;
1244 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (guint32));
1245 MONO_EXIT_GC_SAFE;
1246 if (ret == 0) {
1247 rem = keepaliveinterval % 1000;
1248 keepaliveinterval /= 1000;
1249 if (keepaliveinterval == 0 || rem >= 500)
1250 keepaliveinterval++;
1251 MONO_ENTER_GC_SAFE;
1252 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (guint32));
1253 MONO_EXIT_GC_SAFE;
1255 if (ret != 0) {
1256 mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
1257 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1258 return SOCKET_ERROR;
1261 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1262 return 0;
1264 #endif
1266 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1267 return 0;
1270 buffer = inputlen > 0 ? (gchar*) g_memdup (input, inputlen) : NULL;
1272 MONO_ENTER_GC_SAFE;
1273 ret = ioctl (((MonoFDHandle*) sockethandle)->fd, command, buffer);
1274 MONO_EXIT_GC_SAFE;
1275 if (ret == -1) {
1276 g_free (buffer);
1278 gint errnum = errno;
1279 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: WSAIoctl error: %s", __func__, g_strerror (errno));
1280 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1281 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1282 return SOCKET_ERROR;
1285 if (!buffer) {
1286 *written = 0;
1287 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1288 return 0;
1291 /* We just copy the buffer to the output. Some ioctls
1292 * don't even output any data, but, well...
1294 * NB windows returns WSAEFAULT if outputlen is too small */
1295 inputlen = (inputlen > outputlen) ? outputlen : inputlen;
1297 if (inputlen > 0 && output != NULL)
1298 memcpy (output, buffer, inputlen);
1300 g_free (buffer);
1301 *written = inputlen;
1303 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1304 return 0;
1307 gboolean
1308 mono_w32socket_close (SOCKET sock)
1310 if (!mono_fdhandle_close (sock)) {
1311 mono_w32error_set_last (ERROR_INVALID_HANDLE);
1312 return FALSE;
1315 return TRUE;
1318 gint
1319 mono_w32socket_set_blocking (SOCKET sock, gboolean blocking)
1321 #ifdef O_NONBLOCK
1322 SocketHandle *sockethandle;
1323 gint ret;
1325 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1326 mono_w32error_set_last (WSAENOTSOCK);
1327 return SOCKET_ERROR;
1330 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1331 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1332 mono_w32error_set_last (WSAENOTSOCK);
1333 return SOCKET_ERROR;
1336 /* This works better than ioctl(...FIONBIO...)
1337 * on Linux (it causes connect to return
1338 * EINPROGRESS, but the ioctl doesn't seem to) */
1339 MONO_ENTER_GC_SAFE;
1340 ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_GETFL, 0);
1341 MONO_EXIT_GC_SAFE;
1342 if (ret == -1) {
1343 gint errnum = mono_w32socket_convert_error (errno);
1344 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: fcntl(F_GETFL) error: %s", __func__, g_strerror (errno));
1345 mono_w32socket_set_last_error (errnum);
1346 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1347 return SOCKET_ERROR;
1350 MONO_ENTER_GC_SAFE;
1351 ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_SETFL, blocking ? (ret & (~O_NONBLOCK)) : (ret | (O_NONBLOCK)));
1352 MONO_EXIT_GC_SAFE;
1353 if (ret == -1) {
1354 gint errnum = mono_w32socket_convert_error (errno);
1355 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: fcntl(F_SETFL) error: %s", __func__, g_strerror (errno));
1356 mono_w32socket_set_last_error (errnum);
1357 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1358 return SOCKET_ERROR;
1361 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1362 return 0;
1363 #else
1364 mono_w32socket_set_last_error (ERROR_NOT_SUPPORTED);
1365 return SOCKET_ERROR;
1366 #endif /* O_NONBLOCK */
1369 gint
1370 mono_w32socket_get_available (SOCKET sock, guint64 *amount)
1372 SocketHandle *sockethandle;
1373 gint ret;
1375 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1376 mono_w32error_set_last (WSAENOTSOCK);
1377 return SOCKET_ERROR;
1380 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1381 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1382 mono_w32error_set_last (WSAENOTSOCK);
1383 return SOCKET_ERROR;
1386 #if defined (HOST_DARWIN)
1387 // ioctl (socket, FIONREAD, XXX) returns the size of
1388 // the UDP header as well on Darwin.
1390 // Use getsockopt SO_NREAD instead to get the
1391 // right values for TCP and UDP.
1393 // ai_canonname can be null in some cases on darwin,
1394 // where the runtime assumes it will be the value of
1395 // the ip buffer.
1397 socklen_t optlen = sizeof (int);
1398 MONO_ENTER_GC_SAFE;
1399 ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_NREAD, (gulong*) amount, &optlen);
1400 MONO_EXIT_GC_SAFE;
1401 if (ret == -1) {
1402 gint errnum = mono_w32socket_convert_error (errno);
1403 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockopt error: %s", __func__, g_strerror (errno));
1404 mono_w32socket_set_last_error (errnum);
1405 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1406 return SOCKET_ERROR;
1408 #else
1409 MONO_ENTER_GC_SAFE;
1410 ret = ioctl (((MonoFDHandle*) sockethandle)->fd, FIONREAD, (gulong*) amount);
1411 MONO_EXIT_GC_SAFE;
1412 if (ret == -1) {
1413 gint errnum = mono_w32socket_convert_error (errno);
1414 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: ioctl error: %s", __func__, g_strerror (errno));
1415 mono_w32socket_set_last_error (errnum);
1416 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1417 return SOCKET_ERROR;
1419 #endif
1421 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1422 return 0;
1425 void
1426 mono_w32socket_set_last_error (gint32 error)
1428 mono_w32error_set_last (error);
1431 gint32
1432 mono_w32socket_get_last_error (void)
1434 return mono_w32error_get_last ();
1437 gint32
1438 mono_w32socket_convert_error (gint error)
1440 switch (error) {
1441 case 0: return ERROR_SUCCESS;
1442 case EACCES: return WSAEACCES;
1443 #ifdef EADDRINUSE
1444 case EADDRINUSE: return WSAEADDRINUSE;
1445 #endif
1446 #ifdef EAFNOSUPPORT
1447 case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
1448 #endif
1449 #if EAGAIN != EWOULDBLOCK
1450 case EAGAIN: return WSAEWOULDBLOCK;
1451 #endif
1452 #ifdef EALREADY
1453 case EALREADY: return WSAEALREADY;
1454 #endif
1455 case EBADF: return WSAENOTSOCK;
1456 #ifdef ECONNABORTED
1457 case ECONNABORTED: return WSAENETDOWN;
1458 #endif
1459 #ifdef ECONNREFUSED
1460 case ECONNREFUSED: return WSAECONNREFUSED;
1461 #endif
1462 #ifdef ECONNRESET
1463 case ECONNRESET: return WSAECONNRESET;
1464 #endif
1465 case EDOM: return WSAEINVAL; /* not a precise match, best wecan do. */
1466 case EFAULT: return WSAEFAULT;
1467 #ifdef EHOSTUNREACH
1468 case EHOSTUNREACH: return WSAEHOSTUNREACH;
1469 #endif
1470 #ifdef EINPROGRESS
1471 case EINPROGRESS: return WSAEINPROGRESS;
1472 #endif
1473 case EINTR: return WSAEINTR;
1474 case EINVAL: return WSAEINVAL;
1475 case EIO: return WSA_INVALID_HANDLE; /* not a precise match, best we can do. */
1476 #ifdef EISCONN
1477 case EISCONN: return WSAEISCONN;
1478 #endif
1479 case ELOOP: return WSAELOOP;
1480 case ENFILE: return WSAEMFILE; /* not a precise match, best we can do. */
1481 case EMFILE: return WSAEMFILE;
1482 #ifdef EMSGSIZE
1483 case EMSGSIZE: return WSAEMSGSIZE;
1484 #endif
1485 case ENAMETOOLONG: return WSAENAMETOOLONG;
1486 #ifdef ENETUNREACH
1487 case ENETUNREACH: return WSAENETUNREACH;
1488 #endif
1489 #ifdef ENOBUFS
1490 case ENOBUFS: return WSAENOBUFS; /* not documented */
1491 #endif
1492 case ENOMEM: return WSAENOBUFS;
1493 #ifdef ENOPROTOOPT
1494 case ENOPROTOOPT: return WSAENOPROTOOPT;
1495 #endif
1496 #ifdef ENOSR
1497 case ENOSR: return WSAENETDOWN;
1498 #endif
1499 #ifdef ENOTCONN
1500 case ENOTCONN: return WSAENOTCONN;
1501 #endif
1502 case ENOTDIR: return WSA_INVALID_PARAMETER; /* not a precise match, best we can do. */
1503 #ifdef ENOTSOCK
1504 case ENOTSOCK: return WSAENOTSOCK;
1505 #endif
1506 case ENOTTY: return WSAENOTSOCK;
1507 #ifdef EOPNOTSUPP
1508 case EOPNOTSUPP: return WSAEOPNOTSUPP;
1509 #endif
1510 case EPERM: return WSAEACCES;
1511 case EPIPE: return WSAESHUTDOWN;
1512 #ifdef EPROTONOSUPPORT
1513 case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
1514 #endif
1515 #if ERESTARTSYS
1516 case ERESTARTSYS: return WSAENETDOWN;
1517 #endif
1518 /*FIXME: case EROFS: return WSAE????; */
1519 #ifdef ESOCKTNOSUPPORT
1520 case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
1521 #endif
1522 #ifdef ETIMEDOUT
1523 case ETIMEDOUT: return WSAETIMEDOUT;
1524 #endif
1525 #ifdef EWOULDBLOCK
1526 case EWOULDBLOCK: return WSAEWOULDBLOCK;
1527 #endif
1528 #ifdef EADDRNOTAVAIL
1529 case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
1530 #endif
1531 /* This might happen with unix sockets */
1532 case ENOENT: return WSAECONNREFUSED;
1533 #ifdef EDESTADDRREQ
1534 case EDESTADDRREQ: return WSAEDESTADDRREQ;
1535 #endif
1536 #ifdef EHOSTDOWN
1537 case EHOSTDOWN: return WSAEHOSTDOWN;
1538 #endif
1539 #ifdef ENETDOWN
1540 case ENETDOWN: return WSAENETDOWN;
1541 #endif
1542 case ENODEV: return WSAENETDOWN;
1543 #ifdef EPROTOTYPE
1544 case EPROTOTYPE: return WSAEPROTOTYPE;
1545 #endif
1546 #ifdef ENXIO
1547 case ENXIO: return WSAENXIO;
1548 #endif
1549 #ifdef ENONET
1550 case ENONET: return WSAENETUNREACH;
1551 #endif
1552 #ifdef ENOKEY
1553 case ENOKEY: return WSAENETUNREACH;
1554 #endif
1555 default:
1556 g_error ("%s: no translation into winsock error for (%d) \"%s\"", __func__, error, g_strerror (error));
1560 MonoBoolean
1561 ves_icall_System_Net_Sockets_Socket_SupportPortReuse_icall (MonoProtocolType proto)
1563 #if defined (SO_REUSEPORT)
1564 return TRUE;
1565 #else
1566 #ifdef __linux__
1567 /* Linux always supports double binding for UDP, even on older kernels. */
1568 if (proto == ProtocolType_Udp)
1569 return TRUE;
1570 #endif
1571 return FALSE;
1572 #endif
1575 gboolean
1576 mono_w32socket_duplicate (gpointer handle, gint32 targetProcessId, gpointer *duplicate_handle)
1578 SocketHandle *sockethandle;
1580 if (!mono_fdhandle_lookup_and_ref (GPOINTER_TO_INT(handle), (MonoFDHandle**) &sockethandle)) {
1581 mono_w32error_set_last (ERROR_INVALID_HANDLE);
1582 return FALSE;
1585 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1586 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1587 mono_w32error_set_last (ERROR_INVALID_HANDLE);
1588 return FALSE;
1591 *duplicate_handle = handle;
1592 return TRUE;