Made message fit in 80 cols without wrapping, fixed typo too.
[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 gpointer 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(GUINT_TO_POINTER (sock));
502 }
503
504 /* FIXME: the SOCKET parameter (here and in other functions in this
505  * file) is really an IntPtr which needs to be converted to a guint32.
506  */
507 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock)
508 {
509         closesocket(sock);
510 }
511
512 gint32 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
513 {
514         g_message(G_GNUC_PRETTY_FUNCTION ": returning %d", WSAGetLastError());
515         return(WSAGetLastError());
516 }
517
518 gint32 ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock)
519 {
520         int ret, amount;
521         
522         ret=ioctlsocket(sock, FIONREAD, &amount);
523         if(ret==SOCKET_ERROR) {
524                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
525                 return(0);
526         }
527         
528         return(amount);
529 }
530
531 void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock,
532                                                            gboolean block)
533 {
534         int ret;
535         
536         ret=ioctlsocket(sock, FIONBIO, &block);
537         if(ret==SOCKET_ERROR) {
538                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
539         }
540 }
541
542 gpointer ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock)
543 {
544         SOCKET newsock;
545         
546         newsock=accept(sock, NULL, 0);
547         if(newsock==INVALID_SOCKET) {
548                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
549                 return(NULL);
550         }
551         
552         return(GUINT_TO_POINTER (newsock));
553 }
554
555 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock,
556                                                          guint32 backlog)
557 {
558         int ret;
559         
560         ret=listen(sock, backlog);
561         if(ret==SOCKET_ERROR) {
562                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
563         }
564 }
565
566 static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr,
567                                                int sa_size)
568 {
569         MonoDomain *domain = mono_domain_get ();
570         MonoObject *sockaddr_obj;
571         MonoClass *sockaddr_class;
572         MonoClassField *field;
573         MonoArray *data;
574         MonoAddressFamily family;
575
576         /* Build a System.Net.SocketAddress object instance */
577         sockaddr_class=mono_class_from_name(system_assembly, "System.Net", "SocketAddress");
578         sockaddr_obj=mono_object_new(domain, sockaddr_class);
579         
580         /* Locate the SocketAddress data buffer in the object */
581         field=mono_class_get_field_from_name(sockaddr_class, "data");
582
583         /* Make sure there is space for the family and size bytes */
584         data=mono_array_new(domain, mono_defaults.byte_class, sa_size+2);
585
586         /* The data buffer is laid out as follows:
587          * byte 0 is the address family
588          * byte 1 is the buffer length
589          * bytes 2 and 3 are the port info
590          * the rest is the address info
591          */
592                 
593         family=convert_to_mono_family(saddr->sa_family);
594         if(family==AddressFamily_Unknown) {
595                 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
596                 return(NULL);
597         }
598
599         mono_array_set(data, guint8, 0, family);
600         mono_array_set(data, guint8, 1, sa_size+2);
601         
602         if(saddr->sa_family==AF_INET) {
603                 struct sockaddr_in *sa_in=(struct sockaddr_in *)saddr;
604                 guint16 port=ntohs(sa_in->sin_port);
605                 guint32 address=ntohl(sa_in->sin_addr.s_addr);
606                 
607                 if(sa_size<8) {
608                         mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
609                 }
610                 
611                 mono_array_set(data, guint8, 2, (port>>8) & 0xff);
612                 mono_array_set(data, guint8, 3, (port) & 0xff);
613                 mono_array_set(data, guint8, 4, (address>>24) & 0xff);
614                 mono_array_set(data, guint8, 5, (address>>16) & 0xff);
615                 mono_array_set(data, guint8, 6, (address>>8) & 0xff);
616                 mono_array_set(data, guint8, 7, (address) & 0xff);
617                 
618                 *(MonoArray **)(((char *)sockaddr_obj) + field->offset)=data;
619
620                 return(sockaddr_obj);
621         } else {
622                 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
623                 return(NULL);
624         }
625 }
626
627 extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock)
628 {
629         struct sockaddr sa;
630         int salen;
631         int ret;
632         
633         salen=sizeof(struct sockaddr);
634         ret=getsockname(sock, &sa, &salen);
635         
636         if(ret==SOCKET_ERROR) {
637                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
638         }
639         
640 #ifdef DEBUG
641         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));
642 #endif
643
644         return(create_object_from_sockaddr(&sa, salen));
645 }
646
647 extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock)
648 {
649         struct sockaddr sa;
650         int salen;
651         int ret;
652         
653         salen=sizeof(struct sockaddr);
654         ret=getpeername(sock, &sa, &salen);
655         
656         if(ret==SOCKET_ERROR) {
657                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
658         }
659         
660 #ifdef DEBUG
661         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));
662 #endif
663
664         return(create_object_from_sockaddr(&sa, salen));
665 }
666
667 static struct sockaddr *create_sockaddr_from_object(MonoObject *saddr_obj,
668                                                     int *sa_size)
669 {
670         MonoClassField *field;
671         MonoArray *data;
672         gint32 family;
673         int len;
674
675         /* Dig the SocketAddress data buffer out of the object */
676         field=mono_class_get_field_from_name(saddr_obj->vtable->klass, "data");
677         data=*(MonoArray **)(((char *)saddr_obj) + field->offset);
678
679         /* The data buffer is laid out as follows:
680          * byte 0 is the address family
681          * byte 1 is the buffer length
682          * bytes 2 and 3 are the port info
683          * the rest is the address info
684          */
685         len=mono_array_get(data, guint8, 1);
686         if((len<2) || (mono_array_length(data)!=len)) {
687                 mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
688         }
689         
690         family=convert_family(mono_array_get(data, guint8, 0));
691         if(family==AF_INET) {
692                 struct sockaddr_in *sa=g_new0(struct sockaddr_in, 1);
693                 guint16 port=(mono_array_get(data, guint8, 2) << 8) +
694                         mono_array_get(data, guint8, 3);
695                 guint32 address=(mono_array_get(data, guint8, 4) << 24) +
696                         (mono_array_get(data, guint8, 5) << 16 ) +
697                         (mono_array_get(data, guint8, 6) << 8) +
698                         mono_array_get(data, guint8, 7);
699                 
700                 sa->sin_family=family;
701                 sa->sin_addr.s_addr=htonl(address);
702                 sa->sin_port=htons(port);
703
704                 *sa_size=sizeof(struct sockaddr_in);
705                 return((struct sockaddr *)sa);
706         } else {
707                 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
708                 return(0);
709         }
710 }
711
712 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock, MonoObject *sockaddr)
713 {
714         struct sockaddr *sa;
715         int sa_size;
716         int ret;
717         
718         sa=create_sockaddr_from_object(sockaddr, &sa_size);
719
720 #ifdef DEBUG
721         g_message(G_GNUC_PRETTY_FUNCTION ": binding to %s port %d", inet_ntoa(sa.sin_addr), port);
722 #endif
723
724         ret=bind(sock, sa, sa_size);
725         g_free(sa);
726         
727         if(ret==SOCKET_ERROR) {
728                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
729         }
730 }
731
732 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock, MonoObject *sockaddr)
733 {
734         struct sockaddr *sa;
735         int sa_size;
736         int ret;
737         
738         sa=create_sockaddr_from_object(sockaddr, &sa_size);
739         
740 #ifdef DEBUG
741         g_message(G_GNUC_PRETTY_FUNCTION ": connecting to %s port %d", inet_ntoa(sa.sin_addr), port);
742 #endif
743
744         ret=connect(sock, sa, sa_size);
745         g_free(sa);
746         
747         if(ret==SOCKET_ERROR) {
748                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
749         }
750 }
751
752 gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags)
753 {
754         int ret;
755         guchar *buf;
756         gint32 alen;
757         int recvflags=0;
758         
759         alen=mono_array_length(buffer);
760         if(offset+count>alen) {
761                 return(0);
762         }
763         
764         buf=mono_array_addr(buffer, guchar, offset);
765         
766         ret=recv(sock, buf, count, recvflags);
767         if(ret==SOCKET_ERROR) {
768                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
769         }
770         
771         return(ret);
772 }
773
774 gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr)
775 {
776         int ret;
777         guchar *buf;
778         gint32 alen;
779         int recvflags=0;
780         struct sockaddr *sa;
781         int sa_size;
782         
783         alen=mono_array_length(buffer);
784         if(offset+count>alen) {
785                 return(0);
786         }
787
788         sa=create_sockaddr_from_object(*sockaddr, &sa_size);
789         
790         buf=mono_array_addr(buffer, guchar, offset);
791         
792         ret=recvfrom(sock, buf, count, recvflags, sa, &sa_size);
793         g_free(sa);
794         
795         if(ret==SOCKET_ERROR) {
796                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
797         }
798
799         *sockaddr=create_object_from_sockaddr(sa, sa_size);
800         
801         return(ret);
802 }
803
804 gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags)
805 {
806         int ret;
807         guchar *buf;
808         gint32 alen;
809         int sendflags=0;
810         
811         alen=mono_array_length(buffer);
812         if(offset+count>alen) {
813                 return(0);
814         }
815
816 #ifdef DEBUG
817         g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
818 #endif
819         
820         buf=mono_array_addr(buffer, guchar, offset);
821
822 #ifdef DEBUG
823         g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
824 #endif
825
826         ret=send(sock, buf, count, sendflags);
827         if(ret==SOCKET_ERROR) {
828                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
829         }
830         
831         return(ret);
832 }
833
834 gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr)
835 {
836         int ret;
837         guchar *buf;
838         gint32 alen;
839         int sendflags=0;
840         struct sockaddr *sa;
841         int sa_size;
842         
843         alen=mono_array_length(buffer);
844         if(offset+count>alen) {
845                 return(0);
846         }
847
848         sa=create_sockaddr_from_object(sockaddr, &sa_size);
849         
850 #ifdef DEBUG
851         g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
852 #endif
853         
854         buf=mono_array_addr(buffer, guchar, offset);
855
856 #ifdef DEBUG
857         g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
858 #endif
859
860         ret=sendto(sock, buf, count, sendflags, sa, sa_size);
861         g_free(sa);
862         
863         if(ret==SOCKET_ERROR) {
864                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
865         }
866         
867         return(ret);
868 }
869
870 static SOCKET Socket_to_SOCKET(MonoObject *sockobj)
871 {
872         SOCKET sock;
873         MonoClassField *field;
874         
875         field=mono_class_get_field_from_name(sockobj->vtable->klass, "socket");
876         sock=*(SOCKET *)(((char *)sockobj)+field->offset);
877
878         return(sock);
879 }
880
881 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **read_socks, MonoArray **write_socks, MonoArray **err_socks, gint32 timeout)
882 {
883         fd_set readfds, writefds, errfds;
884         struct timeval tv;
885         div_t divvy;
886         int ret;
887         int readarrsize, writearrsize, errarrsize;
888         MonoDomain *domain=mono_domain_get();
889         MonoClass *sock_arr_class;
890         MonoArray *socks;
891         int count;
892         int i;
893         
894         readarrsize=mono_array_length(*read_socks);
895         if(readarrsize>FD_SETSIZE) {
896                 mono_raise_exception(get_socket_exception(WSAEFAULT));
897                 return;
898         }
899         
900         FD_ZERO(&readfds);
901         for(i=0; i<readarrsize; i++) {
902                 FD_SET(Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i)), &readfds);
903         }
904         
905         writearrsize=mono_array_length(*write_socks);
906         if(writearrsize>FD_SETSIZE) {
907                 mono_raise_exception(get_socket_exception(WSAEFAULT));
908                 return;
909         }
910         
911         FD_ZERO(&writefds);
912         for(i=0; i<writearrsize; i++) {
913                 FD_SET(Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i)), &writefds);
914         }
915         
916         errarrsize=mono_array_length(*err_socks);
917         if(errarrsize>FD_SETSIZE) {
918                 mono_raise_exception(get_socket_exception(WSAEFAULT));
919                 return;
920         }
921         
922         FD_ZERO(&errfds);
923         for(i=0; i<errarrsize; i++) {
924                 FD_SET(Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i)), &errfds);
925         }
926
927         /* Negative timeout meaning block until ready is only
928          * specified in Poll, not Select
929          */
930         if(timeout>=0) {
931                 divvy=div(timeout, 1000000);
932                 tv.tv_sec=divvy.quot;
933                 tv.tv_usec=divvy.rem*1000000;
934         
935                 ret=select(0, &readfds, &writefds, &errfds, &tv);
936         } else {
937                 ret=select(0, &readfds, &writefds, &errfds, NULL);
938         }
939         
940         if(ret==SOCKET_ERROR) {
941                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
942                 return;
943         }
944
945         sock_arr_class=((MonoObject *)*read_socks)->vtable->klass;
946         
947         count=0;
948         for(i=0; i<readarrsize; i++) {
949                 if(FD_ISSET(Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i)), &readfds)) {
950                         count++;
951                 }
952         }
953         socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
954         count=0;
955         for(i=0; i<readarrsize; i++) {
956                 MonoObject *sock=mono_array_get(*read_socks, MonoObject *, i);
957                 
958                 if(FD_ISSET(Socket_to_SOCKET(sock), &readfds)) {
959                         mono_array_set(socks, MonoObject *, count, sock);
960                         count++;
961                 }
962         }
963         *read_socks=socks;
964
965         count=0;
966         for(i=0; i<writearrsize; i++) {
967                 if(FD_ISSET(Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i)), &writefds)) {
968                         count++;
969                 }
970         }
971         socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
972         count=0;
973         for(i=0; i<writearrsize; i++) {
974                 MonoObject *sock=mono_array_get(*write_socks, MonoObject *, i);
975                 
976                 if(FD_ISSET(Socket_to_SOCKET(sock), &writefds)) {
977                         mono_array_set(socks, MonoObject *, count, sock);
978                         count++;
979                 }
980         }
981         *write_socks=socks;
982
983         count=0;
984         for(i=0; i<errarrsize; i++) {
985                 if(FD_ISSET(Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i)), &errfds)) {
986                         count++;
987                 }
988         }
989         socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
990         count=0;
991         for(i=0; i<errarrsize; i++) {
992                 MonoObject *sock=mono_array_get(*err_socks, MonoObject *, i);
993                 
994                 if(FD_ISSET(Socket_to_SOCKET(sock), &errfds)) {
995                         mono_array_set(socks, MonoObject *, count, sock);
996                         count++;
997                 }
998         }
999         *err_socks=socks;
1000 }
1001
1002 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val)
1003 {
1004         int system_level;
1005         int system_name;
1006         int ret;
1007         int val;
1008         int valsize=sizeof(val);
1009         struct linger linger;
1010         int lingersize=sizeof(linger);
1011         MonoDomain *domain=mono_domain_get();
1012         MonoObject *obj;
1013         MonoClass *obj_class;
1014         MonoClassField *field;
1015         
1016         ret=convert_sockopt_level_and_name(level, name, &system_level,
1017                                            &system_name);
1018         if(ret==-1) {
1019                 mono_raise_exception(get_socket_exception(WSAENOPROTOOPT));
1020                 return;
1021         }
1022         
1023         /* No need to deal with MulticastOption names here, because
1024          * you cant getsockopt AddMembership or DropMembership (the
1025          * int getsockopt will error, causing an exception)
1026          */
1027         switch(name) {
1028         case SocketOptionName_Linger:
1029         case SocketOptionName_DontLinger:
1030                 ret=getsockopt(sock, system_level, system_name, &linger,
1031                                &lingersize);
1032                 break;
1033                 
1034         default:
1035                 ret=getsockopt(sock, system_level, system_name, &val,
1036                                &valsize);
1037         }
1038         
1039         if(ret==SOCKET_ERROR) {
1040                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1041                 return;
1042         }
1043         
1044         switch(name) {
1045         case SocketOptionName_Linger:
1046                 /* build a System.Net.Sockets.LingerOption */
1047                 obj_class=mono_class_from_name(system_assembly,
1048                                                "System.Net.Sockets",
1049                                                "LingerOption");
1050                 obj=mono_object_new(domain, obj_class);
1051                 
1052                 /* Locate and set the fields "bool enabled" and "int
1053                  * seconds"
1054                  */
1055                 field=mono_class_get_field_from_name(obj_class, "enabled");
1056                 *(guint8 *)(((char *)obj)+field->offset)=linger.l_onoff;
1057
1058                 field=mono_class_get_field_from_name(obj_class, "seconds");
1059                 *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
1060                 
1061                 break;
1062                 
1063         case SocketOptionName_DontLinger:
1064                 /* construct a bool int in val - true if linger is off */
1065                 val=!linger.l_onoff;
1066                 
1067                 /* fall through */
1068                 
1069         default:
1070                 /* construct an Int32 object to hold val */
1071                 obj=mono_object_new(domain, mono_defaults.int32_class);
1072                 
1073                 /* Locate and set the "value" field */
1074                 field=mono_class_get_field_from_name(mono_defaults.int32_class,
1075                                                      "value");
1076                 *(gint32 *)(((char *)obj)+field->offset)=val;
1077         }
1078
1079         *obj_val=obj;
1080 }
1081
1082 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val)
1083 {
1084         int system_level;
1085         int system_name;
1086         int ret;
1087         guchar *buf;
1088         int valsize;
1089         
1090         ret=convert_sockopt_level_and_name(level, name, &system_level,
1091                                            &system_name);
1092         if(ret==-1) {
1093                 mono_raise_exception(get_socket_exception(WSAENOPROTOOPT));
1094                 return;
1095         }
1096
1097         valsize=mono_array_length(*byte_val);
1098         buf=mono_array_addr(*byte_val, guchar, 0);
1099         
1100         ret=getsockopt(sock, system_level, system_name, buf, &valsize);
1101         if(ret==SOCKET_ERROR) {
1102                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1103         }
1104 }
1105
1106 static struct in_addr ipaddress_to_struct_in_addr(MonoObject *ipaddr)
1107 {
1108         struct in_addr inaddr;
1109         guint64 addr;
1110         MonoClassField *field;
1111         
1112         field=mono_class_get_field_from_name(ipaddr->vtable->klass, "address");
1113         addr=*(guint64 *)(((char *)ipaddr)+field->offset);
1114
1115         /* No idea why .net uses a 64bit type to hold a 32bit value */
1116         inaddr.s_addr=htonl((guint32)addr);
1117         
1118         return(inaddr);
1119 }
1120
1121 void ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal(SOCKET sock, gint32 level, gint32 name, MonoObject *obj_val, MonoArray *byte_val, gint32 int_val)
1122 {
1123         int system_level;
1124         int system_name;
1125         int ret;
1126
1127         ret=convert_sockopt_level_and_name(level, name, &system_level,
1128                                            &system_name);
1129         if(ret==-1) {
1130                 mono_raise_exception(get_socket_exception(WSAENOPROTOOPT));
1131                 return;
1132         }
1133
1134         /* Only one of obj_val, byte_val or int_val has data */
1135         if(obj_val!=NULL) {
1136                 MonoClassField *field;
1137                 struct linger linger;
1138                 int valsize;
1139                 
1140                 switch(name) {
1141                 case SocketOptionName_DontLinger:
1142                         linger.l_onoff=0;
1143                         linger.l_linger=0;
1144                         valsize=sizeof(linger);
1145                         ret=setsockopt(sock, system_level, system_name,
1146                                        &linger, valsize);
1147                         break;
1148                         
1149                 case SocketOptionName_Linger:
1150                         /* Dig out "bool enabled" and "int seconds"
1151                          * fields
1152                          */
1153                         field=mono_class_get_field_from_name(obj_val->vtable->klass, "enabled");
1154                         linger.l_onoff=*(guint8 *)(((char *)obj_val)+field->offset);
1155                         field=mono_class_get_field_from_name(obj_val->vtable->klass, "seconds");
1156                         linger.l_linger=*(guint32 *)(((char *)obj_val)+field->offset);
1157                         
1158                         valsize=sizeof(linger);
1159                         ret=setsockopt(sock, system_level, system_name,
1160                                        &linger, valsize);
1161                         break;
1162                 case SocketOptionName_AddMembership:
1163                 case SocketOptionName_DropMembership:
1164                 {
1165 #ifdef HAVE_STRUCT_IP_MREQN
1166                         struct ip_mreqn mreq;
1167 #else
1168                         struct ip_mreq mreq;
1169 #endif /* HAVE_STRUCT_IP_MREQN */
1170                         
1171                         /* pain! MulticastOption holds two IPAddress
1172                          * members, so I have to dig the value out of
1173                          * those :-(
1174                          */
1175                         field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
1176                         mreq.imr_multiaddr = ipaddress_to_struct_in_addr (*(gpointer *)(((char *)obj_val) +
1177                                                                                         field->offset));
1178                         field = mono_class_get_field_from_name (obj_val->vtable->klass, "local");
1179 #ifdef HAVE_STRUCT_IP_MREQN
1180                         mreq.imr_address = ipaddress_to_struct_in_addr (*(gpointer *)(((char *)obj_val) +
1181                                                                                       field->offset));
1182 #else
1183                         mreq.imr_interface = ipaddress_to_struct_in_addr (*(gpointer *)(((char *)obj_val) +
1184                                                                                         field->offset));
1185 #endif /* HAVE_STRUCT_IP_MREQN */
1186                         
1187                         ret = setsockopt (sock, system_level, system_name,
1188                                           &mreq, sizeof (mreq));
1189                         break;
1190                 }
1191                 default:
1192                         /* Throw an exception */
1193                         mono_raise_exception(get_socket_exception(WSAEINVAL));
1194                 }
1195         } else if (byte_val!=NULL) {
1196                 int valsize=mono_array_length(byte_val);
1197                 guchar *buf=mono_array_addr(byte_val, guchar, 0);
1198         
1199                 ret=setsockopt(sock, system_level, system_name, buf, valsize);
1200                 if(ret==SOCKET_ERROR) {
1201                         mono_raise_exception(get_socket_exception(WSAGetLastError()));
1202                 }
1203         } else {
1204                 ret=setsockopt(sock, system_level, system_name, &int_val,
1205                                sizeof(int_val));
1206         }
1207
1208         if(ret==SOCKET_ERROR) {
1209                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1210         }
1211 }
1212
1213 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock,
1214                                                            gint32 how)
1215 {
1216         int ret;
1217         
1218         /* Currently, the values for how (recv=0, send=1, both=2) match
1219          * the BSD API
1220          */
1221         ret=shutdown(sock, how);
1222         if(ret==SOCKET_ERROR) {
1223                 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1224         }
1225 }
1226
1227 static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
1228                                        MonoArray **h_aliases,
1229                                        MonoArray **h_addr_list)
1230 {
1231         MonoDomain *domain = mono_domain_get ();
1232         int i;
1233
1234         if(he->h_length!=4 || he->h_addrtype!=AF_INET) {
1235                 return(FALSE);
1236         }
1237
1238         *h_name=mono_string_new(domain, he->h_name);
1239
1240         i=0;
1241         while(he->h_aliases[i]!=NULL) {
1242                 i++;
1243         }
1244         
1245         *h_aliases=mono_array_new(domain, mono_defaults.string_class, i);
1246         i=0;
1247         while(he->h_aliases[i]!=NULL) {
1248                 MonoString *alias;
1249                 
1250                 alias=mono_string_new(domain, he->h_aliases[i]);
1251                 mono_array_set(*h_aliases, MonoString *, i, alias);
1252                 i++;
1253         }
1254
1255         i=0;
1256         while(he->h_addr_list[i]!=NULL) {
1257                 i++;
1258         }
1259         
1260         *h_addr_list=mono_array_new(domain, mono_defaults.string_class, i);
1261         i=0;
1262         while(he->h_addr_list[i]!=NULL) {
1263                 MonoString *addr_string;
1264                 char addr[16];
1265                 
1266                 g_snprintf(addr, 16, "%u.%u.%u.%u",
1267                          (unsigned char)he->h_addr_list[i][0],
1268                          (unsigned char)he->h_addr_list[i][1],
1269                          (unsigned char)he->h_addr_list[i][2],
1270                          (unsigned char)he->h_addr_list[i][3]);
1271                 
1272                 addr_string=mono_string_new(domain, addr);
1273                 mono_array_set(*h_addr_list, MonoString *, i, addr_string);
1274                 i++;
1275         }
1276
1277         return(TRUE);
1278 }
1279
1280 extern gboolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
1281 {
1282         char *hostname;
1283         struct hostent *he;
1284         
1285         hostname=mono_string_to_utf8(host);
1286         he=gethostbyname(hostname);
1287         g_free(hostname);
1288         
1289         if(he==NULL) {
1290                 return(FALSE);
1291         }
1292
1293         return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
1294 }
1295
1296 #ifndef HAVE_INET_PTON
1297 static int
1298 inet_pton (int family, const char *address, void *inaddrp)
1299 {
1300         if (family == AF_INET) {
1301 #ifdef HAVE_INET_ATON
1302                 struct in_addr inaddr;
1303                 
1304                 if (!inet_aton (address, &inaddr))
1305                         return 0;
1306                 
1307                 memcpy (inaddrp, &inaddr, sizeof (struct in_addr));
1308                 return 1;
1309 #else
1310                 /* assume the system has inet_addr(), if it doesn't
1311                    have that we're pretty much screwed... */
1312                 guint32 inaddr;
1313                 
1314                 if (!strcmp (address, "255.255.255.255")) {
1315                         /* special-case hack */
1316                         inaddr = 0xffffffff;
1317                 } else {
1318                         inaddr = inet_addr (address);
1319 #ifndef INADDR_NONE
1320 #define INADDR_NONE ((in_addr_t) -1)
1321 #endif
1322                         if (inaddr == INADDR_NONE)
1323                                 return 0;
1324                 }
1325                 
1326                 memcpy (inaddrp, &inaddr, sizeof (guint32));
1327                 return 1;
1328 #endif /* HAVE_INET_ATON */
1329         }
1330         
1331         return -1;
1332 }
1333 #endif /* !HAVE_INET_PTON */
1334
1335 extern gboolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
1336 {
1337         struct in_addr inaddr;
1338         struct hostent *he;
1339         char *address;
1340         
1341         address = mono_string_to_utf8 (addr);
1342         if (inet_pton (AF_INET, address, &inaddr) <= 0) {
1343                 g_free (address);
1344                 return FALSE;
1345         }
1346         
1347         g_free (address);
1348         if ((he = gethostbyaddr ((char *) &inaddr, sizeof (inaddr), AF_INET)) == NULL)
1349                 return FALSE;
1350         
1351         return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
1352 }
1353
1354 void mono_network_init(void)
1355 {
1356         WSADATA wsadata;
1357         int err;
1358         
1359         err=WSAStartup(MAKEWORD(2,0), &wsadata);
1360         if(err!=0) {
1361                 g_error(G_GNUC_PRETTY_FUNCTION ": Couldn't initialise networking");
1362                 exit(-1);
1363         }
1364
1365 #ifdef DEBUG
1366         g_message(G_GNUC_PRETTY_FUNCTION ": Using socket library: %s", wsadata.szDescription);
1367         g_message(G_GNUC_PRETTY_FUNCTION ": Socket system status: %s", wsadata.szSystemStatus);
1368 #endif
1369 }
1370
1371 void mono_network_cleanup(void)
1372 {
1373         WSACleanup();
1374 }