/*
* socket-io.c: Socket IO internal calls
*
- * Author:
+ * Authors:
* Dick Porter (dick@ximian.com)
+ * Gonzalo Paniagua Javier (gonzalo@ximian.com)
*
* (C) 2001 Ximian, Inc.
+ * Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
*/
#include <config.h>
#include <unistd.h>
#include <errno.h>
-#ifndef PLATFORM_WIN32
-#ifdef HAVE_AIO_H
-#include <aio.h>
-#define USE_AIO 1
-#elif defined(HAVE_SYS_AIO_H)
-#include <sys/aio.h>
-#define USE_AIO 1
-#else
-#undef USE_AIO
-#endif
-#endif
-
#include <mono/metadata/object.h>
#include <mono/io-layer/io-layer.h>
#include <mono/metadata/socket-io.h>
#include <mono/metadata/exception.h>
+#include <mono/metadata/assembly.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/threads.h>
+#include <mono/metadata/threads-types.h>
+#include <mono/utils/mono-poll.h>
/* FIXME change this code to not mess so much with the internals */
#include <mono/metadata/class-internals.h>
+#include <mono/metadata/threadpool-internals.h>
#include <sys/time.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
*system_name = IPV6_LEAVE_GROUP;
break;
case SocketOptionName_PacketInformation:
+#ifdef HAVE_IPV6_PKTINFO
*system_name = IPV6_PKTINFO;
+#endif
break;
case SocketOptionName_HeaderIncluded:
case SocketOptionName_IPOptions:
#define STASH_SYS_ASS(this) \
if(system_assembly == NULL) { \
system_assembly=mono_image_loaded ("System"); \
+ if (!system_assembly) { \
+ MonoAssembly *sa = mono_assembly_open ("System.dll", NULL); \
+ if (!sa) g_assert_not_reached (); \
+ else {system_assembly = mono_assembly_get_image (sa);} \
+ } \
}
static MonoImage *system_assembly=NULL;
#endif
*error = 0;
-
+
+ /* Clear any pending work item from this socket if the underlying
+ * polling system does not notify when the socket is closed */
+ mono_thread_pool_remove_socket (GPOINTER_TO_INT (sock));
closesocket(sock);
}
MONO_ARCH_SAVE_REGS;
*error = 0;
+
+ /*
+ * block == TRUE/FALSE means we will block/not block.
+ * But the ioctlsocket call takes TRUE/FALSE for non-block/block
+ */
+ block = !block;
ret = ioctlsocket (sock, FIONBIO, (gulong *) &block);
if(ret==SOCKET_ERROR) {
struct timeval tv;
struct timeval *tvptr;
div_t divvy;
+ time_t start;
MONO_ARCH_SAVE_REGS;
+ start = time (NULL);
do {
- /* FIXME: in case of extra iteration (WSAEINTR), substract time
- * from the initial timeout */
*error = 0;
FD_ZERO (&fds);
_wapi_FD_SET (sock, &fds);
} else {
g_assert_not_reached ();
}
+
+ if (timeout > 0 && ret < 0) {
+ int err = errno;
+ int sec = time (NULL) - start;
+
+ timeout -= sec * 1000;
+ if (timeout < 0)
+ timeout = 0;
+ errno = err;
+ }
+
} while ((ret == SOCKET_ERROR) && (*error == WSAGetLastError ()) == WSAEINTR);
return (ret != SOCKET_ERROR && _wapi_FD_ISSET (sock, &fds));
return(0);
}
- *sockaddr=create_object_from_sockaddr(sa, sa_size, error);
+ /* If we didn't get a socket size, then we're probably a
+ * connected connection-oriented socket and the stack hasn't
+ * returned the remote address. All we can do is return null.
+ */
+ if ( sa_size != 0 )
+ *sockaddr=create_object_from_sockaddr(sa, sa_size, error);
+ else
+ *sockaddr=NULL;
+
g_free(sa);
return(ret);
return(sock);
}
-void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **read_socks, MonoArray **write_socks, MonoArray **err_socks, gint32 timeout, gint32 *error)
+#define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
+void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gint32 timeout, gint32 *error)
{
- fd_set readfds, writefds, errfds;
- fd_set *readptr = NULL, *writeptr = NULL, *errptr = NULL;
- struct timeval tv;
- div_t divvy;
+ MonoThread *thread = NULL;
+ MonoObject *obj;
+ mono_pollfd *pfds;
+ int nfds, idx;
int ret;
- int readarrsize = 0, writearrsize = 0, errarrsize = 0;
- MonoDomain *domain=mono_domain_get();
+ int i, count;
+ int mode;
MonoClass *sock_arr_class;
MonoArray *socks;
- int count;
- int i;
- SOCKET handle;
+ time_t start;
MONO_ARCH_SAVE_REGS;
- if (*read_socks)
- readarrsize=mono_array_length(*read_socks);
-
- *error = 0;
-
- if(readarrsize>FD_SETSIZE) {
- *error = WSAEFAULT;
- return;
- }
-
- if (readarrsize) {
- readptr = &readfds;
- FD_ZERO(&readfds);
- for(i=0; i<readarrsize; i++) {
- handle = Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i));
- _wapi_FD_SET(handle, &readfds);
+ /* *sockets -> READ, null, WRITE, null, ERROR, null */
+ count = mono_array_length (*sockets);
+ nfds = count - 3; /* NULL separators */
+ pfds = g_new0 (mono_pollfd, nfds);
+ mode = idx = 0;
+ for (i = 0; i < count; i++) {
+ obj = mono_array_get (*sockets, MonoObject *, i);
+ if (obj == NULL) {
+ mode++;
+ continue;
}
- }
-
- if (*write_socks)
- writearrsize=mono_array_length(*write_socks);
- if(writearrsize>FD_SETSIZE) {
- *error = WSAEFAULT;
- return;
+ pfds [idx].fd = GPOINTER_TO_INT (Socket_to_SOCKET (obj));
+ pfds [idx].events = (mode == 0) ? MONO_POLLIN : (mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
+ idx++;
}
-
- if (writearrsize) {
- writeptr = &writefds;
- FD_ZERO(&writefds);
- for(i=0; i<writearrsize; i++) {
- handle = Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i));
- _wapi_FD_SET(handle, &writefds);
- }
- }
-
- if (*err_socks)
- errarrsize=mono_array_length(*err_socks);
-
- if(errarrsize>FD_SETSIZE) {
- *error = WSAEFAULT;
- return;
- }
-
- if (errarrsize) {
- errptr = &errfds;
- FD_ZERO(&errfds);
- for(i=0; i<errarrsize; i++) {
- handle = Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i));
- _wapi_FD_SET(handle, &errfds);
- }
- }
-
- /* Negative timeout meaning block until ready is only
- * specified in Poll, not Select
- */
- divvy = div (timeout, 1000000);
-
+ timeout = (timeout >= 0) ? (timeout / 1000) : -1;
+ start = time (NULL);
do {
- if(timeout>=0) {
- tv.tv_sec=divvy.quot;
- tv.tv_usec=divvy.rem;
+ *error = 0;
+ ret = mono_poll (pfds, nfds, timeout);
+ if (timeout > 0 && ret < 0) {
+ int err = errno;
+ int sec = time (NULL) - start;
+
+ timeout -= sec * 1000;
+ if (timeout < 0)
+ timeout = 0;
+ errno = err;
+ }
- ret = _wapi_select (0, readptr, writeptr, errptr, &tv);
- } else {
- ret = _wapi_select (0, readptr, writeptr, errptr, NULL);
+ if (ret == -1 && errno == EINTR) {
+ int leave = 0;
+ if (thread == NULL)
+ thread = mono_thread_current ();
+
+ mono_monitor_enter (thread->synch_lock);
+ leave = ((thread->state & ThreadState_AbortRequested) != 0 ||
+ (thread->state & ThreadState_StopRequested) != 0);
+ mono_monitor_exit (thread->synch_lock);
+ if (leave != 0) {
+ g_free (pfds);
+ *sockets = NULL;
+ return;
+ } else {
+ /* Suspend requested? */
+ mono_thread_interruption_checkpoint ();
+ }
+ errno = EINTR;
}
- } while ((ret==SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR));
+ } while (ret == -1 && errno == EINTR);
- if(ret==SOCKET_ERROR) {
+ if (ret == -1) {
+#ifdef PLATFORM_WIN32
*error = WSAGetLastError ();
+#else
+ *error = errno_to_WSA (errno, __func__);
+#endif
+ g_free (pfds);
return;
}
- if (readarrsize) {
- sock_arr_class=((MonoObject *)*read_socks)->vtable->klass;
-
- count=0;
- for(i=0; i<readarrsize; i++) {
- if(_wapi_FD_ISSET(Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i)), &readfds)) {
- count++;
- }
- }
- socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
- count=0;
- for(i=0; i<readarrsize; i++) {
- MonoObject *sock=mono_array_get(*read_socks, MonoObject *, i);
-
- if(_wapi_FD_ISSET(Socket_to_SOCKET(sock), &readfds)) {
- mono_array_set(socks, MonoObject *, count, sock);
- count++;
- }
- }
- *read_socks=socks;
- } else {
- *read_socks = NULL;
+ if (ret == 0) {
+ g_free (pfds);
+ *sockets = NULL;
+ return;
}
- if (writearrsize) {
- sock_arr_class=((MonoObject *)*write_socks)->vtable->klass;
- count=0;
- for(i=0; i<writearrsize; i++) {
- if(_wapi_FD_ISSET(Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i)), &writefds)) {
- count++;
- }
- }
- socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
- count=0;
- for(i=0; i<writearrsize; i++) {
- MonoObject *sock=mono_array_get(*write_socks, MonoObject *, i);
-
- if(_wapi_FD_ISSET(Socket_to_SOCKET(sock), &writefds)) {
- mono_array_set(socks, MonoObject *, count, sock);
- count++;
- }
- }
- *write_socks=socks;
- } else {
- *write_socks = NULL;
- }
+ sock_arr_class= ((MonoObject *)*sockets)->vtable->klass;
+ ret += 3; /* space for the NULL delimiters */
+ socks = mono_array_new_full (mono_domain_get (), sock_arr_class, &ret, NULL);
+ ret -= 3;
+ mode = idx = 0;
+ for (i = 0; i < count && ret > 0; i++) {
+ mono_pollfd *pfd;
- if (errarrsize) {
- sock_arr_class=((MonoObject *)*err_socks)->vtable->klass;
- count=0;
- for(i=0; i<errarrsize; i++) {
- if(_wapi_FD_ISSET(Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i)), &errfds)) {
- count++;
- }
+ obj = mono_array_get (*sockets, MonoObject *, i);
+ if (obj == NULL) {
+ mode++;
+ idx++;
+ continue;
}
- socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
- count=0;
- for(i=0; i<errarrsize; i++) {
- MonoObject *sock=mono_array_get(*err_socks, MonoObject *, i);
-
- if(_wapi_FD_ISSET(Socket_to_SOCKET(sock), &errfds)) {
- mono_array_set(socks, MonoObject *, count, sock);
- count++;
- }
+
+ pfd = &pfds [i - mode];
+ if (pfd->revents == 0)
+ continue;
+
+ ret--;
+ if (mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0) {
+ mono_array_set (socks, MonoObject *, idx++, obj);
+ } else if (mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0) {
+ mono_array_set (socks, MonoObject *, idx++, obj);
+ } else if ((pfd->revents & POLL_ERRORS) != 0) {
+ mono_array_set (socks, MonoObject *, idx++, obj);
}
- *err_socks=socks;
}
+
+ *sockets = socks;
+ g_free (pfds);
}
static MonoObject* int_to_object (MonoDomain *domain, int val)
int valsize=sizeof(val);
struct linger linger;
int lingersize=sizeof(linger);
- struct timeval tv;
- int tvsize=sizeof(tv);
+ int time_ms = 0;
+ int time_ms_size = sizeof (time_ms);
#ifdef SO_PEERCRED
struct ucred cred;
int credsize = sizeof(cred);
case SocketOptionName_SendTimeout:
case SocketOptionName_ReceiveTimeout:
- ret = _wapi_getsockopt (sock, system_level, system_name, &tv,
- &tvsize);
+ ret = _wapi_getsockopt (sock, system_level, system_name, (char *) &time_ms, &time_ms_size);
break;
#ifdef SO_PEERCRED
case SocketOptionName_SendTimeout:
case SocketOptionName_ReceiveTimeout:
- obj = int_to_object (domain, (tv.tv_sec * 1000) + (tv.tv_usec / 1000));
+ obj = int_to_object (domain, time_ms);
break;
#ifdef SO_PEERCRED
/* build a Mono.Posix.PeerCred+PeerCredData if
* possible
*/
- MonoImage *mono_posix_image = mono_image_loaded ("Mono.Posix");
+ static MonoImage *mono_posix_image = NULL;
MonoPeerCredData *cred_data;
if (mono_posix_image == NULL) {
- *error = WSAENOPROTOOPT;
- return;
+ mono_posix_image=mono_image_loaded ("Mono.Posix");
+ if (!mono_posix_image) {
+ MonoAssembly *sa = mono_assembly_open ("Mono.Posix.dll", NULL);
+ if (!sa) {
+ *error = WSAENOPROTOOPT;
+ return;
+ } else {
+ mono_posix_image = mono_assembly_get_image (sa);
+ }
+ }
}
obj_class = mono_class_from_name(mono_posix_image,
struct in_addr inaddr;
MonoClassField *field;
- field=mono_class_get_field_from_name(ipaddr->vtable->klass, "address");
+ field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Address");
/* No idea why .net uses a 64bit type to hold a 32bit value...
*
MonoArray *data;
int i;
- field=mono_class_get_field_from_name(ipaddr->vtable->klass, "_numbers");
+ field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Numbers");
data=*(MonoArray **)(((char *)ipaddr) + field->offset);
/* Solaris has only the 8 bit version. */
return;
}
} else {
- switch(name) {
- case SocketOptionName_SendTimeout:
- case SocketOptionName_ReceiveTimeout: {
- struct timeval tv;
- tv.tv_sec = int_val / 1000;
- tv.tv_usec = (int_val % 1000) * 1000;
- ret = _wapi_setsockopt (sock, system_level, system_name, &tv, sizeof (tv));
- break;
- }
- default:
- ret = _wapi_setsockopt (sock, system_level, system_name, &int_val,
- sizeof(int_val));
- }
+ /* ReceiveTimeout/SendTimeout get here */
+ ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
}
if(ret==SOCKET_ERROR) {
return (gint) output_bytes;
}
+#ifdef HAVE_SIOCGIFCONF
+static gboolean
+is_loopback (int family, void *ad)
+{
+ char *ptr = (char *) ad;
+
+ if (family == AF_INET) {
+ return (ptr [0] == 127);
+ }
+#ifdef AF_INET6
+ else {
+ return (IN6_IS_ADDR_LOOPBACK ((struct in6_addr *) ptr));
+ }
+#endif
+ return FALSE;
+}
+
+static void *
+get_local_ips (int family, int *nips)
+{
+ int addr_size, offset, fd, i, count;
+ int max_ifaces = 50; /* 50 interfaces should be enough... */
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ struct ifreq iflags;
+ char *result, *tmp_ptr;
+ gboolean ignore_loopback = FALSE;
+
+ *nips = 0;
+ if (family == AF_INET) {
+ addr_size = sizeof (struct in_addr);
+ offset = G_STRUCT_OFFSET (struct sockaddr_in, sin_addr);
+#ifdef AF_INET6
+ } else if (family == AF_INET6) {
+ addr_size = sizeof (struct in6_addr);
+ offset = G_STRUCT_OFFSET (struct sockaddr_in6, sin6_addr);
+#endif
+ } else {
+ return NULL;
+ }
+
+ fd = socket (family, SOCK_STREAM, 0);
+
+ ifc.ifc_len = max_ifaces * sizeof (struct ifreq);
+ ifc.ifc_buf = g_malloc (ifc.ifc_len);
+ if (ioctl (fd, SIOCGIFCONF, &ifc) < 0) {
+ close (fd);
+ g_free (ifc.ifc_buf);
+ return NULL;
+ }
+
+ count = ifc.ifc_len / sizeof (struct ifreq);
+ *nips = count;
+ if (count == 0) {
+ g_free (ifc.ifc_buf);
+ close (fd);
+ return NULL;
+ }
+
+ for (i = 0, ifr = ifc.ifc_req; i < *nips; i++, ifr++) {
+ strcpy (iflags.ifr_name, ifr->ifr_name);
+ if (ioctl (fd, SIOCGIFFLAGS, &iflags) < 0) {
+ continue;
+ }
+
+ if ((iflags.ifr_flags & IFF_UP) == 0) {
+ ifr->ifr_name [0] = '\0';
+ continue;
+ }
+
+ if ((iflags.ifr_flags & IFF_LOOPBACK) == 0) {
+ ignore_loopback = TRUE;
+ }
+ }
+
+ close (fd);
+ result = g_malloc (addr_size * count);
+ tmp_ptr = result;
+ for (i = 0, ifr = ifc.ifc_req; i < count; i++, ifr++) {
+ if (ifr->ifr_name [0] == '\0') {
+ (*nips)--;
+ continue;
+ }
+
+ if (ignore_loopback && is_loopback (family, ((char *) &ifr->ifr_addr) + offset)) {
+ (*nips)--;
+ continue;
+ }
+
+ memcpy (tmp_ptr, ((char *) &ifr->ifr_addr) + offset, addr_size);
+ tmp_ptr += addr_size;
+ }
+
+ g_free (ifc.ifc_buf);
+ return result;
+}
+#else
+static void *
+get_local_ips (int family, int *nips)
+{
+ *nips = 0;
+ return NULL;
+}
+
+#endif /* HAVE_SIOCGIFCONF */
+
#ifndef AF_INET6
static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
MonoArray **h_aliases,
- MonoArray **h_addr_list)
+ MonoArray **h_addr_list,
+ gboolean add_local_ips)
{
MonoDomain *domain = mono_domain_get ();
int i;
+ struct in_addr *local_in = NULL;
+ int nlocal_in = 0;
if(he->h_length!=4 || he->h_addrtype!=AF_INET) {
return(FALSE);
i++;
}
- i=0;
- while(he->h_addr_list[i]!=NULL) {
- i++;
+ if (add_local_ips) {
+ local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
+ if (nlocal_in) {
+ *h_addr_list = mono_array_new(domain, mono_get_string_class (), nlocal_in);
+ for (i = 0; i < nlocal_in; i++) {
+ MonoString *addr_string;
+ char addr [16], *ptr;
+
+ ptr = (char *) &local_in [i];
+ g_snprintf(addr, 16, "%u.%u.%u.%u",
+ (unsigned char) ptr [0],
+ (unsigned char) ptr [1],
+ (unsigned char) ptr [2],
+ (unsigned char) ptr [3]);
+
+ addr_string = mono_string_new (domain, addr);
+ mono_array_set (*h_addr_list, MonoString *, i, addr_string);
+ i++;
+ }
+
+ g_free (local_in);
+ }
}
- *h_addr_list=mono_array_new(domain, mono_get_string_class (), i);
- i=0;
- while(he->h_addr_list[i]!=NULL) {
- MonoString *addr_string;
- char addr[16];
-
- g_snprintf(addr, 16, "%u.%u.%u.%u",
- (unsigned char)he->h_addr_list[i][0],
- (unsigned char)he->h_addr_list[i][1],
- (unsigned char)he->h_addr_list[i][2],
- (unsigned char)he->h_addr_list[i][3]);
-
- addr_string=mono_string_new(domain, addr);
- mono_array_set(*h_addr_list, MonoString *, i, addr_string);
- i++;
+ if (nlocal_in == 0) {
+ i = 0;
+ while (he->h_addr_list[i]!=NULL) {
+ i++;
+ }
+
+ *h_addr_list=mono_array_new(domain, mono_get_string_class (), i);
+ i=0;
+ while(he->h_addr_list[i]!=NULL) {
+ MonoString *addr_string;
+ char addr[16];
+
+ g_snprintf(addr, 16, "%u.%u.%u.%u",
+ (unsigned char)he->h_addr_list[i][0],
+ (unsigned char)he->h_addr_list[i][1],
+ (unsigned char)he->h_addr_list[i][2],
+ (unsigned char)he->h_addr_list[i][3]);
+
+ addr_string=mono_string_new(domain, addr);
+ mono_array_set(*h_addr_list, MonoString *, i, addr_string);
+ i++;
+ }
}
return(TRUE);
#endif
#if defined(AF_INET6) && defined(HAVE_GETHOSTBYNAME2_R)
-static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
+static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2, MonoString **h_name,
+ MonoArray **h_aliases, MonoArray **h_addr_list, gboolean add_local_ips)
{
MonoDomain *domain = mono_domain_get ();
int i, host_count, host_index, family_hint;
+ struct in_addr *local_in = NULL;
+ int nlocal_in = 0;
+ struct in6_addr *local_in6 = NULL;
+ int nlocal_in6 = 0;
+ gboolean from_local = FALSE;
family_hint = get_family_hint ();
/*
* Fills the array
*/
- *h_addr_list=mono_array_new (domain, mono_get_string_class (),
- host_count);
-
host_index = 0;
+ if (add_local_ips) {
+ if (family_hint == PF_UNSPEC || family_hint == PF_INET)
+ local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
+
+ if (family_hint == PF_UNSPEC || family_hint == PF_INET6)
+ local_in6 = (struct in6_addr *) get_local_ips (AF_INET6, &nlocal_in6);
+
+ if (nlocal_in || nlocal_in6) {
+ from_local = TRUE;
+ *h_addr_list = mono_array_new (domain, mono_get_string_class (),
+ nlocal_in + nlocal_in6);
+
+ if (nlocal_in6) {
+ int n;
+ for (n = 0; n < nlocal_in6; n++) {
+ MonoString *addr_string;
+ char addr[46]; /* INET6_ADDRSTRLEN == 46 */
+
+ inet_ntop (AF_INET6, &local_in6 [n], addr,
+ sizeof(addr));
+
+ addr_string = mono_string_new (domain, addr);
+ mono_array_set (*h_addr_list, MonoString *, host_index,
+ addr_string);
+ host_index++;
+ }
+ }
+
+ if (nlocal_in) {
+ int n;
+ for (n = 0; n < nlocal_in; n++) {
+ MonoString *addr_string;
+ char addr[16]; /* INET_ADDRSTRLEN == 16 */
+
+ inet_ntop (AF_INET, &local_in [n], addr,
+ sizeof(addr));
+
+ addr_string = mono_string_new (domain, addr);
+ mono_array_set (*h_addr_list, MonoString *, host_index,
+ addr_string);
+ host_index++;
+ }
+ }
+ g_free (local_in);
+ g_free (local_in6);
+ return TRUE;
+ }
+
+ g_free (local_in);
+ g_free (local_in6);
+ }
+
+ *h_addr_list=mono_array_new (domain, mono_get_string_class (), host_count);
if (he2 != NULL && (family_hint == PF_UNSPEC ||
family_hint == PF_INET6)) {
i = 0;
while(he2->h_addr_list[i] != NULL) {
MonoString *addr_string;
- char addr[40];
+ char addr[46]; /* INET6_ADDRSTRLEN == 46 */
inet_ntop (AF_INET6, he2->h_addr_list[i], addr,
sizeof(addr));
i=0;
while(he1->h_addr_list[i] != NULL) {
MonoString *addr_string;
- char addr[17];
+ char addr[16]; /* INET_ADDRSTRLEN == 16 */
inet_ntop (AF_INET, he1->h_addr_list[i], addr,
sizeof(addr));
static gboolean
addrinfo_to_IPHostEntry(struct addrinfo *info, MonoString **h_name,
MonoArray **h_aliases,
- MonoArray **h_addr_list)
+ MonoArray **h_addr_list,
+ gboolean add_local_ips)
{
gint32 count, i;
struct addrinfo *ai = NULL;
+ struct in_addr *local_in = NULL;
+ int nlocal_in = 0;
+ struct in6_addr *local_in6 = NULL;
+ int nlocal_in6 = 0;
+ int addr_index;
MonoDomain *domain = mono_domain_get ();
+ addr_index = 0;
+ *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
+ if (add_local_ips) {
+ local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
+ local_in6 = (struct in6_addr *) get_local_ips (AF_INET6, &nlocal_in);
+ if (nlocal_in || nlocal_in6) {
+ *h_addr_list=mono_array_new(domain, mono_get_string_class (), nlocal_in + nlocal_in6);
+ if (nlocal_in) {
+ MonoString *addr_string;
+ char addr [16];
+ int i;
+
+ for (i = 0; i < nlocal_in; i++) {
+ inet_ntop (AF_INET, &local_in [i], addr, sizeof (addr));
+ addr_string = mono_string_new (domain, addr);
+ mono_array_set (*h_addr_list, MonoString *, addr_index, addr_string);
+ addr_index++;
+ }
+ }
+
+ if (nlocal_in6) {
+ MonoString *addr_string;
+ char addr [46];
+ int i;
+
+ for (i = 0; i < nlocal_in6; i++) {
+ inet_ntop (AF_INET6, &local_in6 [i], addr, sizeof (addr));
+ addr_string = mono_string_new (domain, addr);
+ mono_array_set (*h_addr_list, MonoString *, addr_index, addr_string);
+ addr_index++;
+ }
+ }
+
+ g_free (local_in);
+ g_free (local_in6);
+ if (info) {
+ freeaddrinfo (info);
+ }
+ return TRUE;
+ }
+
+ g_free (local_in);
+ g_free (local_in6);
+ }
+
for (count=0, ai=info; ai!=NULL; ai=ai->ai_next) {
- if((ai->ai_family != PF_INET) && (ai->ai_family != PF_INET6)) {
+ if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
continue;
- }
count++;
}
- *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
*h_addr_list=mono_array_new(domain, mono_get_string_class (), count);
for (ai=info, i=0; ai!=NULL; ai=ai->ai_next) {
MonoString *addr_string;
const char *ret;
- char *buffer;
- gint32 buffer_size = 0;
+ char buffer [46]; /* Max. size for IPv6 */
if((ai->ai_family != PF_INET) && (ai->ai_family != PF_INET6)) {
continue;
}
- buffer_size = 256;
- do {
- buffer = g_malloc0(buffer_size);
-
- if(ai->ai_family == PF_INET) {
- ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in*)ai->ai_addr)->sin_addr), buffer, buffer_size);
- } else {
- ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr), buffer, buffer_size);
- }
-
- if(ret == 0) {
- g_free(buffer);
- buffer_size += 256;
- }
- } while(ret == 0 && errno == ENOSPC);
+ if(ai->ai_family == PF_INET) {
+ ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in*)ai->ai_addr)->sin_addr), buffer, 16);
+ } else {
+ ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr), buffer, 46);
+ }
if(ret) {
addr_string=mono_string_new(domain, buffer);
- g_free(buffer);
} else {
addr_string=mono_string_new(domain, "");
}
- mono_array_set(*h_addr_list, MonoString *, i, addr_string);
+ mono_array_set(*h_addr_list, MonoString *, addr_index, addr_string);
if(!i && ai->ai_canonname != NULL) {
*h_name=mono_string_new(domain, ai->ai_canonname);
}
- i++;
+ addr_index++;
}
if(info) {
#ifdef AF_INET6
MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
{
+ gboolean add_local_ips = FALSE;
+#ifdef HAVE_SIOCGIFCONF
+ guchar this_hostname [256];
+#endif
#if !defined(HAVE_GETHOSTBYNAME2_R)
struct addrinfo *info = NULL, hints;
char *hostname;
MONO_ARCH_SAVE_REGS;
hostname=mono_string_to_utf8 (host);
-
+#ifdef HAVE_SIOCGIFCONF
+ if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
+ if (!strcmp (hostname, this_hostname))
+ add_local_ips = TRUE;
+ }
+#endif
+
memset(&hints, 0, sizeof(hints));
hints.ai_family = get_family_hint ();
hints.ai_socktype = SOCK_STREAM;
g_free(hostname);
- return(addrinfo_to_IPHostEntry(info, h_name, h_aliases, h_addr_list));
+ return(addrinfo_to_IPHostEntry(info, h_name, h_aliases, h_addr_list, add_local_ips));
#else
struct hostent he1,*hp1, he2, *hp2;
int buffer_size1, buffer_size2;
hostname=mono_string_to_utf8 (host);
+#ifdef HAVE_SIOCGIFCONF
+ if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
+ if (!strcmp (hostname, this_hostname))
+ add_local_ips = TRUE;
+ }
+#endif
+
buffer_size1 = 512;
buffer_size2 = 512;
buffer1 = g_malloc0(buffer_size1);
hp2 = NULL;
return_value = hostent_to_IPHostEntry2(hp1, hp2, h_name, h_aliases,
- h_addr_list);
+ h_addr_list, add_local_ips);
g_free(buffer1);
g_free(buffer2);
{
struct hostent *he;
char *hostname;
+ gboolean add_local_ips = FALSE;
+#ifdef HAVE_SIOCGIFCONF
+ guchar this_hostname [256];
+#endif
MONO_ARCH_SAVE_REGS;
hostname=mono_string_to_utf8(host);
+#ifdef HAVE_SIOCGIFCONF
+ if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
+ if (!strcmp (hostname, this_hostname))
+ add_local_ips = TRUE;
+ }
+#endif
he = _wapi_gethostbyname (hostname);
g_free(hostname);
return(FALSE);
}
- return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
+ return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list, add_local_ips));
}
#endif /* AF_INET6 */
return(FALSE);
}
- return(addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list));
+ return(addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, FALSE));
#else
if (inet_pton (AF_INET, address, &inaddr) <= 0) {
g_free (address);
return(FALSE);
}
- return(hostent_to_IPHostEntry (he, h_name, h_aliases, h_addr_list));
+ return(hostent_to_IPHostEntry (he, h_name, h_aliases, h_addr_list, FALSE));
#endif
}
return(TRUE);
}
-
-/* Async interface */
-#ifndef USE_AIO
-void
-ves_icall_System_Net_Sockets_Socket_AsyncReceive (MonoSocketAsyncResult *ares, gint *error)
-{
- MONO_ARCH_SAVE_REGS;
-
- *error = ERROR_NOT_SUPPORTED;
-}
-
-void
-ves_icall_System_Net_Sockets_Socket_AsyncSend (MonoSocketAsyncResult *ares, gint *error)
-{
- MONO_ARCH_SAVE_REGS;
-
- *error = ERROR_NOT_SUPPORTED;
-}
-#else
-static void
-wsa_overlapped_callback (guint32 error, guint32 numbytes, gpointer result)
-{
- MonoSocketAsyncResult *ares = (MonoSocketAsyncResult *) result;
- MonoThread *thread;
-
- ares->completed = TRUE;
- ares->error = error;
- ares->total = numbytes;
-
- if (ares->callback != NULL) {
- gpointer p [1];
-
- *p = ares;
- thread = mono_thread_attach (mono_object_domain (ares));
- mono_runtime_invoke (ares->callback->method_info->method, NULL, p, NULL);
-
- mono_thread_detach (thread);
- }
-
- if (ares->wait_handle != NULL)
- SetEvent (ares->wait_handle->handle);
-}
-
-void
-ves_icall_System_Net_Sockets_Socket_AsyncReceive (MonoSocketAsyncResult *ares, gint *error)
-{
- gint32 bytesread;
-
- MONO_ARCH_SAVE_REGS;
-
- if (_wapi_socket_async_read (ares->handle,
- mono_array_addr (ares->buffer, gchar, ares->offset),
- ares->size,
- &bytesread,
- ares,
- wsa_overlapped_callback) == FALSE) {
- *error = WSAGetLastError ();
- } else {
- *error = 0;
- ares->completed_synch = TRUE;
- wsa_overlapped_callback (0, bytesread, ares);
- }
-}
-
-void
-ves_icall_System_Net_Sockets_Socket_AsyncSend (MonoSocketAsyncResult *ares, gint *error)
-{
- gint32 byteswritten;
-
- MONO_ARCH_SAVE_REGS;
-
- if (_wapi_socket_async_write (ares->handle,
- mono_array_addr (ares->buffer, gchar, ares->offset),
- ares->size,
- &byteswritten,
- ares,
- wsa_overlapped_callback) == FALSE) {
- *error = WSAGetLastError ();
- } else {
- *error = 0;
- ares->completed_synch = TRUE;
- wsa_overlapped_callback (0, byteswritten, ares);
- }
-}
-#endif /* USE_AIO */
-
void mono_network_init(void)
{
WSADATA wsadata;