Implement vararg support for s390. Minor fix to atomic operation for s390.
[mono.git] / mono / io-layer / sockets.c
blobdf7ac8a25dcc2ff43a15000c381f8fa9bd6e0b34
1 /*
2 * sockets.c: Socket handles
4 * Author:
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
8 */
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #include <errno.h>
14 #include <string.h>
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 */
20 #endif
21 #ifdef HAVE_SYS_SOCKIO_H
22 #include <sys/sockio.h> /* defines SIOCATMARK */
23 #endif
24 #include <unistd.h>
25 #include <fcntl.h>
27 #ifndef HAVE_MSG_NOSIGNAL
28 #include <signal.h>
29 #endif
31 #ifndef PLATFORM_WIN32
32 #ifdef HAVE_AIO_H
33 #include <aio.h>
34 #define USE_AIO 1
35 #elif defined(HAVE_SYS_AIO_H)
36 #include <sys/aio.h>
37 #define USE_AIO 1
38 #else
39 #undef USE_AIO
40 #endif
41 #endif
43 #include <mono/io-layer/wapi.h>
44 #include <mono/io-layer/wapi-private.h>
45 #include <mono/io-layer/socket-private.h>
46 #include <mono/io-layer/handles-private.h>
47 #include <mono/io-layer/socket-wrappers.h>
49 #undef DEBUG
51 static guint32 startup_count=0;
52 static GPtrArray *sockets=NULL;
53 static pthread_key_t error_key;
54 static mono_once_t error_key_once=MONO_ONCE_INIT;
56 static void socket_close_private (gpointer handle);
58 struct _WapiHandleOps _wapi_socket_ops = {
59 NULL, /* close_shared */
60 socket_close_private, /* close_private */
61 NULL, /* signal */
62 NULL, /* own */
63 NULL, /* is_owned */
66 static mono_once_t socket_ops_once=MONO_ONCE_INIT;
68 static void socket_ops_init (void)
70 /* No capabilities to register */
73 static void socket_close_private (gpointer handle)
75 struct _WapiHandlePrivate_socket *socket_private_handle;
76 gboolean ok;
77 int ret;
79 #ifdef DEBUG
80 g_message(G_GNUC_PRETTY_FUNCTION ": closing socket handle %p",
81 handle);
82 #endif
84 if(startup_count==0) {
85 WSASetLastError(WSANOTINITIALISED);
86 return;
89 ok=_wapi_lookup_handle (GUINT_TO_POINTER (handle), WAPI_HANDLE_SOCKET,
90 NULL, (gpointer *)&socket_private_handle);
91 if(ok==FALSE) {
92 g_warning (G_GNUC_PRETTY_FUNCTION
93 ": error looking up socket handle %p", handle);
94 WSASetLastError(WSAENOTSOCK);
95 return;
98 g_ptr_array_remove_fast(sockets, GUINT_TO_POINTER (handle));
100 if (socket_private_handle->fd_mapped.assigned == TRUE) {
101 /* Blank out the mapping, to make catching errors easier */
102 _wapi_handle_fd_offset_store (socket_private_handle->fd_mapped.fd, NULL);
104 do {
105 ret=close(socket_private_handle->fd_mapped.fd);
107 while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
109 if(ret==-1) {
110 gint errnum = errno;
111 #ifdef DEBUG
112 g_message(G_GNUC_PRETTY_FUNCTION ": close error: %s",
113 strerror(errno));
114 #endif
115 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
116 WSASetLastError (errnum);
118 return;
120 } else {
121 WSASetLastError(WSAENOTSOCK);
125 int WSAStartup(guint32 requested, WapiWSAData *data)
127 if(data==NULL) {
128 return(WSAEFAULT);
131 /* Insist on v2.0+ */
132 if(requested < MAKEWORD(2,0)) {
133 return(WSAVERNOTSUPPORTED);
136 if(startup_count==0) {
137 sockets=g_ptr_array_new();
140 startup_count++;
142 /* I've no idea what is the minor version of the spec I read */
143 data->wHighVersion=MAKEWORD(2,0);
145 data->wVersion=requested < data->wHighVersion? requested:
146 data->wHighVersion;
148 #ifdef DEBUG
149 g_message(G_GNUC_PRETTY_FUNCTION ": high version 0x%x",
150 data->wHighVersion);
151 #endif
153 strncpy(data->szDescription, "WAPI", WSADESCRIPTION_LEN);
154 strncpy(data->szSystemStatus, "groovy", WSASYS_STATUS_LEN);
156 return(0);
159 int WSACleanup(void)
161 guint32 i;
163 #ifdef DEBUG
164 g_message(G_GNUC_PRETTY_FUNCTION ": cleaning up");
165 #endif
167 if(--startup_count) {
168 /* Do nothing */
169 return(0);
172 /* Close down all sockets */
173 for(i=0; i<sockets->len; i++) {
174 gpointer handle;
176 handle=g_ptr_array_index(sockets, i);
177 _wapi_handle_ops_close_private (handle);
180 g_ptr_array_free(sockets, FALSE);
181 sockets=NULL;
183 return(0);
186 static void error_init(void)
188 int ret;
190 ret = pthread_key_create(&error_key, NULL);
191 g_assert (ret == 0);
194 void WSASetLastError(int error)
196 int ret;
198 mono_once(&error_key_once, error_init);
199 ret = pthread_setspecific(error_key, GINT_TO_POINTER(error));
200 g_assert (ret == 0);
203 int WSAGetLastError(void)
205 int err;
206 void *errptr;
208 mono_once(&error_key_once, error_init);
209 errptr=pthread_getspecific(error_key);
210 err=GPOINTER_TO_INT(errptr);
212 return(err);
215 int closesocket(guint32 fd_handle)
217 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd_handle));
219 if (handle == NULL ||
220 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
221 WSASetLastError (WSAENOTSOCK);
222 return(0);
225 _wapi_handle_unref (handle);
226 return(0);
229 guint32 _wapi_accept(guint32 fd, struct sockaddr *addr, socklen_t *addrlen)
231 struct _WapiHandlePrivate_socket *new_socket_private_handle;
232 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
233 gpointer new_handle;
234 gboolean ok;
235 int new_fd;
236 int thr_ret;
237 guint32 ret = INVALID_SOCKET;
239 if(startup_count==0) {
240 WSASetLastError(WSANOTINITIALISED);
241 return(INVALID_SOCKET);
244 if (handle == NULL ||
245 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
246 WSASetLastError(WSAENOTSOCK);
247 return(INVALID_SOCKET);
250 do {
251 new_fd=accept(fd, addr, addrlen);
253 while (new_fd==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
255 if(new_fd==-1) {
256 gint errnum = errno;
257 #ifdef DEBUG
258 g_message(G_GNUC_PRETTY_FUNCTION ": accept error: %s",
259 strerror(errno));
260 #endif
262 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
263 WSASetLastError (errnum);
265 return(INVALID_SOCKET);
268 if (new_fd >= _wapi_fd_offset_table_size) {
269 #ifdef DEBUG
270 g_message (G_GNUC_PRETTY_FUNCTION ": File descriptor is too big");
271 #endif
273 WSASetLastError (WSASYSCALLFAILURE);
275 close (new_fd);
277 return(INVALID_SOCKET);
280 new_handle=_wapi_handle_new (WAPI_HANDLE_SOCKET);
281 if(new_handle==_WAPI_HANDLE_INVALID) {
282 g_warning (G_GNUC_PRETTY_FUNCTION
283 ": error creating socket handle");
284 WSASetLastError (ERROR_GEN_FAILURE);
285 return(INVALID_SOCKET);
288 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
289 new_handle);
290 thr_ret = _wapi_handle_lock_handle (new_handle);
291 g_assert (thr_ret == 0);
293 ok=_wapi_lookup_handle (new_handle, WAPI_HANDLE_SOCKET, NULL,
294 (gpointer *)&new_socket_private_handle);
295 if(ok==FALSE) {
296 g_warning (G_GNUC_PRETTY_FUNCTION
297 ": error looking up new socket handle %p",
298 new_handle);
299 goto cleanup;
302 _wapi_handle_fd_offset_store (new_fd, new_handle);
303 ret = new_fd;
305 new_socket_private_handle->fd_mapped.fd = new_fd;
306 new_socket_private_handle->fd_mapped.assigned = TRUE;
308 #ifdef DEBUG
309 g_message(G_GNUC_PRETTY_FUNCTION
310 ": returning newly accepted socket handle %p with fd %d",
311 new_handle, new_socket_private_handle->fd_mapped.fd);
312 #endif
314 cleanup:
315 thr_ret = _wapi_handle_unlock_handle (new_handle);
316 g_assert (thr_ret == 0);
317 pthread_cleanup_pop (0);
319 return(ret);
322 int _wapi_bind(guint32 fd, struct sockaddr *my_addr, socklen_t addrlen)
324 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
325 int ret;
327 if(startup_count==0) {
328 WSASetLastError(WSANOTINITIALISED);
329 return(SOCKET_ERROR);
332 if (handle == NULL ||
333 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
334 WSASetLastError(WSAENOTSOCK);
335 return(SOCKET_ERROR);
338 ret=bind(fd, my_addr, addrlen);
339 if(ret==-1) {
340 gint errnum = errno;
341 #ifdef DEBUG
342 g_message(G_GNUC_PRETTY_FUNCTION ": bind error: %s",
343 strerror(errno));
344 #endif
345 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
346 WSASetLastError (errnum);
348 return(SOCKET_ERROR);
350 return(ret);
353 int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr,
354 socklen_t addrlen)
356 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
357 int ret;
358 gint errnum;
360 if(startup_count==0) {
361 WSASetLastError(WSANOTINITIALISED);
362 return(SOCKET_ERROR);
365 if (handle == NULL ||
366 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
367 WSASetLastError(WSAENOTSOCK);
368 return(SOCKET_ERROR);
371 do {
372 ret=connect(fd, serv_addr, addrlen);
374 while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
376 if(ret==-1 && errno==EACCES) {
377 /* Try setting SO_BROADCAST and connecting again, but
378 * keep the original errno
380 int true=1;
382 errnum = errno;
384 ret=setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &true,
385 sizeof(true));
386 if(ret==0) {
387 do {
388 ret=connect (fd, serv_addr, addrlen);
390 while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
392 } else if (ret==-1) {
393 errnum = errno;
396 if(ret==-1) {
397 #ifdef DEBUG
398 g_message(G_GNUC_PRETTY_FUNCTION ": connect error: %s",
399 strerror(errnum));
400 #endif
401 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
402 WSASetLastError (errnum);
404 return(SOCKET_ERROR);
406 return(ret);
409 int _wapi_getpeername(guint32 fd, struct sockaddr *name, socklen_t *namelen)
411 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
412 int ret;
414 if(startup_count==0) {
415 WSASetLastError(WSANOTINITIALISED);
416 return(SOCKET_ERROR);
419 if (handle == NULL ||
420 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
421 WSASetLastError(WSAENOTSOCK);
422 return(SOCKET_ERROR);
425 ret=getpeername(fd, name, namelen);
426 if(ret==-1) {
427 gint errnum = errno;
428 #ifdef DEBUG
429 g_message(G_GNUC_PRETTY_FUNCTION ": getpeername error: %s",
430 strerror(errno));
431 #endif
433 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
434 WSASetLastError (errnum);
436 return(SOCKET_ERROR);
439 return(ret);
442 int _wapi_getsockname(guint32 fd, struct sockaddr *name, socklen_t *namelen)
444 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
445 int ret;
447 if(startup_count==0) {
448 WSASetLastError(WSANOTINITIALISED);
449 return(SOCKET_ERROR);
452 if (handle == NULL ||
453 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
454 WSASetLastError(WSAENOTSOCK);
455 return(SOCKET_ERROR);
458 ret=getsockname(fd, name, namelen);
459 if(ret==-1) {
460 gint errnum = errno;
461 #ifdef DEBUG
462 g_message(G_GNUC_PRETTY_FUNCTION ": getsockname error: %s",
463 strerror(errno));
464 #endif
466 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
467 WSASetLastError (errnum);
469 return(SOCKET_ERROR);
472 return(ret);
475 int _wapi_getsockopt(guint32 fd, int level, int optname, void *optval,
476 socklen_t *optlen)
478 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
479 int ret;
481 if(startup_count==0) {
482 WSASetLastError(WSANOTINITIALISED);
483 return(SOCKET_ERROR);
486 if (handle == NULL ||
487 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
488 WSASetLastError(WSAENOTSOCK);
489 return(SOCKET_ERROR);
492 ret=getsockopt(fd, level, optname, optval, optlen);
493 if(ret==-1) {
494 gint errnum = errno;
495 #ifdef DEBUG
496 g_message(G_GNUC_PRETTY_FUNCTION ": getsockopt error: %s",
497 strerror(errno));
498 #endif
500 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
501 WSASetLastError (errnum);
503 return(SOCKET_ERROR);
506 return(ret);
509 int _wapi_listen(guint32 fd, int backlog)
511 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
512 int ret;
514 if(startup_count==0) {
515 WSASetLastError(WSANOTINITIALISED);
516 return(SOCKET_ERROR);
519 if (handle == NULL ||
520 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
521 WSASetLastError(WSAENOTSOCK);
522 return(SOCKET_ERROR);
525 ret=listen(fd, backlog);
526 if(ret==-1) {
527 gint errnum = errno;
528 #ifdef DEBUG
529 g_message(G_GNUC_PRETTY_FUNCTION ": listen error: %s",
530 strerror(errno));
531 #endif
533 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
534 WSASetLastError (errnum);
536 return(SOCKET_ERROR);
539 return(0);
542 int _wapi_recv(guint32 fd, void *buf, size_t len, int recv_flags)
544 return(_wapi_recvfrom(fd, buf, len, recv_flags, NULL, 0));
547 int _wapi_recvfrom(guint32 fd, void *buf, size_t len, int recv_flags,
548 struct sockaddr *from, socklen_t *fromlen)
550 #ifndef HAVE_MSG_NOSIGNAL
551 void (*old_sigpipe)(int); // old SIGPIPE handler
552 #endif
553 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
554 int ret;
556 if(startup_count==0) {
557 WSASetLastError(WSANOTINITIALISED);
558 return(SOCKET_ERROR);
561 if (handle == NULL ||
562 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
563 WSASetLastError(WSAENOTSOCK);
564 return(SOCKET_ERROR);
567 #ifdef HAVE_MSG_NOSIGNAL
568 do {
569 ret=recvfrom(fd, buf, len, recv_flags | MSG_NOSIGNAL, from,
570 fromlen);
572 while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
573 #else
574 old_sigpipe = signal(SIGPIPE, SIG_IGN);
575 do {
576 ret=recvfrom(fd, buf, len, recv_flags, from, fromlen);
578 while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
579 signal(SIGPIPE, old_sigpipe);
580 #endif
582 if(ret==-1) {
583 gint errnum = errno;
584 #ifdef DEBUG
585 g_message(G_GNUC_PRETTY_FUNCTION ": recv error: %s",
586 strerror(errno));
587 #endif
589 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
590 WSASetLastError (errnum);
592 return(SOCKET_ERROR);
594 return(ret);
597 int _wapi_send(guint32 fd, const void *msg, size_t len, int send_flags)
599 #ifndef HAVE_MSG_NOSIGNAL
600 void (*old_sigpipe)(int); // old SIGPIPE handler
601 #endif
602 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
603 int ret;
605 if(startup_count==0) {
606 WSASetLastError(WSANOTINITIALISED);
607 return(SOCKET_ERROR);
610 if (handle == NULL ||
611 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
612 WSASetLastError(WSAENOTSOCK);
613 return(SOCKET_ERROR);
616 #ifdef HAVE_MSG_NOSIGNAL
617 do {
618 ret=send(fd, msg, len, send_flags | MSG_NOSIGNAL);
620 while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
621 #else
622 old_sigpipe = signal(SIGPIPE, SIG_IGN);
623 do {
624 ret=send(fd, msg, len, send_flags);
626 while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
627 signal(SIGPIPE, old_sigpipe);
628 #endif
629 if(ret==-1) {
630 gint errnum = errno;
631 #ifdef DEBUG
632 g_message(G_GNUC_PRETTY_FUNCTION ": send error: %s",
633 strerror(errno));
634 #endif
636 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
637 WSASetLastError (errnum);
639 return(SOCKET_ERROR);
641 return(ret);
644 int _wapi_sendto(guint32 fd, const void *msg, size_t len, int send_flags,
645 const struct sockaddr *to, socklen_t tolen)
647 #ifndef HAVE_MSG_NOSIGNAL
648 void (*old_sigpipe)(int); // old SIGPIPE handler
649 #endif
650 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
651 int ret;
653 if(startup_count==0) {
654 WSASetLastError(WSANOTINITIALISED);
655 return(SOCKET_ERROR);
658 if (handle == NULL ||
659 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
660 WSASetLastError(WSAENOTSOCK);
661 return(SOCKET_ERROR);
664 #ifdef HAVE_MSG_NOSIGNAL
665 do {
666 ret=sendto(fd, msg, len, send_flags | MSG_NOSIGNAL, to, tolen);
668 while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
669 #else
670 old_sigpipe = signal(SIGPIPE, SIG_IGN);
671 do {
672 ret=sendto(fd, msg, len, send_flags, to, tolen);
674 while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
675 signal(SIGPIPE, old_sigpipe);
676 #endif
677 if(ret==-1) {
678 gint errnum = errno;
679 #ifdef DEBUG
680 g_message(G_GNUC_PRETTY_FUNCTION ": send error: %s",
681 strerror(errno));
682 #endif
684 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
685 WSASetLastError (errnum);
687 return(SOCKET_ERROR);
689 return(ret);
692 int _wapi_setsockopt(guint32 fd, int level, int optname,
693 const void *optval, socklen_t optlen)
695 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
696 int ret;
698 if(startup_count==0) {
699 WSASetLastError(WSANOTINITIALISED);
700 return(SOCKET_ERROR);
703 if (handle == NULL ||
704 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
705 WSASetLastError(WSAENOTSOCK);
706 return(SOCKET_ERROR);
709 ret=setsockopt(fd, level, optname, optval, optlen);
710 if(ret==-1) {
711 gint errnum = errno;
712 #ifdef DEBUG
713 g_message(G_GNUC_PRETTY_FUNCTION ": setsockopt error: %s",
714 strerror(errno));
715 #endif
717 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
718 WSASetLastError (errnum);
720 return(SOCKET_ERROR);
723 return(ret);
726 int _wapi_shutdown(guint32 fd, int how)
728 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
729 int ret;
731 if(startup_count==0) {
732 WSASetLastError(WSANOTINITIALISED);
733 return(SOCKET_ERROR);
736 if (handle == NULL ||
737 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
738 WSASetLastError(WSAENOTSOCK);
739 return(SOCKET_ERROR);
742 ret=shutdown(fd, how);
743 if(ret==-1) {
744 gint errnum = errno;
745 #ifdef DEBUG
746 g_message(G_GNUC_PRETTY_FUNCTION ": shutdown error: %s",
747 strerror(errno));
748 #endif
750 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
751 WSASetLastError (errnum);
753 return(SOCKET_ERROR);
756 return(ret);
759 guint32 _wapi_socket(int domain, int type, int protocol, void *unused, guint32 unused2, guint32 unused3)
761 struct _WapiHandlePrivate_socket *socket_private_handle;
762 gpointer handle;
763 gboolean ok;
764 int fd;
765 int thr_ret;
766 guint32 ret = INVALID_SOCKET;
768 fd=socket(domain, type, protocol);
769 if (fd==-1 && domain == AF_INET && type == SOCK_RAW && protocol == 0) {
770 /* Retry with protocol == 4 (see bug #54565) */
771 fd = socket (AF_INET, SOCK_RAW, 4);
774 if (fd == -1) {
775 gint errnum = errno;
776 #ifdef DEBUG
777 g_message(G_GNUC_PRETTY_FUNCTION ": socket error: %s", strerror(errno));
778 #endif
779 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
780 WSASetLastError (errnum);
782 return(INVALID_SOCKET);
785 if (fd >= _wapi_fd_offset_table_size) {
786 #ifdef DEBUG
787 g_message (G_GNUC_PRETTY_FUNCTION ": File descriptor is too big");
788 #endif
790 WSASetLastError (WSASYSCALLFAILURE);
791 close (fd);
793 return(INVALID_SOCKET);
797 mono_once (&socket_ops_once, socket_ops_init);
799 handle=_wapi_handle_new (WAPI_HANDLE_SOCKET);
800 if(handle==_WAPI_HANDLE_INVALID) {
801 g_warning (G_GNUC_PRETTY_FUNCTION
802 ": error creating socket handle");
803 return(INVALID_SOCKET);
806 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
807 handle);
808 thr_ret = _wapi_handle_lock_handle (handle);
809 g_assert (thr_ret == 0);
811 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET, NULL,
812 (gpointer *)&socket_private_handle);
813 if(ok==FALSE) {
814 g_warning (G_GNUC_PRETTY_FUNCTION
815 ": error looking up socket handle %p", handle);
816 goto cleanup;
819 _wapi_handle_fd_offset_store (fd, handle);
820 ret = fd;
822 socket_private_handle->fd_mapped.fd = fd;
823 socket_private_handle->fd_mapped.assigned = TRUE;
825 #ifdef DEBUG
826 g_message(G_GNUC_PRETTY_FUNCTION
827 ": returning socket handle %p with fd %d", handle,
828 socket_private_handle->fd_mapped.fd);
829 #endif
831 cleanup:
832 thr_ret = _wapi_handle_unlock_handle (handle);
833 g_assert (thr_ret == 0);
834 pthread_cleanup_pop (0);
836 return(ret);
839 struct hostent *_wapi_gethostbyname(const char *hostname)
841 struct hostent *he;
843 if(startup_count==0) {
844 WSASetLastError(WSANOTINITIALISED);
845 return(NULL);
848 he=gethostbyname(hostname);
849 if(he==NULL) {
850 #ifdef DEBUG
851 g_message(G_GNUC_PRETTY_FUNCTION ": gethostbyname error: %s",
852 strerror(h_errno));
853 #endif
855 switch(h_errno) {
856 case HOST_NOT_FOUND:
857 WSASetLastError(WSAHOST_NOT_FOUND);
858 break;
859 #if NO_ADDRESS != NO_DATA
860 case NO_ADDRESS:
861 #endif
862 case NO_DATA:
863 WSASetLastError(WSANO_DATA);
864 break;
865 case NO_RECOVERY:
866 WSASetLastError(WSANO_RECOVERY);
867 break;
868 case TRY_AGAIN:
869 WSASetLastError(WSATRY_AGAIN);
870 break;
871 default:
872 g_warning (G_GNUC_PRETTY_FUNCTION ": Need to translate %d into winsock error", h_errno);
873 break;
877 return(he);
881 WSAIoctl (guint32 fd, gint32 command,
882 gchar *input, gint i_len,
883 gchar *output, gint o_len, glong *written,
884 void *unused1, void *unused2)
886 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
887 int ret;
888 gchar *buffer = NULL;
890 if(startup_count==0) {
891 WSASetLastError(WSANOTINITIALISED);
892 return(SOCKET_ERROR);
895 if (handle == NULL ||
896 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
897 WSASetLastError (WSAENOTSOCK);
898 return SOCKET_ERROR;
901 if (i_len > 0)
902 buffer = g_memdup (input, i_len);
904 ret = ioctl (fd, command, buffer);
905 if (ret == -1) {
906 gint errnum = errno;
907 #ifdef DEBUG
908 g_message(G_GNUC_PRETTY_FUNCTION ": WSAIoctl error: %s",
909 strerror(errno));
910 #endif
912 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
913 WSASetLastError (errnum);
914 g_free (buffer);
916 return SOCKET_ERROR;
919 if (buffer == NULL) {
920 *written = 0;
921 } else {
922 /* We just copy the buffer to the output. Some ioctls
923 * don't even output any data, but, well... */
924 i_len = (i_len > o_len) ? o_len : i_len;
925 memcpy (output, buffer, i_len);
926 g_free (buffer);
927 *written = i_len;
930 return 0;
933 int ioctlsocket(guint32 fd, gint32 command, gpointer arg)
935 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
936 int ret;
938 if(startup_count==0) {
939 WSASetLastError(WSANOTINITIALISED);
940 return(SOCKET_ERROR);
943 if (handle == NULL ||
944 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
945 WSASetLastError(WSAENOTSOCK);
946 return(SOCKET_ERROR);
949 if(command!=FIONBIO &&
950 command!=FIONREAD &&
951 command!=SIOCATMARK) {
952 /* Not listed in the MSDN specs, but ioctl(2) returns
953 * this if command is invalid
955 WSASetLastError(WSAEINVAL);
956 return(SOCKET_ERROR);
959 #ifdef O_NONBLOCK
960 /* This works better than ioctl(...FIONBIO...) on Linux (it causes
961 * connect to return EINPROGRESS, but the ioctl doesn't seem to)
963 if(command==FIONBIO) {
964 ret=fcntl(fd, F_GETFL, 0);
965 if(ret!=-1) {
966 if(*(gboolean *)arg) {
967 ret &= ~O_NONBLOCK;
968 } else {
969 ret |= O_NONBLOCK;
971 ret=fcntl(fd, F_SETFL, ret);
973 } else
974 #endif /* O_NONBLOCK */
976 ret=ioctl(fd, command, arg);
978 if(ret==-1) {
979 gint errnum = errno;
980 #ifdef DEBUG
981 g_message(G_GNUC_PRETTY_FUNCTION ": ioctl error: %s",
982 strerror(errno));
983 #endif
985 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
986 WSASetLastError (errnum);
988 return(SOCKET_ERROR);
991 return(0);
994 int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds,
995 fd_set *exceptfds, struct timeval *timeout)
997 int ret;
999 if(startup_count==0) {
1000 WSASetLastError(WSANOTINITIALISED);
1001 return(SOCKET_ERROR);
1004 do {
1005 ret=select(getdtablesize(), readfds, writefds, exceptfds, timeout);
1007 while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
1009 if(ret==-1) {
1010 gint errnum = errno;
1011 #ifdef DEBUG
1012 g_message(G_GNUC_PRETTY_FUNCTION ": select error: %s",
1013 strerror(errno));
1014 #endif
1015 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
1016 WSASetLastError (errnum);
1018 return(SOCKET_ERROR);
1021 return(ret);
1024 void _wapi_FD_CLR(guint32 fd, fd_set *set)
1026 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
1028 if (handle == NULL ||
1029 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1030 WSASetLastError(WSAENOTSOCK);
1031 return;
1034 FD_CLR(fd, set);
1037 int _wapi_FD_ISSET(guint32 fd, fd_set *set)
1039 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
1041 if (handle == NULL ||
1042 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1043 WSASetLastError(WSAENOTSOCK);
1044 return(0);
1047 return(FD_ISSET(fd, set));
1050 void _wapi_FD_SET(guint32 fd, fd_set *set)
1052 gpointer handle = _wapi_handle_fd_offset_to_handle (GUINT_TO_POINTER (fd));
1054 if (handle == NULL ||
1055 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1056 WSASetLastError(WSAENOTSOCK);
1057 return;
1060 FD_SET(fd, set);
1063 #ifdef USE_AIO
1065 typedef struct {
1066 struct aiocb *aio;
1067 gpointer ares;
1068 SocketAsyncCB callback;
1069 } notifier_data_t;
1071 #define SIGPTR(a) a.SIGVAL_PTR
1073 static void
1074 async_notifier (union sigval sig)
1076 notifier_data_t *ndata = SIGPTR (sig);
1077 guint32 error;
1078 guint32 numbytes;
1080 error = aio_return (ndata->aio);
1081 if (error < 0) {
1082 error = _wapi_get_win32_file_error (error);
1083 numbytes = 0;
1084 } else {
1085 numbytes = error;
1086 error = 0;
1089 ndata->callback (error, numbytes, ndata->ares);
1090 g_free (ndata->aio);
1091 g_free (ndata);
1094 static gboolean
1095 do_aio_call (gboolean is_read, gpointer fd_handle, gpointer buffer,
1096 guint32 numbytes, guint32 *out_bytes,
1097 gpointer ares,
1098 SocketAsyncCB callback)
1100 gpointer handle = _wapi_handle_fd_offset_to_handle (fd_handle);
1101 int fd = GPOINTER_TO_UINT (fd_handle);
1102 struct aiocb *aio;
1103 int result;
1104 notifier_data_t *ndata;
1106 if (handle == NULL ||
1107 _wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1108 WSASetLastError (WSAENOTSOCK);
1109 return FALSE;
1112 ndata = g_new0 (notifier_data_t, 1);
1113 aio = g_new0 (struct aiocb, 1);
1114 ndata->ares = ares;
1115 ndata->aio = aio;
1116 ndata->callback = callback;
1118 aio->aio_fildes = fd;
1119 aio->aio_lio_opcode = (is_read) ? LIO_READ : LIO_WRITE;
1120 aio->aio_nbytes = numbytes;
1121 aio->aio_offset = 0;
1122 aio->aio_buf = buffer;
1123 aio->aio_sigevent.sigev_notify = SIGEV_THREAD;
1124 aio->aio_sigevent.sigev_notify_function = async_notifier;
1125 SIGPTR (aio->aio_sigevent.sigev_value) = ndata;
1127 if (is_read) {
1128 result = aio_read (aio);
1129 } else {
1130 result = aio_write (aio);
1133 if (result == -1) {
1134 WSASetLastError (errno_to_WSA (errno, "do_aio_call"));
1135 return FALSE;
1138 result = aio_error (aio);
1139 if (result == 0) {
1140 numbytes = aio_return (aio);
1141 } else {
1142 WSASetLastError (errno_to_WSA (result, "do_aio_call"));
1143 return FALSE;
1146 if (out_bytes)
1147 *out_bytes = numbytes;
1149 return TRUE;
1152 gboolean _wapi_socket_async_read (gpointer handle, gpointer buffer,
1153 guint32 numbytes,
1154 guint32 *bytesread, gpointer ares,
1155 SocketAsyncCB callback)
1157 return do_aio_call (TRUE, handle, buffer, numbytes, bytesread, ares, callback);
1160 gboolean _wapi_socket_async_write (gpointer handle, gpointer buffer,
1161 guint32 numbytes,
1162 guint32 *byteswritten, gpointer ares,
1163 SocketAsyncCB callback)
1165 return do_aio_call (FALSE, handle, buffer, numbytes, byteswritten, ares, callback);
1168 #endif /* USE_AIO */