2003-06-10 Dick Porter <dick@ximian.com>
[mono.git] / mono / metadata / socket-io.c
1 /*
2  * socket-io.c: Socket IO internal calls
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9
10 #include <config.h>
11
12 #include <glib.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16
17 #include <mono/metadata/object.h>
18 #include <mono/io-layer/io-layer.h>
19 #include <mono/metadata/socket-io.h>
20 #include <mono/metadata/exception.h>
21 #include <mono/metadata/appdomain.h>
22
23 #include <sys/time.h> 
24
25 #ifdef HAVE_NETDB_H
26 #include <netdb.h>
27 #endif
28 #ifdef HAVE_SYS_FILIO_H
29 #include <sys/filio.h>     /* defines FIONBIO and FIONREAD */
30 #endif
31 #ifdef HAVE_SYS_SOCKIO_H
32 #include <sys/sockio.h>    /* defines SIOCATMARK */
33 #endif
34 #ifdef HAVE_SYS_UN_H
35 #include <sys/un.h>
36 #endif
37
38
39
40 #undef DEBUG
41
42 static gint32 convert_family(MonoAddressFamily mono_family)
43 {
44         gint32 family=-1;
45         
46         switch(mono_family) {
47         case AddressFamily_Unknown:
48         case AddressFamily_ImpLink:
49         case AddressFamily_Pup:
50         case AddressFamily_Chaos:
51         case AddressFamily_Iso:
52         case AddressFamily_Ecma:
53         case AddressFamily_DataKit:
54         case AddressFamily_Ccitt:
55         case AddressFamily_DataLink:
56         case AddressFamily_Lat:
57         case AddressFamily_HyperChannel:
58         case AddressFamily_NetBios:
59         case AddressFamily_VoiceView:
60         case AddressFamily_FireFox:
61         case AddressFamily_Banyan:
62         case AddressFamily_Atm:
63         case AddressFamily_Cluster:
64         case AddressFamily_Ieee12844:
65         case AddressFamily_NetworkDesigners:
66                 g_warning("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family);
67                 break;
68                 
69         case AddressFamily_Unspecified:
70                 family=AF_UNSPEC;
71                 break;
72                 
73         case AddressFamily_Unix:
74                 family=AF_UNIX;
75                 break;
76                 
77         case AddressFamily_InterNetwork:
78                 family=AF_INET;
79                 break;
80                 
81 #ifdef AF_IPX
82         case AddressFamily_Ipx:
83                 family=AF_IPX;
84                 break;
85 #endif
86                 
87         case AddressFamily_Sna:
88                 family=AF_SNA;
89                 break;
90                 
91         case AddressFamily_DecNet:
92                 family=AF_DECnet;
93                 break;
94                 
95         case AddressFamily_AppleTalk:
96                 family=AF_APPLETALK;
97                 break;
98                 
99 #ifdef AF_INET6
100         case AddressFamily_InterNetworkV6:
101                 family=AF_INET6;
102                 break;
103 #endif
104 #ifdef AF_IRDA  
105         case AddressFamily_Irda:
106                 family=AF_IRDA;
107                 break;
108 #endif
109         default:
110                 g_warning("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family);
111         }
112
113         return(family);
114 }
115
116 static MonoAddressFamily convert_to_mono_family(guint16 af_family)
117 {
118         MonoAddressFamily family=AddressFamily_Unknown;
119         
120         switch(af_family) {
121         case AF_UNSPEC:
122                 family=AddressFamily_Unspecified;
123                 break;
124                 
125         case AF_UNIX:
126                 family=AddressFamily_Unix;
127                 break;
128                 
129         case AF_INET:
130                 family=AddressFamily_InterNetwork;
131                 break;
132                 
133 #ifdef AF_IPX
134         case AF_IPX:
135                 family=AddressFamily_Ipx;
136                 break;
137 #endif
138                 
139         case AF_SNA:
140                 family=AddressFamily_Sna;
141                 break;
142                 
143         case AF_DECnet:
144                 family=AddressFamily_DecNet;
145                 break;
146                 
147         case AF_APPLETALK:
148                 family=AddressFamily_AppleTalk;
149                 break;
150                 
151 #ifdef AF_INET6
152         case AF_INET6:
153                 family=AddressFamily_InterNetworkV6;
154                 break;
155 #endif
156                 
157 #ifdef AF_IRDA  
158         case AF_IRDA:
159                 family=AddressFamily_Irda;
160                 break;
161 #endif
162         default:
163                 g_warning("unknown address family 0x%x", af_family);
164         }
165
166         return(family);
167 }
168
169 static gint32 convert_type(MonoSocketType mono_type)
170 {
171         gint32 type=-1;
172         
173         switch(mono_type) {
174         case SocketType_Stream:
175                 type=SOCK_STREAM;
176                 break;
177
178         case SocketType_Dgram:
179                 type=SOCK_DGRAM;
180                 break;
181                 
182         case SocketType_Raw:
183                 type=SOCK_RAW;
184                 break;
185
186         case SocketType_Rdm:
187                 type=SOCK_RDM;
188                 break;
189
190         case SocketType_Seqpacket:
191                 type=SOCK_SEQPACKET;
192                 break;
193
194         case SocketType_Unknown:
195                 g_warning("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type);
196                 break;
197
198         default:
199                 g_warning("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type);
200         }
201
202         return(type);
203 }
204
205 static gint32 convert_proto(MonoProtocolType mono_proto)
206 {
207         gint32 proto=-1;
208         
209         switch(mono_proto) {
210         case ProtocolType_IP:
211         case ProtocolType_Icmp:
212         case ProtocolType_Igmp:
213         case ProtocolType_Ggp:
214         case ProtocolType_Tcp:
215         case ProtocolType_Pup:
216         case ProtocolType_Udp:
217         case ProtocolType_Idp:
218                 /* These protocols are known (on my system at least) */
219                 proto=mono_proto;
220                 break;
221                 
222         case ProtocolType_ND:
223         case ProtocolType_Raw:
224         case ProtocolType_Ipx:
225         case ProtocolType_Spx:
226         case ProtocolType_SpxII:
227         case ProtocolType_Unknown:
228                 /* These protocols arent */
229                 g_warning("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto);
230                 break;
231                 
232         default:
233                 break;
234         }
235
236         return(proto);
237 }
238
239 static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level,
240                                              MonoSocketOptionName mono_name,
241                                              int *system_level,
242                                              int *system_name)
243 {
244         switch (mono_level) {
245         case SocketOptionLevel_Socket:
246                 *system_level = SOL_SOCKET;
247                 
248                 switch(mono_name) {
249                 case SocketOptionName_DontLinger:
250                         /* This is SO_LINGER, because the setsockopt
251                          * internal call maps DontLinger to SO_LINGER
252                          * with l_onoff=0
253                          */
254                         *system_name = SO_LINGER;
255                         break;
256                 case SocketOptionName_Debug:
257                         *system_name = SO_DEBUG;
258                         break;
259 #ifdef SO_ACCEPTCONN
260                 case SocketOptionName_AcceptConnection:
261                         *system_name = SO_ACCEPTCONN;
262                         break;
263 #endif
264                 case SocketOptionName_ReuseAddress:
265                         *system_name = SO_REUSEADDR;
266                         break;
267                 case SocketOptionName_KeepAlive:
268                         *system_name = SO_KEEPALIVE;
269                         break;
270                 case SocketOptionName_DontRoute:
271                         *system_name = SO_DONTROUTE;
272                         break;
273                 case SocketOptionName_Broadcast:
274                         *system_name = SO_BROADCAST;
275                         break;
276                 case SocketOptionName_Linger:
277                         *system_name = SO_LINGER;
278                         break;
279                 case SocketOptionName_OutOfBandInline:
280                         *system_name = SO_OOBINLINE;
281                         break;
282                 case SocketOptionName_SendBuffer:
283                         *system_name = SO_SNDBUF;
284                         break;
285                 case SocketOptionName_ReceiveBuffer:
286                         *system_name = SO_RCVBUF;
287                         break;
288                 case SocketOptionName_SendLowWater:
289                         *system_name = SO_SNDLOWAT;
290                         break;
291                 case SocketOptionName_ReceiveLowWater:
292                         *system_name = SO_RCVLOWAT;
293                         break;
294                 case SocketOptionName_SendTimeout:
295                         *system_name = SO_SNDTIMEO;
296                         break;
297                 case SocketOptionName_ReceiveTimeout:
298                         *system_name = SO_RCVTIMEO;
299                         break;
300                 case SocketOptionName_Error:
301                         *system_name = SO_ERROR;
302                         break;
303                 case SocketOptionName_Type:
304                         *system_name = SO_TYPE;
305                         break;
306                 case SocketOptionName_ExclusiveAddressUse:
307                 case SocketOptionName_UseLoopback:
308                 case SocketOptionName_MaxConnections:
309                         /* Can't figure out how to map these, so fall
310                          * through
311                          */
312                 default:
313                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name);
314                         return(-1);
315                 }
316                 break;
317                 
318         case SocketOptionLevel_IP:
319 #ifdef HAVE_SOL_IP
320                 *system_level = SOL_IP;
321 #else
322                 if (1) {
323                         static int cached = 0;
324                         static int proto;
325                         
326                         if (!cached) {
327                                 struct protoent *pent;
328                                 
329                                 pent = getprotobyname ("IP");
330                                 proto = pent ? pent->p_proto : 0 /* 0 a good default value?? */;
331                                 cached = 1;
332                         }
333                         
334                         *system_level = proto;
335                 }
336 #endif /* HAVE_SOL_IP */
337                 
338                 switch(mono_name) {
339                 case SocketOptionName_IPOptions:
340                         *system_name = IP_OPTIONS;
341                         break;
342 #ifdef IP_HDRINCL
343                 case SocketOptionName_HeaderIncluded:
344                         *system_name = IP_HDRINCL;
345                         break;
346 #endif
347 #ifdef IP_TOS
348                 case SocketOptionName_TypeOfService:
349                         *system_name = IP_TOS;
350                         break;
351 #endif
352 #ifdef IP_TTL
353                 case SocketOptionName_IpTimeToLive:
354                         *system_name = IP_TTL;
355                         break;
356 #endif
357                 case SocketOptionName_MulticastInterface:
358                         *system_name = IP_MULTICAST_IF;
359                         break;
360                 case SocketOptionName_MulticastTimeToLive:
361                         *system_name = IP_MULTICAST_TTL;
362                         break;
363                 case SocketOptionName_MulticastLoopback:
364                         *system_name = IP_MULTICAST_LOOP;
365                         break;
366                 case SocketOptionName_AddMembership:
367                         *system_name = IP_ADD_MEMBERSHIP;
368                         break;
369                 case SocketOptionName_DropMembership:
370                         *system_name = IP_DROP_MEMBERSHIP;
371                         break;
372 #ifdef HAVE_IP_PKTINFO
373                 case SocketOptionName_PacketInformation:
374                         *system_name = IP_PKTINFO;
375                         break;
376 #endif /* HAVE_IP_PKTINFO */
377                 case SocketOptionName_DontFragment:
378                 case SocketOptionName_AddSourceMembership:
379                 case SocketOptionName_DropSourceMembership:
380                 case SocketOptionName_BlockSource:
381                 case SocketOptionName_UnblockSource:
382                         /* Can't figure out how to map these, so fall
383                          * through
384                          */
385                 default:
386                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name);
387                         return(-1);
388                 }
389                 break;
390                 
391         case SocketOptionLevel_Tcp:
392 #ifdef HAVE_SOL_TCP
393                 *system_level = SOL_TCP;
394 #else
395                 if (1) {
396                         static int cached = 0;
397                         static int proto;
398                         
399                         if (!cached) {
400                                 struct protoent *pent;
401                                 
402                                 pent = getprotobyname ("TCP");
403                                 proto = pent ? pent->p_proto : 6 /* is 6 a good default value?? */;
404                                 cached = 1;
405                         }
406                         
407                         *system_level = proto;
408                 }
409 #endif /* HAVE_SOL_TCP */
410                 
411                 switch(mono_name) {
412                 case SocketOptionName_NoDelay:
413                         *system_name = TCP_NODELAY;
414                         break;
415 #if 0
416                         /* The documentation is talking complete
417                          * bollocks here: rfc-1222 is titled
418                          * 'Advancing the NSFNET Routing Architecture'
419                          * and doesn't mention either of the words
420                          * "expedite" or "urgent".
421                          */
422                 case SocketOptionName_BsdUrgent:
423                 case SocketOptionName_Expedited:
424 #endif
425                 default:
426                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name);
427                         return(-1);
428                 }
429                 break;
430                 
431         case SocketOptionLevel_Udp:
432                 g_warning("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level);
433
434                 switch(mono_name) {
435                 case SocketOptionName_NoChecksum:
436                 case SocketOptionName_ChecksumCoverage:
437                 default:
438                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name);
439                         return(-1);
440                 }
441                 return(-1);
442                 break;
443
444         default:
445                 g_warning("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level);
446                 return(-1);
447         }
448
449         return(0);
450 }
451
452 #define STASH_SYS_ASS(this) \
453         if(system_assembly == NULL) { \
454                 system_assembly=this->vtable->klass->image; \
455         }
456
457 static MonoImage *system_assembly=NULL;
458
459 static MonoException *get_socket_exception(guint32 error_code)
460 {
461         /* Don't cache this exception, because we need the object
462          * constructor to set up the message from the sockets error code.
463          */
464         MonoException *ex;
465         
466         /* This is a bit of a kludge.  The SocketException 0-arg
467          * constructor calls WSAGetLastError() to find the error code
468          * to use.  Until we can init objects with parameters, this
469          * will have to do.
470          */
471         WSASetLastError(error_code);
472         
473         ex=(MonoException *)mono_exception_from_name(system_assembly,
474                                                      "System.Net.Sockets",
475                                                      "SocketException");
476         return(ex);
477 }
478
479 gpointer ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject *this, gint32 family, gint32 type, gint32 proto)
480 {
481         SOCKET sock;
482         gint32 sock_family;
483         gint32 sock_proto;
484         gint32 sock_type;
485         int ret;
486         int true=1;
487         
488         MONO_ARCH_SAVE_REGS;
489
490         STASH_SYS_ASS(this);
491         
492         sock_family=convert_family(family);
493         if(sock_family==-1) {
494                 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
495                 return(NULL);
496         }
497
498         sock_proto=convert_proto(proto);
499         if(sock_proto==-1) {
500                 mono_raise_exception(get_socket_exception(WSAEPROTONOSUPPORT));
501                 return(NULL);
502         }
503         
504         sock_type=convert_type(type);
505         if(sock_type==-1) {
506                 mono_raise_exception(get_socket_exception(WSAESOCKTNOSUPPORT));
507                 return(NULL);
508         }
509         
510         sock=socket(sock_family, sock_type, sock_proto);
511         if(sock==INVALID_SOCKET) {
512                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
513                 return(NULL);
514         }
515
516         if (sock_family == AF_INET && sock_type == SOCK_DGRAM)
517                 return (GUINT_TO_POINTER (sock));
518
519         /* .net seems to set this by default for SOCK_STREAM,
520          * not for SOCK_DGRAM (see bug #36322) */
521         ret=setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof(true));
522         if(ret==SOCKET_ERROR) {
523                 closesocket(sock);
524                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
525                 return(NULL);
526         }
527         
528         return(GUINT_TO_POINTER (sock));
529 }
530
531 /* FIXME: the SOCKET parameter (here and in other functions in this
532  * file) is really an IntPtr which needs to be converted to a guint32.
533  */
534 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock)
535 {
536         MONO_ARCH_SAVE_REGS;
537
538 #ifdef DEBUG
539         g_message (G_GNUC_PRETTY_FUNCTION ": closing 0x%x", sock);
540 #endif
541
542         closesocket(sock);
543 }
544
545 gint32 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
546 {
547         MONO_ARCH_SAVE_REGS;
548
549 #ifdef DEBUG
550         g_message(G_GNUC_PRETTY_FUNCTION ": returning %d", WSAGetLastError());
551 #endif
552
553         return(WSAGetLastError());
554 }
555
556 gint32 ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock)
557 {
558         int ret, amount;
559         
560         MONO_ARCH_SAVE_REGS;
561
562         ret=ioctlsocket(sock, FIONREAD, &amount);
563         if(ret==SOCKET_ERROR) {
564                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
565                 return(0);
566         }
567         
568         return(amount);
569 }
570
571 void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock,
572                                                            gboolean block)
573 {
574         int ret;
575         
576         MONO_ARCH_SAVE_REGS;
577
578         ret=ioctlsocket(sock, FIONBIO, &block);
579         if(ret==SOCKET_ERROR) {
580                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
581         }
582 }
583
584 gpointer ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock)
585 {
586         SOCKET newsock;
587         
588         MONO_ARCH_SAVE_REGS;
589
590         newsock=accept(sock, NULL, 0);
591         if(newsock==INVALID_SOCKET) {
592                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
593                 return(NULL);
594         }
595         
596         return(GUINT_TO_POINTER (newsock));
597 }
598
599 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock,
600                                                          guint32 backlog)
601 {
602         int ret;
603         
604         MONO_ARCH_SAVE_REGS;
605
606         ret=listen(sock, backlog);
607         if(ret==SOCKET_ERROR) {
608                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
609         }
610 }
611
612 static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr,
613                                                int sa_size)
614 {
615         MonoDomain *domain = mono_domain_get ();
616         MonoObject *sockaddr_obj;
617         MonoClass *sockaddr_class;
618         MonoClassField *field;
619         MonoArray *data;
620         MonoAddressFamily family;
621
622         /* Build a System.Net.SocketAddress object instance */
623         sockaddr_class=mono_class_from_name(system_assembly, "System.Net", "SocketAddress");
624         sockaddr_obj=mono_object_new(domain, sockaddr_class);
625         
626         /* Locate the SocketAddress data buffer in the object */
627         field=mono_class_get_field_from_name(sockaddr_class, "data");
628
629         /* Make sure there is space for the family and size bytes */
630         data=mono_array_new(domain, mono_defaults.byte_class, sa_size+2);
631
632         /* The data buffer is laid out as follows:
633          * byte 0 is the address family
634          * byte 1 is the buffer length
635          * bytes 2 and 3 are the port info
636          * the rest is the address info
637          */
638                 
639         family=convert_to_mono_family(saddr->sa_family);
640         if(family==AddressFamily_Unknown) {
641                 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
642                 return(NULL);
643         }
644
645         mono_array_set(data, guint8, 0, family & 0x0FF);
646         mono_array_set(data, guint8, 1, ((family << 8) & 0x0FFFF));
647         
648         if(saddr->sa_family==AF_INET) {
649                 struct sockaddr_in *sa_in=(struct sockaddr_in *)saddr;
650                 guint16 port=ntohs(sa_in->sin_port);
651                 guint32 address=ntohl(sa_in->sin_addr.s_addr);
652                 
653                 if(sa_size<8) {
654                         mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
655                 }
656                 
657                 mono_array_set(data, guint8, 2, (port>>8) & 0xff);
658                 mono_array_set(data, guint8, 3, (port) & 0xff);
659                 mono_array_set(data, guint8, 4, (address>>24) & 0xff);
660                 mono_array_set(data, guint8, 5, (address>>16) & 0xff);
661                 mono_array_set(data, guint8, 6, (address>>8) & 0xff);
662                 mono_array_set(data, guint8, 7, (address) & 0xff);
663                 
664                 *(MonoArray **)(((char *)sockaddr_obj) + field->offset)=data;
665
666                 return(sockaddr_obj);
667 #ifdef HAVE_SYS_UN_H
668         } else if (saddr->sa_family == AF_UNIX) {
669                 int i;
670
671                 for (i = 0; i < sa_size; i++)
672                         mono_array_set (data, guint8, i + 2, saddr->sa_data [i]);
673                 
674                 *(MonoArray **)(((char *)sockaddr_obj) + field->offset) = data;
675
676                 return sockaddr_obj;
677 #endif
678         } else {
679                 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
680                 return(NULL);
681         }
682 }
683
684 extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock)
685 {
686         struct sockaddr sa;
687         int salen;
688         int ret;
689         
690         MONO_ARCH_SAVE_REGS;
691
692         salen=sizeof(struct sockaddr);
693         ret=getsockname(sock, &sa, &salen);
694         
695         if(ret==SOCKET_ERROR) {
696                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
697         }
698         
699 #ifdef DEBUG
700         g_message(G_GNUC_PRETTY_FUNCTION ": bound to %s port %d", inet_ntoa(((struct sockaddr_in *)&sa)->sin_addr), ntohs(((struct sockaddr_in *)&sa)->sin_port));
701 #endif
702
703         return(create_object_from_sockaddr(&sa, salen));
704 }
705
706 extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock)
707 {
708         struct sockaddr sa;
709         int salen;
710         int ret;
711         
712         MONO_ARCH_SAVE_REGS;
713
714         salen=sizeof(struct sockaddr);
715         ret=getpeername(sock, &sa, &salen);
716         
717         if(ret==SOCKET_ERROR) {
718                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
719         }
720         
721 #ifdef DEBUG
722         g_message(G_GNUC_PRETTY_FUNCTION ": connected to %s port %d", inet_ntoa(((struct sockaddr_in *)&sa)->sin_addr), ntohs(((struct sockaddr_in *)&sa)->sin_port));
723 #endif
724
725         return(create_object_from_sockaddr(&sa, salen));
726 }
727
728 static struct sockaddr *create_sockaddr_from_object(MonoObject *saddr_obj,
729                                                     int *sa_size)
730 {
731         MonoClassField *field;
732         MonoArray *data;
733         gint32 family;
734         int len;
735
736         /* Dig the SocketAddress data buffer out of the object */
737         field=mono_class_get_field_from_name(saddr_obj->vtable->klass, "data");
738         data=*(MonoArray **)(((char *)saddr_obj) + field->offset);
739
740         /* The data buffer is laid out as follows:
741          * byte 0 is the address family low byte
742          * byte 1 is the address family high byte
743          * INET:
744          *      bytes 2 and 3 are the port info
745          *      the rest is the address info
746          * UNIX:
747          *      the rest is the file name
748          */
749         len = mono_array_length (data);
750         if (len < 2) {
751                 mono_raise_exception (mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
752         }
753         
754         family = convert_family (mono_array_get (data, guint16, 0));
755         if(family==AF_INET) {
756                 struct sockaddr_in *sa=g_new0(struct sockaddr_in, 1);
757                 guint16 port=(mono_array_get(data, guint8, 2) << 8) +
758                         mono_array_get(data, guint8, 3);
759                 guint32 address=(mono_array_get(data, guint8, 4) << 24) +
760                         (mono_array_get(data, guint8, 5) << 16 ) +
761                         (mono_array_get(data, guint8, 6) << 8) +
762                         mono_array_get(data, guint8, 7);
763                 
764                 sa->sin_family=family;
765                 sa->sin_addr.s_addr=htonl(address);
766                 sa->sin_port=htons(port);
767
768                 *sa_size=sizeof(struct sockaddr_in);
769                 return((struct sockaddr *)sa);
770 #ifdef HAVE_SYS_UN_H
771         } else if (family == AF_UNIX) {
772                 struct sockaddr_un *sock_un = g_new0 (struct sockaddr_un, 1);
773                 int i;
774
775                 if (len - 2 > MONO_SIZEOF_SUNPATH)
776                         mono_raise_exception (mono_get_exception_index_out_of_range ());
777
778                 sock_un->sun_family = family;
779                 for (i = 0; i < len - 2; i++)
780                         sock_un->sun_path [i] = mono_array_get (data, guint8,
781                                                                 i + 2);
782                 sock_un->sun_path [len - 2] = '\0';
783                 *sa_size = sizeof (struct sockaddr_un);
784
785                 return (struct sockaddr *)sock_un;
786 #endif
787         } else {
788                 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
789                 return(0);
790         }
791 }
792
793 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock, MonoObject *sockaddr)
794 {
795         struct sockaddr *sa;
796         int sa_size;
797         int ret;
798         
799         MONO_ARCH_SAVE_REGS;
800
801         sa=create_sockaddr_from_object(sockaddr, &sa_size);
802
803 #ifdef DEBUG
804         g_message(G_GNUC_PRETTY_FUNCTION ": binding to %s port %d", inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port));
805 #endif
806         ret=bind(sock, sa, sa_size);
807         g_free(sa);
808         
809         if(ret==SOCKET_ERROR) {
810                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
811         }
812 }
813
814 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock, MonoObject *sockaddr)
815 {
816         struct sockaddr *sa;
817         int sa_size;
818         int ret;
819         
820         MONO_ARCH_SAVE_REGS;
821
822         sa=create_sockaddr_from_object(sockaddr, &sa_size);
823         
824 #ifdef DEBUG
825         g_message(G_GNUC_PRETTY_FUNCTION ": connecting to %s port %d", inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port));
826 #endif
827
828         ret=connect(sock, sa, sa_size);
829         g_free(sa);
830         
831         if(ret==SOCKET_ERROR) {
832                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
833         }
834 }
835
836 gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags)
837 {
838         int ret;
839         guchar *buf;
840         gint32 alen;
841         int recvflags=0;
842         
843         MONO_ARCH_SAVE_REGS;
844
845         alen=mono_array_length(buffer);
846         if(offset+count>alen) {
847                 return(0);
848         }
849         
850         buf=mono_array_addr(buffer, guchar, offset);
851         
852         ret=recv(sock, buf, count, recvflags);
853         if(ret==SOCKET_ERROR) {
854                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
855         }
856         
857         return(ret);
858 }
859
860 gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr)
861 {
862         int ret;
863         guchar *buf;
864         gint32 alen;
865         int recvflags=0;
866         struct sockaddr *sa;
867         int sa_size;
868         
869         MONO_ARCH_SAVE_REGS;
870
871         alen=mono_array_length(buffer);
872         if(offset+count>alen) {
873                 return(0);
874         }
875
876         sa=create_sockaddr_from_object(*sockaddr, &sa_size);
877         
878         buf=mono_array_addr(buffer, guchar, offset);
879         
880         ret=recvfrom(sock, buf, count, recvflags, sa, &sa_size);
881         
882         if(ret==SOCKET_ERROR) {
883                 g_free(sa);
884                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
885         }
886
887         *sockaddr=create_object_from_sockaddr(sa, sa_size);
888         g_free(sa);
889         
890         return(ret);
891 }
892
893 gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags)
894 {
895         int ret;
896         guchar *buf;
897         gint32 alen;
898         int sendflags=0;
899         
900         MONO_ARCH_SAVE_REGS;
901
902         alen=mono_array_length(buffer);
903         if(offset+count>alen) {
904                 return(0);
905         }
906
907 #ifdef DEBUG
908         g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
909 #endif
910         
911         buf=mono_array_addr(buffer, guchar, offset);
912
913 #ifdef DEBUG
914         g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
915 #endif
916
917         ret=send(sock, buf, count, sendflags);
918         if(ret==SOCKET_ERROR) {
919                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
920         }
921         
922         return(ret);
923 }
924
925 gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr)
926 {
927         int ret;
928         guchar *buf;
929         gint32 alen;
930         int sendflags=0;
931         struct sockaddr *sa;
932         int sa_size;
933         
934         MONO_ARCH_SAVE_REGS;
935
936         alen=mono_array_length(buffer);
937         if(offset+count>alen) {
938                 return(0);
939         }
940
941         sa=create_sockaddr_from_object(sockaddr, &sa_size);
942         
943 #ifdef DEBUG
944         g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
945 #endif
946         
947         buf=mono_array_addr(buffer, guchar, offset);
948
949 #ifdef DEBUG
950         g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
951 #endif
952
953         ret=sendto(sock, buf, count, sendflags, sa, sa_size);
954         g_free(sa);
955         
956         if(ret==SOCKET_ERROR) {
957                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
958         }
959         
960         return(ret);
961 }
962
963 static SOCKET Socket_to_SOCKET(MonoObject *sockobj)
964 {
965         SOCKET sock;
966         MonoClassField *field;
967         
968         field=mono_class_get_field_from_name(sockobj->vtable->klass, "socket");
969         sock=*(SOCKET *)(((char *)sockobj)+field->offset);
970
971         return(sock);
972 }
973
974 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **read_socks, MonoArray **write_socks, MonoArray **err_socks, gint32 timeout)
975 {
976         fd_set readfds, writefds, errfds;
977         fd_set *readptr = NULL, *writeptr = NULL, *errptr = NULL;
978         struct timeval tv;
979         div_t divvy;
980         int ret;
981         int readarrsize = 0, writearrsize = 0, errarrsize = 0;
982         MonoDomain *domain=mono_domain_get();
983         MonoClass *sock_arr_class;
984         MonoArray *socks;
985         int count;
986         int i;
987         SOCKET handle;
988         
989         MONO_ARCH_SAVE_REGS;
990
991         if (*read_socks)
992                 readarrsize=mono_array_length(*read_socks);
993
994         if(readarrsize>FD_SETSIZE) {
995                 mono_raise_exception(get_socket_exception(WSAEFAULT));
996                 return;
997         }
998         
999         if (readarrsize) {
1000                 readptr = &readfds;
1001                 FD_ZERO(&readfds);
1002                 for(i=0; i<readarrsize; i++) {
1003                         handle = Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i));
1004                         FD_SET(handle, &readfds);
1005                 }
1006         }
1007         
1008         if (*write_socks)
1009                 writearrsize=mono_array_length(*write_socks);
1010
1011         if(writearrsize>FD_SETSIZE) {
1012                 mono_raise_exception(get_socket_exception(WSAEFAULT));
1013                 return;
1014         }
1015         
1016         if (writearrsize) {
1017                 writeptr = &writefds;
1018                 FD_ZERO(&writefds);
1019                 for(i=0; i<writearrsize; i++) {
1020                         handle = Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i));
1021                         FD_SET(handle, &writefds);
1022                 }
1023         }
1024         
1025         if (*err_socks)
1026                 errarrsize=mono_array_length(*err_socks);
1027
1028         if(errarrsize>FD_SETSIZE) {
1029                 mono_raise_exception(get_socket_exception(WSAEFAULT));
1030                 return;
1031         }
1032         
1033         if (errarrsize) {
1034                 errptr = &errfds;
1035                 FD_ZERO(&errfds);
1036                 for(i=0; i<errarrsize; i++) {
1037                         handle = Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i));
1038                         FD_SET(handle, &errfds);
1039                 }
1040         }
1041
1042         /* Negative timeout meaning block until ready is only
1043          * specified in Poll, not Select
1044          */
1045         if(timeout>=0) {
1046                 divvy=div(timeout, 1000000);
1047                 tv.tv_sec=divvy.quot;
1048                 tv.tv_usec=divvy.rem;
1049         
1050                 ret=select(0, readptr, writeptr, errptr, &tv);
1051         } else {
1052                 ret=select(0, readptr, writeptr, errptr, NULL);
1053         }
1054         
1055         if(ret==SOCKET_ERROR) {
1056                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1057                 return;
1058         }
1059
1060         if (readarrsize) {
1061                 sock_arr_class=((MonoObject *)*read_socks)->vtable->klass;
1062                 
1063                 count=0;
1064                 for(i=0; i<readarrsize; i++) {
1065                         if(FD_ISSET(Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i)), &readfds)) {
1066                                 count++;
1067                         }
1068                 }
1069                 socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
1070                 count=0;
1071                 for(i=0; i<readarrsize; i++) {
1072                         MonoObject *sock=mono_array_get(*read_socks, MonoObject *, i);
1073                         
1074                         if(FD_ISSET(Socket_to_SOCKET(sock), &readfds)) {
1075                                 mono_array_set(socks, MonoObject *, count, sock);
1076                                 count++;
1077                         }
1078                 }
1079                 *read_socks=socks;
1080         } else {
1081                 *read_socks = NULL;
1082         }
1083
1084         if (writearrsize) {
1085                 sock_arr_class=((MonoObject *)*write_socks)->vtable->klass;
1086                 count=0;
1087                 for(i=0; i<writearrsize; i++) {
1088                         if(FD_ISSET(Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i)), &writefds)) {
1089                                 count++;
1090                         }
1091                 }
1092                 socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
1093                 count=0;
1094                 for(i=0; i<writearrsize; i++) {
1095                         MonoObject *sock=mono_array_get(*write_socks, MonoObject *, i);
1096                         
1097                         if(FD_ISSET(Socket_to_SOCKET(sock), &writefds)) {
1098                                 mono_array_set(socks, MonoObject *, count, sock);
1099                                 count++;
1100                         }
1101                 }
1102                 *write_socks=socks;
1103         } else {
1104                 *write_socks = NULL;
1105         }
1106
1107         if (errarrsize) {
1108                 sock_arr_class=((MonoObject *)*err_socks)->vtable->klass;
1109                 count=0;
1110                 for(i=0; i<errarrsize; i++) {
1111                         if(FD_ISSET(Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i)), &errfds)) {
1112                                 count++;
1113                         }
1114                 }
1115                 socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
1116                 count=0;
1117                 for(i=0; i<errarrsize; i++) {
1118                         MonoObject *sock=mono_array_get(*err_socks, MonoObject *, i);
1119                         
1120                         if(FD_ISSET(Socket_to_SOCKET(sock), &errfds)) {
1121                                 mono_array_set(socks, MonoObject *, count, sock);
1122                                 count++;
1123                         }
1124                 }
1125                 *err_socks=socks;
1126         }
1127 }
1128
1129 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val)
1130 {
1131         int system_level;
1132         int system_name;
1133         int ret;
1134         int val;
1135         int valsize=sizeof(val);
1136         struct linger linger;
1137         int lingersize=sizeof(linger);
1138         MonoDomain *domain=mono_domain_get();
1139         MonoObject *obj;
1140         MonoClass *obj_class;
1141         MonoClassField *field;
1142         
1143         MONO_ARCH_SAVE_REGS;
1144
1145         ret=convert_sockopt_level_and_name(level, name, &system_level,
1146                                            &system_name);
1147         if(ret==-1) {
1148                 mono_raise_exception(get_socket_exception(WSAENOPROTOOPT));
1149                 return;
1150         }
1151         
1152         /* No need to deal with MulticastOption names here, because
1153          * you cant getsockopt AddMembership or DropMembership (the
1154          * int getsockopt will error, causing an exception)
1155          */
1156         switch(name) {
1157         case SocketOptionName_Linger:
1158         case SocketOptionName_DontLinger:
1159                 ret=getsockopt(sock, system_level, system_name, &linger,
1160                                &lingersize);
1161                 break;
1162                 
1163         default:
1164                 ret=getsockopt(sock, system_level, system_name, &val,
1165                                &valsize);
1166         }
1167         
1168         if(ret==SOCKET_ERROR) {
1169                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1170                 return;
1171         }
1172         
1173         switch(name) {
1174         case SocketOptionName_Linger:
1175                 /* build a System.Net.Sockets.LingerOption */
1176                 obj_class=mono_class_from_name(system_assembly,
1177                                                "System.Net.Sockets",
1178                                                "LingerOption");
1179                 obj=mono_object_new(domain, obj_class);
1180                 
1181                 /* Locate and set the fields "bool enabled" and "int
1182                  * seconds"
1183                  */
1184                 field=mono_class_get_field_from_name(obj_class, "enabled");
1185                 *(guint8 *)(((char *)obj)+field->offset)=linger.l_onoff;
1186
1187                 field=mono_class_get_field_from_name(obj_class, "seconds");
1188                 *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
1189                 
1190                 break;
1191                 
1192         case SocketOptionName_DontLinger:
1193                 /* construct a bool int in val - true if linger is off */
1194                 val=!linger.l_onoff;
1195                 
1196                 /* fall through */
1197                 
1198         default:
1199                 /* construct an Int32 object to hold val */
1200                 obj=mono_object_new(domain, mono_defaults.int32_class);
1201                 
1202                 /* Locate and set the "value" field */
1203                 field=mono_class_get_field_from_name(mono_defaults.int32_class,
1204                                                      "value");
1205                 *(gint32 *)(((char *)obj)+field->offset)=val;
1206         }
1207
1208         *obj_val=obj;
1209 }
1210
1211 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val)
1212 {
1213         int system_level;
1214         int system_name;
1215         int ret;
1216         guchar *buf;
1217         int valsize;
1218         
1219         MONO_ARCH_SAVE_REGS;
1220
1221         ret=convert_sockopt_level_and_name(level, name, &system_level,
1222                                            &system_name);
1223         if(ret==-1) {
1224                 mono_raise_exception(get_socket_exception(WSAENOPROTOOPT));
1225                 return;
1226         }
1227
1228         valsize=mono_array_length(*byte_val);
1229         buf=mono_array_addr(*byte_val, guchar, 0);
1230         
1231         ret=getsockopt(sock, system_level, system_name, buf, &valsize);
1232         if(ret==SOCKET_ERROR) {
1233                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1234         }
1235 }
1236
1237 static struct in_addr ipaddress_to_struct_in_addr(MonoObject *ipaddr)
1238 {
1239         struct in_addr inaddr;
1240         MonoClassField *field;
1241         
1242         field=mono_class_get_field_from_name(ipaddr->vtable->klass, "address");
1243
1244         /* No idea why .net uses a 64bit type to hold a 32bit value...
1245          *
1246          * Internal value of IPAddess is in Network Order, there is no need
1247          * to call htonl here.
1248          */
1249         inaddr.s_addr=(guint32)*(guint64 *)(((char *)ipaddr)+field->offset);
1250         
1251         return(inaddr);
1252 }
1253
1254 void ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal(SOCKET sock, gint32 level, gint32 name, MonoObject *obj_val, MonoArray *byte_val, gint32 int_val)
1255 {
1256         int system_level;
1257         int system_name;
1258         int ret;
1259
1260         MONO_ARCH_SAVE_REGS;
1261
1262         ret=convert_sockopt_level_and_name(level, name, &system_level,
1263                                            &system_name);
1264         if(ret==-1) {
1265                 mono_raise_exception(get_socket_exception(WSAENOPROTOOPT));
1266                 return;
1267         }
1268
1269         /* Only one of obj_val, byte_val or int_val has data */
1270         if(obj_val!=NULL) {
1271                 MonoClassField *field;
1272                 struct linger linger;
1273                 int valsize;
1274                 
1275                 switch(name) {
1276                 case SocketOptionName_DontLinger:
1277                         linger.l_onoff=0;
1278                         linger.l_linger=0;
1279                         valsize=sizeof(linger);
1280                         ret=setsockopt(sock, system_level, system_name,
1281                                        &linger, valsize);
1282                         break;
1283                         
1284                 case SocketOptionName_Linger:
1285                         /* Dig out "bool enabled" and "int seconds"
1286                          * fields
1287                          */
1288                         field=mono_class_get_field_from_name(obj_val->vtable->klass, "enabled");
1289                         linger.l_onoff=*(guint8 *)(((char *)obj_val)+field->offset);
1290                         field=mono_class_get_field_from_name(obj_val->vtable->klass, "seconds");
1291                         linger.l_linger=*(guint32 *)(((char *)obj_val)+field->offset);
1292                         
1293                         valsize=sizeof(linger);
1294                         ret=setsockopt(sock, system_level, system_name,
1295                                        &linger, valsize);
1296                         break;
1297                 case SocketOptionName_AddMembership:
1298                 case SocketOptionName_DropMembership:
1299 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1300                 {
1301                         MonoObject *address = NULL;
1302
1303 #ifdef HAVE_STRUCT_IP_MREQN
1304                         struct ip_mreqn mreq = {{0}};
1305 #else
1306                         struct ip_mreq mreq = {{0}};
1307 #endif /* HAVE_STRUCT_IP_MREQN */
1308                         
1309                         /* pain! MulticastOption holds two IPAddress
1310                          * members, so I have to dig the value out of
1311                          * those :-(
1312                          */
1313                         field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
1314                         address = *(gpointer *)(((char *)obj_val) + field->offset);
1315
1316                         /* address might not be defined and if so, set the address to ADDR_ANY.
1317                          */
1318                         if(address)
1319                                 mreq.imr_multiaddr = ipaddress_to_struct_in_addr (address);
1320
1321                         field = mono_class_get_field_from_name (obj_val->vtable->klass, "local");
1322                         address = *(gpointer *)(((char *)obj_val) + field->offset);
1323
1324 #ifdef HAVE_STRUCT_IP_MREQN
1325                         if(address)
1326                                 mreq.imr_address = ipaddress_to_struct_in_addr (address);
1327 #else
1328                         if(address)
1329                                 mreq.imr_interface = ipaddress_to_struct_in_addr (address);
1330 #endif /* HAVE_STRUCT_IP_MREQN */
1331                         
1332                         ret = setsockopt (sock, system_level, system_name,
1333                                           &mreq, sizeof (mreq));
1334                         break;
1335                 }
1336 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
1337                 default:
1338                         /* Throw an exception */
1339                         mono_raise_exception(get_socket_exception(WSAEINVAL));
1340                 }
1341         } else if (byte_val!=NULL) {
1342                 int valsize=mono_array_length(byte_val);
1343                 guchar *buf=mono_array_addr(byte_val, guchar, 0);
1344         
1345                 ret=setsockopt(sock, system_level, system_name, buf, valsize);
1346                 if(ret==SOCKET_ERROR) {
1347                         mono_raise_exception(get_socket_exception(WSAGetLastError()));
1348                 }
1349         } else {
1350                 ret=setsockopt(sock, system_level, system_name, &int_val,
1351                                sizeof(int_val));
1352         }
1353
1354         if(ret==SOCKET_ERROR) {
1355                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1356         }
1357 }
1358
1359 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock,
1360                                                            gint32 how)
1361 {
1362         int ret;
1363         
1364         MONO_ARCH_SAVE_REGS;
1365
1366         /* Currently, the values for how (recv=0, send=1, both=2) match
1367          * the BSD API
1368          */
1369         ret=shutdown(sock, how);
1370         if(ret==SOCKET_ERROR) {
1371                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1372         }
1373 }
1374
1375 static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
1376                                        MonoArray **h_aliases,
1377                                        MonoArray **h_addr_list)
1378 {
1379         MonoDomain *domain = mono_domain_get ();
1380         int i;
1381
1382         if(he->h_length!=4 || he->h_addrtype!=AF_INET) {
1383                 return(FALSE);
1384         }
1385
1386         *h_name=mono_string_new(domain, he->h_name);
1387
1388         i=0;
1389         while(he->h_aliases[i]!=NULL) {
1390                 i++;
1391         }
1392         
1393         *h_aliases=mono_array_new(domain, mono_defaults.string_class, i);
1394         i=0;
1395         while(he->h_aliases[i]!=NULL) {
1396                 MonoString *alias;
1397                 
1398                 alias=mono_string_new(domain, he->h_aliases[i]);
1399                 mono_array_set(*h_aliases, MonoString *, i, alias);
1400                 i++;
1401         }
1402
1403         i=0;
1404         while(he->h_addr_list[i]!=NULL) {
1405                 i++;
1406         }
1407         
1408         *h_addr_list=mono_array_new(domain, mono_defaults.string_class, i);
1409         i=0;
1410         while(he->h_addr_list[i]!=NULL) {
1411                 MonoString *addr_string;
1412                 char addr[16];
1413                 
1414                 g_snprintf(addr, 16, "%u.%u.%u.%u",
1415                          (unsigned char)he->h_addr_list[i][0],
1416                          (unsigned char)he->h_addr_list[i][1],
1417                          (unsigned char)he->h_addr_list[i][2],
1418                          (unsigned char)he->h_addr_list[i][3]);
1419                 
1420                 addr_string=mono_string_new(domain, addr);
1421                 mono_array_set(*h_addr_list, MonoString *, i, addr_string);
1422                 i++;
1423         }
1424
1425         return(TRUE);
1426 }
1427
1428 extern MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
1429 {
1430         char *hostname;
1431         struct hostent *he;
1432         
1433         MONO_ARCH_SAVE_REGS;
1434
1435         hostname=mono_string_to_utf8(host);
1436         he=gethostbyname(hostname);
1437         g_free(hostname);
1438         
1439         if(he==NULL) {
1440                 return(FALSE);
1441         }
1442
1443         return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
1444 }
1445
1446 #ifndef HAVE_INET_PTON
1447 static int
1448 inet_pton (int family, const char *address, void *inaddrp)
1449 {
1450         if (family == AF_INET) {
1451 #ifdef HAVE_INET_ATON
1452                 struct in_addr inaddr;
1453                 
1454                 if (!inet_aton (address, &inaddr))
1455                         return 0;
1456                 
1457                 memcpy (inaddrp, &inaddr, sizeof (struct in_addr));
1458                 return 1;
1459 #else
1460                 /* assume the system has inet_addr(), if it doesn't
1461                    have that we're pretty much screwed... */
1462                 guint32 inaddr;
1463                 
1464                 if (!strcmp (address, "255.255.255.255")) {
1465                         /* special-case hack */
1466                         inaddr = 0xffffffff;
1467                 } else {
1468                         inaddr = inet_addr (address);
1469 #ifndef INADDR_NONE
1470 #define INADDR_NONE ((in_addr_t) -1)
1471 #endif
1472                         if (inaddr == INADDR_NONE)
1473                                 return 0;
1474                 }
1475                 
1476                 memcpy (inaddrp, &inaddr, sizeof (guint32));
1477                 return 1;
1478 #endif /* HAVE_INET_ATON */
1479         }
1480         
1481         return -1;
1482 }
1483 #endif /* !HAVE_INET_PTON */
1484
1485 extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
1486 {
1487         struct in_addr inaddr;
1488         struct hostent *he;
1489         char *address;
1490         
1491         MONO_ARCH_SAVE_REGS;
1492
1493         address = mono_string_to_utf8 (addr);
1494         if (inet_pton (AF_INET, address, &inaddr) <= 0) {
1495                 g_free (address);
1496                 return FALSE;
1497         }
1498         
1499         g_free (address);
1500         if ((he = gethostbyaddr ((char *) &inaddr, sizeof (inaddr), AF_INET)) == NULL)
1501                 return FALSE;
1502         
1503         return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
1504 }
1505
1506 extern MonoBoolean ves_icall_System_Net_Dns_GetHostName_internal(MonoString **h_name)
1507 {
1508         guchar hostname[256];
1509         int ret;
1510         
1511         MONO_ARCH_SAVE_REGS;
1512
1513         ret=gethostname (hostname, sizeof(hostname));
1514         if(ret==-1) {
1515                 return(FALSE);
1516         }
1517         
1518         *h_name=mono_string_new(mono_domain_get (), hostname);
1519
1520         return(TRUE);
1521 }
1522
1523
1524 void mono_network_init(void)
1525 {
1526         WSADATA wsadata;
1527         int err;
1528         
1529         err=WSAStartup(MAKEWORD(2,0), &wsadata);
1530         if(err!=0) {
1531                 g_error(G_GNUC_PRETTY_FUNCTION ": Couldn't initialise networking");
1532                 exit(-1);
1533         }
1534
1535 #ifdef DEBUG
1536         g_message(G_GNUC_PRETTY_FUNCTION ": Using socket library: %s", wsadata.szDescription);
1537         g_message(G_GNUC_PRETTY_FUNCTION ": Socket system status: %s", wsadata.szSystemStatus);
1538 #endif
1539 }
1540
1541 void mono_network_cleanup(void)
1542 {
1543         WSACleanup();
1544 }