* list :
[mono.git] / mono / metadata / socket-io.c
index 4b7200d401fd36e50661d2d21f684ddf6b32744c..aba200d31c5e5c8fa1c37197dd484ce5f14704bc 100644 (file)
@@ -8,7 +8,11 @@
  */
 
 #include <config.h>
+
 #include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
 
 #include <mono/metadata/object.h>
 #include <mono/io-layer/io-layer.h>
 #include <mono/metadata/exception.h>
 #include <mono/metadata/appdomain.h>
 
+#include <sys/time.h> 
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>     /* defines FIONBIO and FIONREAD */
+#endif
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>    /* defines SIOCATMARK */
+#endif
+
+
 #undef DEBUG
 
 static gint32 convert_family(MonoAddressFamily mono_family)
@@ -201,6 +218,7 @@ static gint32 convert_proto(MonoProtocolType mono_proto)
                break;
                
        default:
+               break;
        }
 
        return(proto);
@@ -211,65 +229,67 @@ static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level,
                                             int *system_level,
                                             int *system_name)
 {
-       switch(mono_level) {
+       switch (mono_level) {
        case SocketOptionLevel_Socket:
-               *system_level=SOL_SOCKET;
-
+               *system_level = SOL_SOCKET;
+               
                switch(mono_name) {
                case SocketOptionName_DontLinger:
                        /* This is SO_LINGER, because the setsockopt
                         * internal call maps DontLinger to SO_LINGER
                         * with l_onoff=0
                         */
-                       *system_name=SO_LINGER;
+                       *system_name = SO_LINGER;
                        break;
                case SocketOptionName_Debug:
-                       *system_name=SO_DEBUG;
+                       *system_name = SO_DEBUG;
                        break;
+#ifdef SO_ACCEPTCONN
                case SocketOptionName_AcceptConnection:
-                       *system_name=SO_ACCEPTCONN;
+                       *system_name = SO_ACCEPTCONN;
                        break;
+#endif
                case SocketOptionName_ReuseAddress:
-                       *system_name=SO_REUSEADDR;
+                       *system_name = SO_REUSEADDR;
                        break;
                case SocketOptionName_KeepAlive:
-                       *system_name=SO_KEEPALIVE;
+                       *system_name = SO_KEEPALIVE;
                        break;
                case SocketOptionName_DontRoute:
-                       *system_name=SO_DONTROUTE;
+                       *system_name = SO_DONTROUTE;
                        break;
                case SocketOptionName_Broadcast:
-                       *system_name=SO_BROADCAST;
+                       *system_name = SO_BROADCAST;
                        break;
                case SocketOptionName_Linger:
-                       *system_name=SO_LINGER;
+                       *system_name = SO_LINGER;
                        break;
                case SocketOptionName_OutOfBandInline:
-                       *system_name=SO_OOBINLINE;
+                       *system_name = SO_OOBINLINE;
                        break;
                case SocketOptionName_SendBuffer:
-                       *system_name=SO_SNDBUF;
+                       *system_name = SO_SNDBUF;
                        break;
                case SocketOptionName_ReceiveBuffer:
-                       *system_name=SO_RCVBUF;
+                       *system_name = SO_RCVBUF;
                        break;
                case SocketOptionName_SendLowWater:
-                       *system_name=SO_SNDLOWAT;
+                       *system_name = SO_SNDLOWAT;
                        break;
                case SocketOptionName_ReceiveLowWater:
-                       *system_name=SO_RCVLOWAT;
+                       *system_name = SO_RCVLOWAT;
                        break;
                case SocketOptionName_SendTimeout:
-                       *system_name=SO_SNDTIMEO;
+                       *system_name = SO_SNDTIMEO;
                        break;
                case SocketOptionName_ReceiveTimeout:
-                       *system_name=SO_RCVTIMEO;
+                       *system_name = SO_RCVTIMEO;
                        break;
                case SocketOptionName_Error:
-                       *system_name=SO_ERROR;
+                       *system_name = SO_ERROR;
                        break;
                case SocketOptionName_Type:
-                       *system_name=SO_TYPE;
+                       *system_name = SO_TYPE;
                        break;
                case SocketOptionName_ExclusiveAddressUse:
                case SocketOptionName_UseLoopback:
@@ -284,39 +304,64 @@ static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level,
                break;
                
        case SocketOptionLevel_IP:
-               *system_level=SOL_IP;
-
+#ifdef HAVE_SOL_IP
+               *system_level = SOL_IP;
+#else
+               if (1) {
+                       static int cached = 0;
+                       static int proto;
+                       
+                       if (!cached) {
+                               struct protoent *pent;
+                               
+                               pent = getprotobyname ("IP");
+                               proto = pent ? pent->p_proto : 0 /* 0 a good default value?? */;
+                               cached = 1;
+                       }
+                       
+                       *system_level = proto;
+               }
+#endif /* HAVE_SOL_IP */
+               
                switch(mono_name) {
                case SocketOptionName_IPOptions:
-                       *system_name=IP_OPTIONS;
+                       *system_name = IP_OPTIONS;
                        break;
+#ifdef IP_HDRINCL
                case SocketOptionName_HeaderIncluded:
-                       *system_name=IP_HDRINCL;
+                       *system_name = IP_HDRINCL;
                        break;
+#endif
+#ifdef IP_TOS
                case SocketOptionName_TypeOfService:
-                       *system_name=IP_TOS;
+                       *system_name = IP_TOS;
                        break;
+#endif
+#ifdef IP_TTL
                case SocketOptionName_IpTimeToLive:
-                       *system_name=IP_TTL;
+                       *system_name = IP_TTL;
                        break;
+#endif
                case SocketOptionName_MulticastInterface:
-                       *system_name=IP_MULTICAST_IF;
+                       *system_name = IP_MULTICAST_IF;
                        break;
                case SocketOptionName_MulticastTimeToLive:
-                       *system_name=IP_MULTICAST_TTL;
+                       *system_name = IP_MULTICAST_TTL;
                        break;
                case SocketOptionName_MulticastLoopback:
-                       *system_name=IP_MULTICAST_LOOP;
+                       *system_name = IP_MULTICAST_LOOP;
                        break;
                case SocketOptionName_AddMembership:
-                       *system_name=IP_ADD_MEMBERSHIP;
+                       *system_name = IP_ADD_MEMBERSHIP;
                        break;
                case SocketOptionName_DropMembership:
-                       *system_name=IP_DROP_MEMBERSHIP;
+                       *system_name = IP_DROP_MEMBERSHIP;
                        break;
+#ifdef HAVE_IP_PKTINFO
                case SocketOptionName_PacketInformation:
-                       *system_name=IP_PKTINFO;
+                       *system_name = IP_PKTINFO;
                        break;
+#endif /* HAVE_IP_PKTINFO */
                case SocketOptionName_DontFragment:
                case SocketOptionName_AddSourceMembership:
                case SocketOptionName_DropSourceMembership:
@@ -332,11 +377,28 @@ static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level,
                break;
                
        case SocketOptionLevel_Tcp:
-               *system_level=SOL_TCP;
-
+#ifdef HAVE_SOL_TCP
+               *system_level = SOL_TCP;
+#else
+               if (1) {
+                       static int cached = 0;
+                       static int proto;
+                       
+                       if (!cached) {
+                               struct protoent *pent;
+                               
+                               pent = getprotobyname ("TCP");
+                               proto = pent ? pent->p_proto : 6 /* is 6 a good default value?? */;
+                               cached = 1;
+                       }
+                       
+                       *system_level = proto;
+               }
+#endif /* HAVE_SOL_TCP */
+               
                switch(mono_name) {
                case SocketOptionName_NoDelay:
-                       *system_name=TCP_NODELAY;
+                       *system_name = TCP_NODELAY;
                        break;
 #if 0
                        /* The documentation is talking complete
@@ -376,7 +438,7 @@ static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level,
 }
 
 #define STASH_SYS_ASS(this) \
-       if(system_assembly==NULL) { \
+       if(system_assembly == NULL) { \
                system_assembly=this->vtable->klass->image; \
        }
 
@@ -402,7 +464,7 @@ static MonoException *get_socket_exception(guint32 error_code)
        return(ex);
 }
 
-SOCKET ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject *this, gint32 family, gint32 type, gint32 proto)
+gpointer ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject *this, gint32 family, gint32 type, gint32 proto)
 {
        SOCKET sock;
        gint32 sock_family;
@@ -445,9 +507,12 @@ SOCKET ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject *this, gin
                return(NULL);
        }
        
-       return(sock);
+       return(GUINT_TO_POINTER (sock));
 }
 
+/* FIXME: the SOCKET parameter (here and in other functions in this
+ * file) is really an IntPtr which needs to be converted to a guint32.
+ */
 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock)
 {
        closesocket(sock);
@@ -455,7 +520,10 @@ void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock)
 
 gint32 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
 {
+#ifdef DEBUG
        g_message(G_GNUC_PRETTY_FUNCTION ": returning %d", WSAGetLastError());
+#endif
+
        return(WSAGetLastError());
 }
 
@@ -483,7 +551,7 @@ void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock,
        }
 }
 
-SOCKET ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock)
+gpointer ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock)
 {
        SOCKET newsock;
        
@@ -493,7 +561,7 @@ SOCKET ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock)
                return(NULL);
        }
        
