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 pthread_key_t error_key;
41 static mono_once_t error_key_once=MONO_ONCE_INIT;
43 static void socket_close (gpointer handle, gpointer data);
45 struct _WapiHandleOps _wapi_socket_ops = {
46 socket_close, /* close */
52 static mono_once_t socket_ops_once=MONO_ONCE_INIT;
54 static void socket_ops_init (void)
56 /* No capabilities to register */
59 static void socket_close (gpointer handle, gpointer data G_GNUC_UNUSED)
64 g_message ("%s: closing socket handle %p", __func__, handle);
67 if (startup_count == 0) {
68 WSASetLastError (WSANOTINITIALISED);
73 ret = close (GPOINTER_TO_UINT(handle));
74 } while (ret == -1 && errno == EINTR &&
75 !_wapi_thread_cur_apc_pending ());
80 g_message ("%s: close error: %s", __func__, strerror (errno));
82 errnum = errno_to_WSA (errnum, __func__);
83 WSASetLastError (errnum);
87 int WSAStartup(guint32 requested, WapiWSAData *data)
94 if (requested < MAKEWORD(2,0)) {
95 return(WSAVERNOTSUPPORTED);
100 /* I've no idea what is the minor version of the spec I read */
101 data->wHighVersion = MAKEWORD(2,0);
103 data->wVersion = requested < data->wHighVersion? requested:
107 g_message ("%s: high version 0x%x", __func__, data->wHighVersion);
110 strncpy (data->szDescription, "WAPI", WSADESCRIPTION_LEN);
111 strncpy (data->szSystemStatus, "groovy", WSASYS_STATUS_LEN);
117 cleanup_close (gpointer handle, gpointer data)
119 _wapi_handle_ops_close (handle, NULL);
126 g_message ("%s: cleaning up", __func__);
129 if (--startup_count) {
134 _wapi_handle_foreach (WAPI_HANDLE_SOCKET, cleanup_close, NULL);
138 static void error_init(void)
142 ret = pthread_key_create (&error_key, NULL);
146 void WSASetLastError(int error)
150 mono_once (&error_key_once, error_init);
151 ret = pthread_setspecific (error_key, GINT_TO_POINTER(error));
155 int WSAGetLastError(void)
160 mono_once (&error_key_once, error_init);
161 errptr = pthread_getspecific (error_key);
162 err = GPOINTER_TO_INT(errptr);
167 int closesocket(guint32 fd)
169 gpointer handle = GUINT_TO_POINTER (fd);
171 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
172 WSASetLastError (WSAENOTSOCK);
176 _wapi_handle_unref (handle);
180 guint32 _wapi_accept(guint32 fd, struct sockaddr *addr, socklen_t *addrlen)
182 gpointer handle = GUINT_TO_POINTER (fd);
186 if (startup_count == 0) {
187 WSASetLastError (WSANOTINITIALISED);
188 return(INVALID_SOCKET);
191 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
192 WSASetLastError (WSAENOTSOCK);
193 return(INVALID_SOCKET);
197 new_fd = accept (fd, addr, addrlen);
198 } while (new_fd == -1 && errno == EINTR &&
199 !_wapi_thread_cur_apc_pending());
204 g_message ("%s: accept error: %s", __func__, strerror(errno));
207 errnum = errno_to_WSA (errnum, __func__);
208 WSASetLastError (errnum);
210 return(INVALID_SOCKET);
213 if (new_fd >= _wapi_fd_reserve) {
215 g_message ("%s: File descriptor is too big", __func__);
218 WSASetLastError (WSASYSCALLFAILURE);
222 return(INVALID_SOCKET);
225 new_handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, new_fd, NULL);
226 if(new_handle == _WAPI_HANDLE_INVALID) {
227 g_warning ("%s: error creating socket handle", __func__);
228 WSASetLastError (ERROR_GEN_FAILURE);
229 return(INVALID_SOCKET);
233 g_message ("%s: returning newly accepted socket handle %p with",
234 __func__, new_handle);
240 int _wapi_bind(guint32 fd, struct sockaddr *my_addr, socklen_t addrlen)
242 gpointer handle = GUINT_TO_POINTER (fd);
245 if (startup_count == 0) {
246 WSASetLastError (WSANOTINITIALISED);
247 return(SOCKET_ERROR);
250 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
251 WSASetLastError (WSAENOTSOCK);
252 return(SOCKET_ERROR);
255 ret = bind (fd, my_addr, addrlen);
259 g_message ("%s: bind error: %s", __func__, strerror(errno));
261 errnum = errno_to_WSA (errnum, __func__);
262 WSASetLastError (errnum);
264 return(SOCKET_ERROR);
269 int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr,
272 gpointer handle = GUINT_TO_POINTER (fd);
276 if (startup_count == 0) {
277 WSASetLastError (WSANOTINITIALISED);
278 return(SOCKET_ERROR);
281 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
282 WSASetLastError (WSAENOTSOCK);
283 return(SOCKET_ERROR);
287 ret = connect (fd, serv_addr, addrlen);
288 } while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
290 if (ret == -1 && errno == EACCES) {
291 /* Try setting SO_BROADCAST and connecting again, but
292 * keep the original errno
298 ret = setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &true,
302 ret = connect (fd, serv_addr, addrlen);
303 } while (ret==-1 && errno==EINTR &&
304 !_wapi_thread_cur_apc_pending());
306 } else if (ret == -1) {
312 g_message ("%s: connect error: %s", __func__,
315 errnum = errno_to_WSA (errnum, __func__);
316 if (errnum == WSAEINPROGRESS)
317 errnum = WSAEWOULDBLOCK; /* see bug #73053 */
319 WSASetLastError (errnum);
321 return(SOCKET_ERROR);
326 int _wapi_getpeername(guint32 fd, struct sockaddr *name, socklen_t *namelen)
328 gpointer handle = GUINT_TO_POINTER (fd);
331 if (startup_count == 0) {
332 WSASetLastError (WSANOTINITIALISED);
333 return(SOCKET_ERROR);
336 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
337 WSASetLastError (WSAENOTSOCK);
338 return(SOCKET_ERROR);
341 ret = getpeername (fd, name, namelen);
345 g_message ("%s: getpeername error: %s", __func__,
349 errnum = errno_to_WSA (errnum, __func__);
350 WSASetLastError (errnum);
352 return(SOCKET_ERROR);
358 int _wapi_getsockname(guint32 fd, struct sockaddr *name, socklen_t *namelen)
360 gpointer handle = GUINT_TO_POINTER (fd);
363 if (startup_count == 0) {
364 WSASetLastError (WSANOTINITIALISED);
365 return(SOCKET_ERROR);
368 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
369 WSASetLastError (WSAENOTSOCK);
370 return(SOCKET_ERROR);
373 ret = getsockname (fd, name, namelen);
377 g_message ("%s: getsockname error: %s", __func__,
381 errnum = errno_to_WSA (errnum, __func__);
382 WSASetLastError (errnum);
384 return(SOCKET_ERROR);
390 int _wapi_getsockopt(guint32 fd, int level, int optname, void *optval,
393 gpointer handle = GUINT_TO_POINTER (fd);
398 if (startup_count == 0) {
399 WSASetLastError (WSANOTINITIALISED);
400 return(SOCKET_ERROR);
403 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
404 WSASetLastError (WSAENOTSOCK);
405 return(SOCKET_ERROR);
409 if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) {
411 *optlen = sizeof (tv);
414 ret = getsockopt (fd, level, optname, tmp_val, optlen);
418 g_message ("%s: getsockopt error: %s", __func__,
422 errnum = errno_to_WSA (errnum, __func__);
423 WSASetLastError (errnum);
425 return(SOCKET_ERROR);
428 if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) {
429 *((int *) optval) = tv.tv_sec * 1000 + tv.tv_usec;
430 *optlen = sizeof (int);
436 int _wapi_listen(guint32 fd, int backlog)
438 gpointer handle = GUINT_TO_POINTER (fd);
441 if (startup_count == 0) {
442 WSASetLastError (WSANOTINITIALISED);
443 return(SOCKET_ERROR);
446 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
447 WSASetLastError (WSAENOTSOCK);
448 return(SOCKET_ERROR);
451 ret = listen (fd, backlog);
455 g_message ("%s: listen error: %s", __func__, strerror (errno));
458 errnum = errno_to_WSA (errnum, __func__);
459 WSASetLastError (errnum);
461 return(SOCKET_ERROR);
467 int _wapi_recv(guint32 fd, void *buf, size_t len, int recv_flags)
469 return(_wapi_recvfrom (fd, buf, len, recv_flags, NULL, 0));
472 int _wapi_recvfrom(guint32 fd, void *buf, size_t len, int recv_flags,
473 struct sockaddr *from, socklen_t *fromlen)
475 #ifndef HAVE_MSG_NOSIGNAL
476 void (*old_sigpipe)(int); // old SIGPIPE handler
478 gpointer handle = GUINT_TO_POINTER (fd);
481 if (startup_count == 0) {
482 WSASetLastError (WSANOTINITIALISED);
483 return(SOCKET_ERROR);
486 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
487 WSASetLastError (WSAENOTSOCK);
488 return(SOCKET_ERROR);
491 #ifdef HAVE_MSG_NOSIGNAL
493 ret = recvfrom (fd, buf, len, recv_flags | MSG_NOSIGNAL, from,
495 } while (ret == -1 && errno == EINTR &&
496 !_wapi_thread_cur_apc_pending ());
498 old_sigpipe = signal (SIGPIPE, SIG_IGN);
500 ret = recvfrom (fd, buf, len, recv_flags, from, fromlen);
501 } while (ret == -1 && errno == EINTR &&
502 !_wapi_thread_cur_apc_pending ());
503 signal (SIGPIPE, old_sigpipe);
509 g_message ("%s: recv error: %s", __func__, strerror(errno));
512 errnum = errno_to_WSA (errnum, __func__);
513 WSASetLastError (errnum);
515 return(SOCKET_ERROR);
520 int _wapi_send(guint32 fd, const void *msg, size_t len, int send_flags)
522 #ifndef HAVE_MSG_NOSIGNAL
523 void (*old_sigpipe)(int); // old SIGPIPE handler
525 gpointer handle = GUINT_TO_POINTER (fd);
528 if (startup_count == 0) {
529 WSASetLastError (WSANOTINITIALISED);
530 return(SOCKET_ERROR);
533 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
534 WSASetLastError (WSAENOTSOCK);
535 return(SOCKET_ERROR);
538 #ifdef HAVE_MSG_NOSIGNAL
540 ret = send (fd, msg, len, send_flags | MSG_NOSIGNAL);
541 } while (ret == -1 && errno == EINTR &&
542 !_wapi_thread_cur_apc_pending ());
544 old_sigpipe = signal (SIGPIPE, SIG_IGN);
546 ret = send (fd, msg, len, send_flags);
547 } while (ret == -1 && errno == EINTR &&
548 !_wapi_thread_cur_apc_pending ());
549 signal (SIGPIPE, old_sigpipe);
554 g_message ("%s: send error: %s", __func__, strerror (errno));
557 errnum = errno_to_WSA (errnum, __func__);
558 WSASetLastError (errnum);
560 return(SOCKET_ERROR);
565 int _wapi_sendto(guint32 fd, const void *msg, size_t len, int send_flags,
566 const struct sockaddr *to, socklen_t tolen)
568 #ifndef HAVE_MSG_NOSIGNAL
569 void (*old_sigpipe)(int); // old SIGPIPE handler
571 gpointer handle = GUINT_TO_POINTER (fd);
574 if (startup_count == 0) {
575 WSASetLastError (WSANOTINITIALISED);
576 return(SOCKET_ERROR);
579 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
580 WSASetLastError (WSAENOTSOCK);
581 return(SOCKET_ERROR);
584 #ifdef HAVE_MSG_NOSIGNAL
586 ret = sendto (fd, msg, len, send_flags | MSG_NOSIGNAL, to,
588 } while (ret == -1 && errno == EINTR &&
589 !_wapi_thread_cur_apc_pending ());
591 old_sigpipe = signal (SIGPIPE, SIG_IGN);
593 ret = sendto (fd, msg, len, send_flags, to, tolen);
594 } while (ret == -1 && errno == EINTR &&
595 !_wapi_thread_cur_apc_pending ());
596 signal (SIGPIPE, old_sigpipe);
601 g_message ("%s: send error: %s", __func__, strerror (errno));
604 errnum = errno_to_WSA (errnum, __func__);
605 WSASetLastError (errnum);
607 return(SOCKET_ERROR);
612 int _wapi_setsockopt(guint32 fd, int level, int optname,
613 const void *optval, socklen_t optlen)
615 gpointer handle = GUINT_TO_POINTER (fd);
620 if (startup_count == 0) {
621 WSASetLastError (WSANOTINITIALISED);
622 return(SOCKET_ERROR);
625 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
626 WSASetLastError (WSAENOTSOCK);
627 return(SOCKET_ERROR);
631 if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) {
632 int ms = *((int *) optval);
633 tv.tv_sec = ms / 1000;
634 tv.tv_usec = ms % 1000;
636 optlen = sizeof (tv);
639 ret = setsockopt (fd, level, optname, tmp_val, optlen);
643 g_message ("%s: setsockopt error: %s", __func__,
647 errnum = errno_to_WSA (errnum, __func__);
648 WSASetLastError (errnum);
650 return(SOCKET_ERROR);
656 int _wapi_shutdown(guint32 fd, int how)
658 gpointer handle = GUINT_TO_POINTER (fd);
661 if (startup_count == 0) {
662 WSASetLastError (WSANOTINITIALISED);
663 return(SOCKET_ERROR);
666 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
667 WSASetLastError (WSAENOTSOCK);
668 return(SOCKET_ERROR);
671 ret = shutdown (fd, how);
675 g_message ("%s: shutdown error: %s", __func__,
679 errnum = errno_to_WSA (errnum, __func__);
680 WSASetLastError (errnum);
682 return(SOCKET_ERROR);
688 guint32 _wapi_socket(int domain, int type, int protocol, void *unused,
689 guint32 unused2, guint32 unused3)
694 fd = socket (domain, type, protocol);
695 if (fd == -1 && domain == AF_INET && type == SOCK_RAW &&
697 /* Retry with protocol == 4 (see bug #54565) */
698 fd = socket (AF_INET, SOCK_RAW, 4);
704 g_message ("%s: socket error: %s", __func__, strerror (errno));
706 errnum = errno_to_WSA (errnum, __func__);
707 WSASetLastError (errnum);
709 return(INVALID_SOCKET);
712 if (fd >= _wapi_fd_reserve) {
714 g_message ("%s: File descriptor is too big", __func__);
717 WSASetLastError (WSASYSCALLFAILURE);
720 return(INVALID_SOCKET);
724 mono_once (&socket_ops_once, socket_ops_init);
726 handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, fd, NULL);
727 if (handle == _WAPI_HANDLE_INVALID) {
728 g_warning ("%s: error creating socket handle", __func__);
729 return(INVALID_SOCKET);
733 g_message ("%s: returning socket handle %p", __func__, handle);
739 struct hostent *_wapi_gethostbyname(const char *hostname)
743 if (startup_count == 0) {
744 WSASetLastError (WSANOTINITIALISED);
748 he = gethostbyname (hostname);
751 g_message ("%s: gethostbyname error: %s", __func__,
757 WSASetLastError (WSAHOST_NOT_FOUND);
759 #if NO_ADDRESS != NO_DATA
763 WSASetLastError (WSANO_DATA);
766 WSASetLastError (WSANO_RECOVERY);
769 WSASetLastError (WSATRY_AGAIN);
772 g_warning ("%s: Need to translate %d into winsock error", __func__, h_errno);
781 WSAIoctl (guint32 fd, gint32 command,
782 gchar *input, gint i_len,
783 gchar *output, gint o_len, glong *written,
784 void *unused1, void *unused2)
786 gpointer handle = GUINT_TO_POINTER (fd);
788 gchar *buffer = NULL;
790 if (startup_count == 0) {
791 WSASetLastError (WSANOTINITIALISED);
792 return(SOCKET_ERROR);
795 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
796 WSASetLastError (WSAENOTSOCK);
801 buffer = g_memdup (input, i_len);
804 ret = ioctl (fd, command, buffer);
808 g_message("%s: WSAIoctl error: %s", __func__,
812 errnum = errno_to_WSA (errnum, __func__);
813 WSASetLastError (errnum);
816 return(SOCKET_ERROR);
819 if (buffer == NULL) {
822 /* We just copy the buffer to the output. Some ioctls
823 * don't even output any data, but, well...
825 i_len = (i_len > o_len) ? o_len : i_len;
826 memcpy (output, buffer, i_len);
834 int ioctlsocket(guint32 fd, gint32 command, gpointer arg)
836 gpointer handle = GUINT_TO_POINTER (fd);
839 if (startup_count == 0) {
840 WSASetLastError (WSANOTINITIALISED);
841 return(SOCKET_ERROR);
844 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
845 WSASetLastError (WSAENOTSOCK);
846 return(SOCKET_ERROR);
849 if (command != FIONBIO &&
850 command != FIONREAD &&
851 command != SIOCATMARK) {
852 /* Not listed in the MSDN specs, but ioctl(2) returns
853 * this if command is invalid
855 WSASetLastError (WSAEINVAL);
856 return(SOCKET_ERROR);
860 /* This works better than ioctl(...FIONBIO...) on Linux (it causes
861 * connect to return EINPROGRESS, but the ioctl doesn't seem to)
863 if (command == FIONBIO) {
864 ret = fcntl (fd, F_GETFL, 0);
866 if (*(gboolean *)arg) {
871 ret = fcntl (fd, F_SETFL, ret);
874 #endif /* O_NONBLOCK */
876 ret = ioctl (fd, command, arg);
881 g_message ("%s: ioctl error: %s", __func__, strerror (errno));
884 errnum = errno_to_WSA (errnum, __func__);
885 WSASetLastError (errnum);
887 return(SOCKET_ERROR);
893 int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds,
894 fd_set *exceptfds, struct timeval *timeout)
898 if (startup_count == 0) {
899 WSASetLastError (WSANOTINITIALISED);
900 return(SOCKET_ERROR);
904 ret = select(getdtablesize (), readfds, writefds, exceptfds,
906 } while (ret == -1 && errno == EINTR &&
907 !_wapi_thread_cur_apc_pending ());
912 g_message ("%s: select error: %s", __func__, strerror (errno));
914 errnum = errno_to_WSA (errnum, __func__);
915 WSASetLastError (errnum);
917 return(SOCKET_ERROR);
923 void _wapi_FD_CLR(guint32 fd, fd_set *set)
925 gpointer handle = GUINT_TO_POINTER (fd);
927 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
928 WSASetLastError (WSAENOTSOCK);
935 int _wapi_FD_ISSET(guint32 fd, fd_set *set)
937 gpointer handle = GUINT_TO_POINTER (fd);
939 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
940 WSASetLastError (WSAENOTSOCK);
944 return(FD_ISSET (fd, set));
947 void _wapi_FD_SET(guint32 fd, fd_set *set)
949 gpointer handle = GUINT_TO_POINTER (fd);
951 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
952 WSASetLastError (WSAENOTSOCK);