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