-       return(newsock);
+       return(GUINT_TO_POINTER (newsock));
 }
 
 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock,
@@ -734,13 +802,14 @@ gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoAr
        buf=mono_array_addr(buffer, guchar, offset);
        
        ret=recvfrom(sock, buf, count, recvflags, sa, &sa_size);
-       g_free(sa);
        
        if(ret==SOCKET_ERROR) {
+               g_free(sa);
                mono_raise_exception(get_socket_exception(WSAGetLastError()));
        }
 
        *sockaddr=create_object_from_sockaddr(sa, sa_size);
+       g_free(sa);
        
        return(ret);
 }
@@ -811,13 +880,13 @@ gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArra
        return(ret);
 }
 
-static SOCKET Socket_to_SOCKET(MonoObject *socket)
+static SOCKET Socket_to_SOCKET(MonoObject *sockobj)
 {
        SOCKET sock;
        MonoClassField *field;
        
-       field=mono_class_get_field_from_name(socket->vtable->klass, "socket");
-       sock=*(SOCKET *)(((char *)socket)+field->offset);
+       field=mono_class_get_field_from_name(sockobj->vtable->klass, "socket");
+       sock=*(SOCKET *)(((char *)sockobj)+field->offset);
 
        return(sock);
 }
@@ -1077,10 +1146,9 @@ void ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal(SOCKET sock, g
 
        /* Only one of obj_val, byte_val or int_val has data */
        if(obj_val!=NULL) {
+               MonoClassField *field;
                struct linger linger;
-               struct ip_mreqn mreq;
                int valsize;
-               MonoClassField *field;
                
                switch(name) {
                case SocketOptionName_DontLinger:
@@ -1104,23 +1172,35 @@ void ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal(SOCKET sock, g
                        ret=setsockopt(sock, system_level, system_name,
                                       &linger, valsize);
                        break;
-                       
                case SocketOptionName_AddMembership:
                case SocketOptionName_DropMembership:
+               {
+#ifdef HAVE_STRUCT_IP_MREQN
+                       struct ip_mreqn mreq;
+#else
+                       struct ip_mreq mreq;
+#endif /* HAVE_STRUCT_IP_MREQN */
+                       
                        /* pain! MulticastOption holds two IPAddress
                         * members, so I have to dig the value out of
                         * those :-(
                         */
-                       field=mono_class_get_field_from_name(obj_val->vtable->klass, "group");
-                       mreq.imr_multiaddr=ipaddress_to_struct_in_addr(*(gpointer *)(((char *)obj_val)+field->offset));
-                       field=mono_class_get_field_from_name(obj_val->vtable->klass, "local");
-                       mreq.imr_address=ipaddress_to_struct_in_addr(*(gpointer *)(((char *)obj_val)+field->offset))
-;
-                       valsize=sizeof(mreq);
-                       ret=setsockopt(sock, system_level, system_name,
-                                      &mreq, valsize);
+                       field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
+                       mreq.imr_multiaddr = ipaddress_to_struct_in_addr (*(gpointer *)(((char *)obj_val) +
+                                                                                       field->offset));
+                       field = mono_class_get_field_from_name (obj_val->vtable->klass, "local");
+#ifdef HAVE_STRUCT_IP_MREQN
+                       mreq.imr_address = ipaddress_to_struct_in_addr (*(gpointer *)(((char *)obj_val) +
+                                                                                     field->offset));
+#else
+                       mreq.imr_interface = ipaddress_to_struct_in_addr (*(gpointer *)(((char *)obj_val) +
+                                                                                       field->offset));
+#endif /* HAVE_STRUCT_IP_MREQN */
+                       
+                       ret = setsockopt (sock, system_level, system_name,
+                                         &mreq, sizeof (mreq));
                        break;
-
+               }
                default:
                        /* Throw an exception */
                        mono_raise_exception(get_socket_exception(WSAEINVAL));
@@ -1196,7 +1276,7 @@ static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
                MonoString *addr_string;
                char addr[16];
                
-               snprintf(addr, 16, "%u.%u.%u.%u",
+               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],
@@ -1210,14 +1290,14 @@ static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
        return(TRUE);
 }
 
-extern gboolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
+extern MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
 {
        char *hostname;
        struct hostent *he;
        
        hostname=mono_string_to_utf8(host);
        he=gethostbyname(hostname);
-       free(hostname);
+       g_free(hostname);
        
        if(he==NULL) {
                return(FALSE);
@@ -1226,27 +1306,80 @@ extern gboolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host
        return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
 }
 
-extern gboolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
+#ifndef HAVE_INET_PTON
+static int
+inet_pton (int family, const char *address, void *inaddrp)
 {
-       char *address;
-       guint32 inaddr;
+       if (family == AF_INET) {
+#ifdef HAVE_INET_ATON
+               struct in_addr inaddr;
+               
+               if (!inet_aton (address, &inaddr))
+                       return 0;
+               
+               memcpy (inaddrp, &inaddr, sizeof (struct in_addr));
+               return 1;
+#else
+               /* assume the system has inet_addr(), if it doesn't
+                  have that we're pretty much screwed... */
+               guint32 inaddr;
+               
+               if (!strcmp (address, "255.255.255.255")) {
+                       /* special-case hack */
+                       inaddr = 0xffffffff;
+               } else {
+                       inaddr = inet_addr (address);
+#ifndef INADDR_NONE
+#define INADDR_NONE ((in_addr_t) -1)
+#endif
+                       if (inaddr == INADDR_NONE)
+                               return 0;
+               }
+               
+               memcpy (inaddrp, &inaddr, sizeof (guint32));
+               return 1;
+#endif /* HAVE_INET_ATON */
+       }
+       
+       return -1;
+}
+#endif /* !HAVE_INET_PTON */
+
+extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
+{
+       struct in_addr inaddr;
        struct hostent *he;
+       char *address;
        
-       address=mono_string_to_utf8(addr);
-       inaddr=inet_addr(address);
-       free(address);
-       if(inaddr==INADDR_NONE) {
-               return(FALSE);
+       address = mono_string_to_utf8 (addr);
+       if (inet_pton (AF_INET, address, &inaddr) <= 0) {
+               g_free (address);
+               return FALSE;
        }
        
-       he=gethostbyaddr(&inaddr, sizeof(inaddr), AF_INET);
-       if(he==NULL) {
+       g_free (address);
+       if ((he = gethostbyaddr ((char *) &inaddr, sizeof (inaddr), AF_INET)) == NULL)
+               return FALSE;
+       
+       return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
+}
+
+extern MonoBoolean ves_icall_System_Net_Dns_GetHostName_internal(MonoString **h_name)
+{
+       guchar hostname[256];
+       int ret;
+       
+       ret=gethostname (hostname, sizeof(hostname));
+       if(ret==-1) {
                return(FALSE);
        }
+       
+       *h_name=mono_string_new(mono_domain_get (), hostname);
 
-       return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
+       return(TRUE);
 }
 
+
 void mono_network_init(void)
 {
        WSADATA wsadata;