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