2 * sockets.c: Socket handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <sys/ioctl.h>
18 #ifdef HAVE_SYS_FILIO_H
19 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
21 #ifdef HAVE_SYS_SOCKIO_H
22 #include <sys/sockio.h> /* defines SIOCATMARK */
27 #ifndef HAVE_MSG_NOSIGNAL
31 #include <mono/io-layer/wapi.h>
32 #include <mono/io-layer/wapi-private.h>
33 #include <mono/io-layer/socket-private.h>
34 #include <mono/io-layer/handles-private.h>
35 #include <mono/io-layer/socket-wrappers.h>
39 static guint32 startup_count=0;
40 static GPtrArray *sockets=NULL;
41 static pthread_key_t error_key;
42 static mono_once_t error_key_once=MONO_ONCE_INIT;
44 static void socket_close (gpointer handle);
46 struct _WapiHandleOps _wapi_socket_ops = {
47 socket_close, /* close */
53 static mono_once_t socket_ops_once=MONO_ONCE_INIT;
55 static void socket_ops_init (void)
57 /* No capabilities to register */
60 static void socket_close (gpointer handle)
65 g_message ("%s: closing socket handle %p", __func__, handle);
68 if (startup_count == 0) {
69 WSASetLastError (WSANOTINITIALISED);
73 g_ptr_array_remove_fast (sockets, handle);
76 ret = close (GPOINTER_TO_UINT(handle));
77 } while (ret == -1 && errno == EINTR &&
78 !_wapi_thread_cur_apc_pending ());
83 g_message ("%s: close error: %s", __func__, strerror (errno));
85 errnum = errno_to_WSA (errnum, __func__);
86 WSASetLastError (errnum);
90 int WSAStartup(guint32 requested, WapiWSAData *data)
97 if (requested < MAKEWORD(2,0)) {
98 return(WSAVERNOTSUPPORTED);
101 if (startup_count == 0) {
102 sockets = g_ptr_array_new();
107 /* I've no idea what is the minor version of the spec I read */
108 data->wHighVersion = MAKEWORD(2,0);
110 data->wVersion = requested < data->wHighVersion? requested:
114 g_message ("%s: high version 0x%x", __func__, data->wHighVersion);
117 strncpy (data->szDescription, "WAPI", WSADESCRIPTION_LEN);
118 strncpy (data->szSystemStatus, "groovy", WSASYS_STATUS_LEN);
128 g_message ("%s: cleaning up", __func__);
131 if (--startup_count) {
136 /* Close down all sockets */
137 for (i = 0; i < sockets->len; i++) {
140 handle = g_ptr_array_index (sockets, i);
141 _wapi_handle_ops_close (handle);
144 g_ptr_array_free (sockets, FALSE);
150 static void error_init(void)
154 ret = pthread_key_create (&error_key, NULL);
158 void WSASetLastError(int error)
162 mono_once (&error_key_once, error_init);
163 ret = pthread_setspecific (error_key, GINT_TO_POINTER(error));
167 int WSAGetLastError(void)
172 mono_once (&error_key_once, error_init);
173 errptr = pthread_getspecific (error_key);
174 err = GPOINTER_TO_INT(errptr);
179 int closesocket(guint32 fd)
181 gpointer handle = GUINT_TO_POINTER (fd);
183 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
184 WSASetLastError (WSAENOTSOCK);
188 _wapi_handle_unref (handle);
192 guint32 _wapi_accept(guint32 fd, struct sockaddr *addr, socklen_t *addrlen)
194 gpointer handle = GUINT_TO_POINTER (fd);
198 if (startup_count == 0) {
199 WSASetLastError (WSANOTINITIALISED);
200 return(INVALID_SOCKET);
203 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
204 WSASetLastError (WSAENOTSOCK);
205 return(INVALID_SOCKET);
209 new_fd = accept (fd, addr, addrlen);
210 } while (new_fd == -1 && errno == EINTR &&
211 !_wapi_thread_cur_apc_pending());
216 g_message ("%s: accept error: %s", __func__, strerror(errno));
219 errnum = errno_to_WSA (errnum, __func__);
220 WSASetLastError (errnum);
222 return(INVALID_SOCKET);
225 if (new_fd >= _wapi_fd_reserve) {
227 g_message ("%s: File descriptor is too big", __func__);
230 WSASetLastError (WSASYSCALLFAILURE);
234 return(INVALID_SOCKET);
237 new_handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, new_fd, NULL);
238 if(new_handle == _WAPI_HANDLE_INVALID) {
239 g_warning ("%s: error creating socket handle", __func__);
240 WSASetLastError (ERROR_GEN_FAILURE);
241 return(INVALID_SOCKET);
244 g_ptr_array_add (sockets, new_handle);
247 g_message ("%s: returning newly accepted socket handle %p with",
248 __func__, new_handle);
254 int _wapi_bind(guint32 fd, struct sockaddr *my_addr, socklen_t addrlen)
256 gpointer handle = GUINT_TO_POINTER (fd);
259 if (startup_count == 0) {
260 WSASetLastError (WSANOTINITIALISED);
261 return(SOCKET_ERROR);
264 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
265 WSASetLastError (WSAENOTSOCK);
266 return(SOCKET_ERROR);
269 ret = bind (fd, my_addr, addrlen);
273 g_message ("%s: bind error: %s", __func__, strerror(errno));
275 errnum = errno_to_WSA (errnum, __func__);
276 WSASetLastError (errnum);
278 return(SOCKET_ERROR);
283 int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr,
286 gpointer handle = GUINT_TO_POINTER (fd);
290 if (startup_count == 0) {
291 WSASetLastError (WSANOTINITIALISED);
292 return(SOCKET_ERROR);
295 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
296 WSASetLastError (WSAENOTSOCK);
297 return(SOCKET_ERROR);
301 ret = connect (fd, serv_addr, addrlen);
302 } while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
304 if (ret == -1 && errno == EACCES) {
305 /* Try setting SO_BROADCAST and connecting again, but
306 * keep the original errno
312 ret = setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &true,
316 ret = connect (fd, serv_addr, addrlen);
317 } while (ret==-1 && errno==EINTR &&
318 !_wapi_thread_cur_apc_pending());
320 } else if (ret == -1) {
326 g_message ("%s: connect error: %s", __func__,
329 errnum = errno_to_WSA (errnum, __func__);
330 if (errnum == WSAEINPROGRESS)
331 errnum = WSAEWOULDBLOCK; /* see bug #73053 */
333 WSASetLastError (errnum);
335 return(SOCKET_ERROR);
340 int _wapi_getpeername(guint32 fd, struct sockaddr *name, socklen_t *namelen)
342 gpointer handle = GUINT_TO_POINTER (fd);
345 if (startup_count == 0) {
346 WSASetLastError (WSANOTINITIALISED);
347 return(SOCKET_ERROR);
350 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
351 WSASetLastError (WSAENOTSOCK);
352 return(SOCKET_ERROR);
355 ret = getpeername (fd, name, namelen);
359 g_message ("%s: getpeername error: %s", __func__,
363 errnum = errno_to_WSA (errnum, __func__);
364 WSASetLastError (errnum);
366 return(SOCKET_ERROR);
372 int _wapi_getsockname(guint32 fd, struct sockaddr *name, socklen_t *namelen)
374 gpointer handle = GUINT_TO_POINTER (fd);
377 if (startup_count == 0) {
378 WSASetLastError (WSANOTINITIALISED);
379 return(SOCKET_ERROR);
382 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
383 WSASetLastError (WSAENOTSOCK);
384 return(SOCKET_ERROR);
387 ret = getsockname (fd, name, namelen);
391 g_message ("%s: getsockname error: %s", __func__,
395 errnum = errno_to_WSA (errnum, __func__);
396 WSASetLastError (errnum);
398 return(SOCKET_ERROR);
404 int _wapi_getsockopt(guint32 fd, int level, int optname, void *optval,
407 gpointer handle = GUINT_TO_POINTER (fd);
410 if (startup_count == 0) {
411 WSASetLastError (WSANOTINITIALISED);
412 return(SOCKET_ERROR);
415 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
416 WSASetLastError (WSAENOTSOCK);
417 return(SOCKET_ERROR);
420 ret = getsockopt (fd, level, optname, optval, optlen);
424 g_message ("%s: getsockopt error: %s", __func__,
428 errnum = errno_to_WSA (errnum, __func__);
429 WSASetLastError (errnum);
431 return(SOCKET_ERROR);
437 int _wapi_listen(guint32 fd, int backlog)
439 gpointer handle = GUINT_TO_POINTER (fd);
442 if (startup_count == 0) {
443 WSASetLastError (WSANOTINITIALISED);
444 return(SOCKET_ERROR);
447 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
448 WSASetLastError (WSAENOTSOCK);
449 return(SOCKET_ERROR);
452 ret = listen (fd, backlog);
456 g_message ("%s: listen error: %s", __func__, strerror (errno));
459 errnum = errno_to_WSA (errnum, __func__);
460 WSASetLastError (errnum);
462 return(SOCKET_ERROR);
468 int _wapi_recv(guint32 fd, void *buf, size_t len, int recv_flags)
470 return(_wapi_recvfrom (fd, buf, len, recv_flags, NULL, 0));
473 int _wapi_recvfrom(guint32 fd, void *buf, size_t len, int recv_flags,
474 struct sockaddr *from, socklen_t *fromlen)
476 #ifndef HAVE_MSG_NOSIGNAL
477 void (*old_sigpipe)(int); // old SIGPIPE handler
479 gpointer handle = GUINT_TO_POINTER (fd);
482 if (startup_count == 0) {
483 WSASetLastError (WSANOTINITIALISED);
484 return(SOCKET_ERROR);
487 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
488 WSASetLastError (WSAENOTSOCK);
489 return(SOCKET_ERROR);
492 #ifdef HAVE_MSG_NOSIGNAL
494 ret = recvfrom (fd, buf, len, recv_flags | MSG_NOSIGNAL, from,
496 } while (ret == -1 && errno == EINTR &&
497 !_wapi_thread_cur_apc_pending ());
499 old_sigpipe = signal (SIGPIPE, SIG_IGN);
501 ret = recvfrom (fd, buf, len, recv_flags, from, fromlen);
502 } while (ret == -1 && errno == EINTR &&
503 !_wapi_thread_cur_apc_pending ());
504 signal (SIGPIPE, old_sigpipe);
510 g_message ("%s: recv error: %s", __func__, strerror(errno));
513 errnum = errno_to_WSA (errnum, __func__);
514 WSASetLastError (errnum);
516 return(SOCKET_ERROR);
521 int _wapi_send(guint32 fd, const void *msg, size_t len, int send_flags)
523 #ifndef HAVE_MSG_NOSIGNAL
524 void (*old_sigpipe)(int); // old SIGPIPE handler
526 gpointer handle = GUINT_TO_POINTER (fd);
529 if (startup_count == 0) {
530 WSASetLastError (WSANOTINITIALISED);
531 return(SOCKET_ERROR);
534 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
535 WSASetLastError (WSAENOTSOCK);
536 return(SOCKET_ERROR);
539 #ifdef HAVE_MSG_NOSIGNAL
541 ret = send (fd, msg, len, send_flags | MSG_NOSIGNAL);
542 } while (ret == -1 && errno == EINTR &&
543 !_wapi_thread_cur_apc_pending ());
545 old_sigpipe = signal (SIGPIPE, SIG_IGN);
547 ret = send (fd, msg, len, send_flags);
548 } while (ret == -1 && errno == EINTR &&
549 !_wapi_thread_cur_apc_pending ());
550 signal (SIGPIPE, old_sigpipe);
555 g_message ("%s: send error: %s", __func__, strerror (errno));
558 errnum = errno_to_WSA (errnum, __func__);
559 WSASetLastError (errnum);
561 return(SOCKET_ERROR);
566 int _wapi_sendto(guint32 fd, const void *msg, size_t len, int send_flags,
567 const struct sockaddr *to, socklen_t tolen)
569 #ifndef HAVE_MSG_NOSIGNAL
570 void (*old_sigpipe)(int); // old SIGPIPE handler
572 gpointer handle = GUINT_TO_POINTER (fd);
575 if (startup_count == 0) {
576 WSASetLastError (WSANOTINITIALISED);
577 return(SOCKET_ERROR);
580 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
581 WSASetLastError (WSAENOTSOCK);
582 return(SOCKET_ERROR);
585 #ifdef HAVE_MSG_NOSIGNAL
587 ret = sendto (fd, msg, len, send_flags | MSG_NOSIGNAL, to,
589 } while (ret == -1 && errno == EINTR &&
590 !_wapi_thread_cur_apc_pending ());
592 old_sigpipe = signal (SIGPIPE, SIG_IGN);
594 ret = sendto (fd, msg, len, send_flags, to, tolen);
595 } while (ret == -1 && errno == EINTR &&
596 !_wapi_thread_cur_apc_pending ());
597 signal (SIGPIPE, old_sigpipe);
602 g_message ("%s: send error: %s", __func__, strerror (errno));
605 errnum = errno_to_WSA (errnum, __func__);
606 WSASetLastError (errnum);
608 return(SOCKET_ERROR);
613 int _wapi_setsockopt(guint32 fd, int level, int optname,
614 const void *optval, socklen_t optlen)
616 gpointer handle = GUINT_TO_POINTER (fd);
619 if (startup_count == 0) {
620 WSASetLastError (WSANOTINITIALISED);
621 return(SOCKET_ERROR);
624 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
625 WSASetLastError (WSAENOTSOCK);
626 return(SOCKET_ERROR);
629 ret = setsockopt (fd, level, optname, optval, optlen);
633 g_message ("%s: setsockopt error: %s", __func__,
637 errnum = errno_to_WSA (errnum, __func__);
638 WSASetLastError (errnum);
640 return(SOCKET_ERROR);
646 int _wapi_shutdown(guint32 fd, int how)
648 gpointer handle = GUINT_TO_POINTER (fd);
651 if (startup_count == 0) {
652 WSASetLastError (WSANOTINITIALISED);
653 return(SOCKET_ERROR);
656 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
657 WSASetLastError (WSAENOTSOCK);
658 return(SOCKET_ERROR);
661 ret = shutdown (fd, how);
665 g_message ("%s: shutdown error: %s", __func__,
669 errnum = errno_to_WSA (errnum, __func__);
670 WSASetLastError (errnum);
672 return(SOCKET_ERROR);
678 guint32 _wapi_socket(int domain, int type, int protocol, void *unused,
679 guint32 unused2, guint32 unused3)
684 fd = socket (domain, type, protocol);
685 if (fd == -1 && domain == AF_INET && type == SOCK_RAW &&
687 /* Retry with protocol == 4 (see bug #54565) */
688 fd = socket (AF_INET, SOCK_RAW, 4);
694 g_message ("%s: socket error: %s", __func__, strerror (errno));
696 errnum = errno_to_WSA (errnum, __func__);
697 WSASetLastError (errnum);
699 return(INVALID_SOCKET);
702 if (fd >= _wapi_fd_reserve) {
704 g_message ("%s: File descriptor is too big", __func__);
707 WSASetLastError (WSASYSCALLFAILURE);
710 return(INVALID_SOCKET);
714 mono_once (&socket_ops_once, socket_ops_init);
716 handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, fd, NULL);
717 if (handle == _WAPI_HANDLE_INVALID) {
718 g_warning ("%s: error creating socket handle", __func__);
719 return(INVALID_SOCKET);
722 g_ptr_array_add (sockets, handle);
725 g_message ("%s: returning socket handle %p", __func__, handle);
731 struct hostent *_wapi_gethostbyname(const char *hostname)
735 if (startup_count == 0) {
736 WSASetLastError (WSANOTINITIALISED);
740 he = gethostbyname (hostname);
743 g_message ("%s: gethostbyname error: %s", __func__,
749 WSASetLastError (WSAHOST_NOT_FOUND);
751 #if NO_ADDRESS != NO_DATA
755 WSASetLastError (WSANO_DATA);
758 WSASetLastError (WSANO_RECOVERY);
761 WSASetLastError (WSATRY_AGAIN);
764 g_warning ("%s: Need to translate %d into winsock error", __func__, h_errno);
773 WSAIoctl (guint32 fd, gint32 command,
774 gchar *input, gint i_len,
775 gchar *output, gint o_len, glong *written,
776 void *unused1, void *unused2)
778 gpointer handle = GUINT_TO_POINTER (fd);
780 gchar *buffer = NULL;
782 if (startup_count == 0) {
783 WSASetLastError (WSANOTINITIALISED);
784 return(SOCKET_ERROR);
787 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
788 WSASetLastError (WSAENOTSOCK);
793 buffer = g_memdup (input, i_len);
796 ret = ioctl (fd, command, buffer);
800 g_message("%s: WSAIoctl error: %s", __func__,
804 errnum = errno_to_WSA (errnum, __func__);
805 WSASetLastError (errnum);
808 return(SOCKET_ERROR);
811 if (buffer == NULL) {
814 /* We just copy the buffer to the output. Some ioctls
815 * don't even output any data, but, well...
817 i_len = (i_len > o_len) ? o_len : i_len;
818 memcpy (output, buffer, i_len);
826 int ioctlsocket(guint32 fd, gint32 command, gpointer arg)
828 gpointer handle = GUINT_TO_POINTER (fd);
831 if (startup_count == 0) {
832 WSASetLastError (WSANOTINITIALISED);
833 return(SOCKET_ERROR);
836 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
837 WSASetLastError (WSAENOTSOCK);
838 return(SOCKET_ERROR);
841 if (command != FIONBIO &&
842 command != FIONREAD &&
843 command != SIOCATMARK) {
844 /* Not listed in the MSDN specs, but ioctl(2) returns
845 * this if command is invalid
847 WSASetLastError (WSAEINVAL);
848 return(SOCKET_ERROR);
852 /* This works better than ioctl(...FIONBIO...) on Linux (it causes
853 * connect to return EINPROGRESS, but the ioctl doesn't seem to)
855 if (command == FIONBIO) {
856 ret = fcntl (fd, F_GETFL, 0);
858 if (*(gboolean *)arg) {
863 ret = fcntl (fd, F_SETFL, ret);
866 #endif /* O_NONBLOCK */
868 ret = ioctl (fd, command, arg);
873 g_message ("%s: ioctl error: %s", __func__, strerror (errno));
876 errnum = errno_to_WSA (errnum, __func__);
877 WSASetLastError (errnum);
879 return(SOCKET_ERROR);
885 int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds,
886 fd_set *exceptfds, struct timeval *timeout)
890 if (startup_count == 0) {
891 WSASetLastError (WSANOTINITIALISED);
892 return(SOCKET_ERROR);
896 ret = select(getdtablesize (), readfds, writefds, exceptfds,
898 } while (ret == -1 && errno == EINTR &&
899 !_wapi_thread_cur_apc_pending ());
904 g_message ("%s: select error: %s", __func__, strerror (errno));
906 errnum = errno_to_WSA (errnum, __func__);
907 WSASetLastError (errnum);
909 return(SOCKET_ERROR);
915 void _wapi_FD_CLR(guint32 fd, fd_set *set)
917 gpointer handle = GUINT_TO_POINTER (fd);
919 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
920 WSASetLastError (WSAENOTSOCK);
927 int _wapi_FD_ISSET(guint32 fd, fd_set *set)
929 gpointer handle = GUINT_TO_POINTER (fd);
931 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
932 WSASetLastError (WSAENOTSOCK);
936 return(FD_ISSET (fd, set));
939 void _wapi_FD_SET(guint32 fd, fd_set *set)
941 gpointer handle = GUINT_TO_POINTER (fd);
943 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
944 WSASetLastError (WSAENOTSOCK);