2 * socket-io.c: Socket IO internal calls
5 * Dick Porter (dick@ximian.com)
7 * (C) 2001 Ximian, Inc.
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>
30 static gint32 convert_family(MonoAddressFamily 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);
57 case AddressFamily_Unspecified:
61 case AddressFamily_Unix:
65 case AddressFamily_InterNetwork:
69 case AddressFamily_Ipx:
73 case AddressFamily_Sna:
77 case AddressFamily_DecNet:
81 case AddressFamily_AppleTalk:
85 case AddressFamily_InterNetworkV6:
89 case AddressFamily_Irda:
94 g_warning("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family);
100 static MonoAddressFamily convert_to_mono_family(guint16 af_family)
102 MonoAddressFamily family=AddressFamily_Unknown;
106 family=AddressFamily_Unspecified;
110 family=AddressFamily_Unix;
114 family=AddressFamily_InterNetwork;
118 family=AddressFamily_Ipx;
122 family=AddressFamily_Sna;
126 family=AddressFamily_DecNet;
130 family=AddressFamily_AppleTalk;
134 family=AddressFamily_InterNetworkV6;
139 family=AddressFamily_Irda;
143 g_warning("unknown address family 0x%x", af_family);
149 static gint32 convert_type(MonoSocketType mono_type)
154 case SocketType_Stream:
158 case SocketType_Dgram:
170 case SocketType_Seqpacket:
174 case SocketType_Unknown:
175 g_warning("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type);
179 g_warning("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type);
185 static gint32 convert_proto(MonoProtocolType 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) */
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);
218 static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level,
219 MonoSocketOptionName mono_name,
223 switch (mono_level) {
224 case SocketOptionLevel_Socket:
225 *system_level = SOL_SOCKET;
228 case SocketOptionName_DontLinger:
229 /* This is SO_LINGER, because the setsockopt
230 * internal call maps DontLinger to SO_LINGER
233 *system_name = SO_LINGER;
235 case SocketOptionName_Debug:
236 *system_name = SO_DEBUG;
239 case SocketOptionName_AcceptConnection:
240 *system_name = SO_ACCEPTCONN;
243 case SocketOptionName_ReuseAddress:
244 *system_name = SO_REUSEADDR;
246 case SocketOptionName_KeepAlive:
247 *system_name = SO_KEEPALIVE;
249 case SocketOptionName_DontRoute:
250 *system_name = SO_DONTROUTE;
252 case SocketOptionName_Broadcast:
253 *system_name = SO_BROADCAST;
255 case SocketOptionName_Linger:
256 *system_name = SO_LINGER;
258 case SocketOptionName_OutOfBandInline:
259 *system_name = SO_OOBINLINE;
261 case SocketOptionName_SendBuffer:
262 *system_name = SO_SNDBUF;
264 case SocketOptionName_ReceiveBuffer:
265 *system_name = SO_RCVBUF;
267 case SocketOptionName_SendLowWater:
268 *system_name = SO_SNDLOWAT;
270 case SocketOptionName_ReceiveLowWater:
271 *system_name = SO_RCVLOWAT;
273 case SocketOptionName_SendTimeout:
274 *system_name = SO_SNDTIMEO;
276 case SocketOptionName_ReceiveTimeout:
277 *system_name = SO_RCVTIMEO;
279 case SocketOptionName_Error:
280 *system_name = SO_ERROR;
282 case SocketOptionName_Type:
283 *system_name = SO_TYPE;
285 case SocketOptionName_ExclusiveAddressUse:
286 case SocketOptionName_UseLoopback:
287 case SocketOptionName_MaxConnections:
288 /* Can't figure out how to map these, so fall
292 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name);
297 case SocketOptionLevel_IP:
299 *system_level = SOL_IP;
302 static int cached = 0;
306 struct protoent *pent;
308 pent = getprotobyname ("IP");
309 proto = pent ? pent->p_proto : 0 /* 0 a good default value?? */;
313 *system_level = proto;
315 #endif /* HAVE_SOL_IP */
318 case SocketOptionName_IPOptions:
319 *system_name = IP_OPTIONS;
322 case SocketOptionName_HeaderIncluded:
323 *system_name = IP_HDRINCL;
327 case SocketOptionName_TypeOfService:
328 *system_name = IP_TOS;
332 case SocketOptionName_IpTimeToLive:
333 *system_name = IP_TTL;
336 case SocketOptionName_MulticastInterface:
337 *system_name = IP_MULTICAST_IF;
339 case SocketOptionName_MulticastTimeToLive:
340 *system_name = IP_MULTICAST_TTL;
342 case SocketOptionName_MulticastLoopback:
343 *system_name = IP_MULTICAST_LOOP;
345 case SocketOptionName_AddMembership:
346 *system_name = IP_ADD_MEMBERSHIP;
348 case SocketOptionName_DropMembership:
349 *system_name = IP_DROP_MEMBERSHIP;
351 #ifdef HAVE_IP_PKTINFO
352 case SocketOptionName_PacketInformation:
353 *system_name = IP_PKTINFO;
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
365 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name);
370 case SocketOptionLevel_Tcp:
372 *system_level = SOL_TCP;
375 static int cached = 0;
379 struct protoent *pent;
381 pent = getprotobyname ("TCP");
382 proto = pent ? pent->p_proto : 6 /* is 6 a good default value?? */;
386 *system_level = proto;
388 #endif /* HAVE_SOL_TCP */
391 case SocketOptionName_NoDelay:
392 *system_name = TCP_NODELAY;
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".
401 case SocketOptionName_BsdUrgent:
402 case SocketOptionName_Expedited:
405 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name);
410 case SocketOptionLevel_Udp:
411 g_warning("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level);
414 case SocketOptionName_NoChecksum:
415 case SocketOptionName_ChecksumCoverage:
417 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name);
424 g_warning("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level);
431 #define STASH_SYS_ASS(this) \
432 if(system_assembly == NULL) { \
433 system_assembly=this->vtable->klass->image; \
436 static MonoImage *system_assembly=NULL;
438 static MonoException *get_socket_exception(guint32 error_code)
440 /* Don't cache this exception, because we need the object
441 * constructor to set up the message from the sockets error code.
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
450 WSASetLastError(error_code);
452 ex=(MonoException *)mono_exception_from_name(system_assembly,
453 "System.Net.Sockets",
458 SOCKET ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject *this, gint32 family, gint32 type, gint32 proto)
469 sock_family=convert_family(family);
470 if(sock_family==-1) {
471 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
475 sock_proto=convert_proto(proto);
477 mono_raise_exception(get_socket_exception(WSAEPROTONOSUPPORT));
481 sock_type=convert_type(type);
483 mono_raise_exception(get_socket_exception(WSAESOCKTNOSUPPORT));
487 sock=socket(sock_family, sock_type, sock_proto);
488 if(sock==INVALID_SOCKET) {
489 mono_raise_exception(get_socket_exception(WSAGetLastError()));
493 /* .net seems to set this by default */
494 ret=setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof(true));
495 if(ret==SOCKET_ERROR) {
497 mono_raise_exception(get_socket_exception(WSAGetLastError()));
504 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock)
509 gint32 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
511 g_message(G_GNUC_PRETTY_FUNCTION ": returning %d", WSAGetLastError());
512 return(WSAGetLastError());
515 gint32 ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock)
519 ret=ioctlsocket(sock, FIONREAD, &amount);
520 if(ret==SOCKET_ERROR) {
521 mono_raise_exception(get_socket_exception(WSAGetLastError()));
528 void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock,
533 ret=ioctlsocket(sock, FIONBIO, &block);
534 if(ret==SOCKET_ERROR) {
535 mono_raise_exception(get_socket_exception(WSAGetLastError()));
539 SOCKET ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock)
543 newsock=accept(sock, NULL, 0);
544 if(newsock==INVALID_SOCKET) {
545 mono_raise_exception(get_socket_exception(WSAGetLastError()));
552 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock,
557 ret=listen(sock, backlog);
558 if(ret==SOCKET_ERROR) {
559 mono_raise_exception(get_socket_exception(WSAGetLastError()));
563 static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr,
566 MonoDomain *domain = mono_domain_get ();
567 MonoObject *sockaddr_obj;
568 MonoClass *sockaddr_class;
569 MonoClassField *field;
571 MonoAddressFamily family;
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);
577 /* Locate the SocketAddress data buffer in the object */
578 field=mono_class_get_field_from_name(sockaddr_class, "data");
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);
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
590 family=convert_to_mono_family(saddr->sa_family);
591 if(family==AddressFamily_Unknown) {
592 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
596 mono_array_set(data, guint8, 0, family);
597 mono_array_set(data, guint8, 1, sa_size+2);
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);
605 mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
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);
615 *(MonoArray **)(((char *)sockaddr_obj) + field->offset)=data;
617 return(sockaddr_obj);
619 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
624 extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock)
630 salen=sizeof(struct sockaddr);
631 ret=getsockname(sock, &sa, &salen);
633 if(ret==SOCKET_ERROR) {
634 mono_raise_exception(get_socket_exception(WSAGetLastError()));
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));
641 return(create_object_from_sockaddr(&sa, salen));
644 extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock)
650 salen=sizeof(struct sockaddr);
651 ret=getpeername(sock, &sa, &salen);
653 if(ret==SOCKET_ERROR) {
654 mono_raise_exception(get_socket_exception(WSAGetLastError()));
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));
661 return(create_object_from_sockaddr(&sa, salen));
664 static struct sockaddr *create_sockaddr_from_object(MonoObject *saddr_obj,
667 MonoClassField *field;
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);
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
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"));
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);
697 sa->sin_family=family;
698 sa->sin_addr.s_addr=htonl(address);
699 sa->sin_port=htons(port);
701 *sa_size=sizeof(struct sockaddr_in);
702 return((struct sockaddr *)sa);
704 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
709 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock, MonoObject *sockaddr)
715 sa=create_sockaddr_from_object(sockaddr, &sa_size);
718 g_message(G_GNUC_PRETTY_FUNCTION ": binding to %s port %d", inet_ntoa(sa.sin_addr), port);
721 ret=bind(sock, sa, sa_size);
724 if(ret==SOCKET_ERROR) {
725 mono_raise_exception(get_socket_exception(WSAGetLastError()));
729 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock, MonoObject *sockaddr)
735 sa=create_sockaddr_from_object(sockaddr, &sa_size);
738 g_message(G_GNUC_PRETTY_FUNCTION ": connecting to %s port %d", inet_ntoa(sa.sin_addr), port);
741 ret=connect(sock, sa, sa_size);
744 if(ret==SOCKET_ERROR) {
745 mono_raise_exception(get_socket_exception(WSAGetLastError()));
749 gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags)
756 alen=mono_array_length(buffer);
757 if(offset+count>alen) {
761 buf=mono_array_addr(buffer, guchar, offset);
763 ret=recv(sock, buf, count, recvflags);
764 if(ret==SOCKET_ERROR) {
765 mono_raise_exception(get_socket_exception(WSAGetLastError()));
771 gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr)
780 alen=mono_array_length(buffer);
781 if(offset+count>alen) {
785 sa=create_sockaddr_from_object(*sockaddr, &sa_size);
787 buf=mono_array_addr(buffer, guchar, offset);
789 ret=recvfrom(sock, buf, count, recvflags, sa, &sa_size);
792 if(ret==SOCKET_ERROR) {
793 mono_raise_exception(get_socket_exception(WSAGetLastError()));
796 *sockaddr=create_object_from_sockaddr(sa, sa_size);
801 gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags)
808 alen=mono_array_length(buffer);
809 if(offset+count>alen) {
814 g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
817 buf=mono_array_addr(buffer, guchar, offset);
820 g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
823 ret=send(sock, buf, count, sendflags);
824 if(ret==SOCKET_ERROR) {
825 mono_raise_exception(get_socket_exception(WSAGetLastError()));
831 gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr)
840 alen=mono_array_length(buffer);
841 if(offset+count>alen) {
845 sa=create_sockaddr_from_object(sockaddr, &sa_size);
848 g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
851 buf=mono_array_addr(buffer, guchar, offset);
854 g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
857 ret=sendto(sock, buf, count, sendflags, sa, sa_size);
860 if(ret==SOCKET_ERROR) {
861 mono_raise_exception(get_socket_exception(WSAGetLastError()));
867 static SOCKET Socket_to_SOCKET(MonoObject *sockobj)
870 MonoClassField *field;
872 field=mono_class_get_field_from_name(sockobj->vtable->klass, "socket");
873 sock=*(SOCKET *)(((char *)sockobj)+field->offset);
878 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **read_socks, MonoArray **write_socks, MonoArray **err_socks, gint32 timeout)
880 fd_set readfds, writefds, errfds;
884 int readarrsize, writearrsize, errarrsize;
885 MonoDomain *domain=mono_domain_get();
886 MonoClass *sock_arr_class;
891 readarrsize=mono_array_length(*read_socks);
892 if(readarrsize>FD_SETSIZE) {
893 mono_raise_exception(get_socket_exception(WSAEFAULT));
898 for(i=0; i<readarrsize; i++) {
899 FD_SET(Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i)), &readfds);
902 writearrsize=mono_array_length(*write_socks);
903 if(writearrsize>FD_SETSIZE) {
904 mono_raise_exception(get_socket_exception(WSAEFAULT));
909 for(i=0; i<writearrsize; i++) {
910 FD_SET(Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i)), &writefds);
913 errarrsize=mono_array_length(*err_socks);
914 if(errarrsize>FD_SETSIZE) {
915 mono_raise_exception(get_socket_exception(WSAEFAULT));
920 for(i=0; i<errarrsize; i++) {
921 FD_SET(Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i)), &errfds);
924 /* Negative timeout meaning block until ready is only
925 * specified in Poll, not Select
928 divvy=div(timeout, 1000000);
929 tv.tv_sec=divvy.quot;
930 tv.tv_usec=divvy.rem*1000000;
932 ret=select(0, &readfds, &writefds, &errfds, &tv);
934 ret=select(0, &readfds, &writefds, &errfds, NULL);
937 if(ret==SOCKET_ERROR) {
938 mono_raise_exception(get_socket_exception(WSAGetLastError()));
942 sock_arr_class=((MonoObject *)*read_socks)->vtable->klass;
945 for(i=0; i<readarrsize; i++) {
946 if(FD_ISSET(Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i)), &readfds)) {
950 socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
952 for(i=0; i<readarrsize; i++) {
953 MonoObject *sock=mono_array_get(*read_socks, MonoObject *, i);
955 if(FD_ISSET(Socket_to_SOCKET(sock), &readfds)) {
956 mono_array_set(socks, MonoObject *, count, sock);
963 for(i=0; i<writearrsize; i++) {
964 if(FD_ISSET(Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i)), &writefds)) {
968 socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
970 for(i=0; i<writearrsize; i++) {
971 MonoObject *sock=mono_array_get(*write_socks, MonoObject *, i);
973 if(FD_ISSET(Socket_to_SOCKET(sock), &writefds)) {
974 mono_array_set(socks, MonoObject *, count, sock);
981 for(i=0; i<errarrsize; i++) {
982 if(FD_ISSET(Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i)), &errfds)) {
986 socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
988 for(i=0; i<errarrsize; i++) {
989 MonoObject *sock=mono_array_get(*err_socks, MonoObject *, i);
991 if(FD_ISSET(Socket_to_SOCKET(sock), &errfds)) {
992 mono_array_set(socks, MonoObject *, count, sock);
999 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val)
1005 int valsize=sizeof(val);
1006 struct linger linger;
1007 int lingersize=sizeof(linger);
1008 MonoDomain *domain=mono_domain_get();
1010 MonoClass *obj_class;
1011 MonoClassField *field;
1013 ret=convert_sockopt_level_and_name(level, name, &system_level,
1016 mono_raise_exception(get_socket_exception(WSAENOPROTOOPT));
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)
1025 case SocketOptionName_Linger:
1026 case SocketOptionName_DontLinger:
1027 ret=getsockopt(sock, system_level, system_name, &linger,
1032 ret=getsockopt(sock, system_level, system_name, &val,
1036 if(ret==SOCKET_ERROR) {
1037 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1042 case SocketOptionName_Linger:
1043 /* build a System.Net.Sockets.LingerOption */
1044 obj_class=mono_class_from_name(system_assembly,
1045 "System.Net.Sockets",
1047 obj=mono_object_new(domain, obj_class);
1049 /* Locate and set the fields "bool enabled" and "int
1052 field=mono_class_get_field_from_name(obj_class, "enabled");
1053 *(guint8 *)(((char *)obj)+field->offset)=linger.l_onoff;
1055 field=mono_class_get_field_from_name(obj_class, "seconds");
1056 *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
1060 case SocketOptionName_DontLinger:
1061 /* construct a bool int in val - true if linger is off */
1062 val=!linger.l_onoff;
1067 /* construct an Int32 object to hold val */
1068 obj=mono_object_new(domain, mono_defaults.int32_class);
1070 /* Locate and set the "value" field */
1071 field=mono_class_get_field_from_name(mono_defaults.int32_class,
1073 *(gint32 *)(((char *)obj)+field->offset)=val;
1079 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val)
1087 ret=convert_sockopt_level_and_name(level, name, &system_level,
1090 mono_raise_exception(get_socket_exception(WSAENOPROTOOPT));
1094 valsize=mono_array_length(*byte_val);
1095 buf=mono_array_addr(*byte_val, guchar, 0);
1097 ret=getsockopt(sock, system_level, system_name, buf, &valsize);
1098 if(ret==SOCKET_ERROR) {
1099 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1103 static struct in_addr ipaddress_to_struct_in_addr(MonoObject *ipaddr)
1105 struct in_addr inaddr;
1107 MonoClassField *field;
1109 field=mono_class_get_field_from_name(ipaddr->vtable->klass, "address");
1110 addr=*(guint64 *)(((char *)ipaddr)+field->offset);
1112 /* No idea why .net uses a 64bit type to hold a 32bit value */
1113 inaddr.s_addr=htonl((guint32)addr);
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)
1124 ret=convert_sockopt_level_and_name(level, name, &system_level,
1127 mono_raise_exception(get_socket_exception(WSAENOPROTOOPT));
1131 /* Only one of obj_val, byte_val or int_val has data */
1133 MonoClassField *field;
1134 struct linger linger;
1138 case SocketOptionName_DontLinger:
1141 valsize=sizeof(linger);
1142 ret=setsockopt(sock, system_level, system_name,
1146 case SocketOptionName_Linger:
1147 /* Dig out "bool enabled" and "int seconds"
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);
1155 valsize=sizeof(linger);
1156 ret=setsockopt(sock, system_level, system_name,
1159 case SocketOptionName_AddMembership:
1160 case SocketOptionName_DropMembership:
1162 #ifdef HAVE_STRUCT_IP_MREQN
1163 struct ip_mreqn mreq;
1165 struct ip_mreq mreq;
1166 #endif /* HAVE_STRUCT_IP_MREQN */
1168 /* pain! MulticastOption holds two IPAddress
1169 * members, so I have to dig the value out of
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) +
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) +
1180 mreq.imr_interface = ipaddress_to_struct_in_addr (*(gpointer *)(((char *)obj_val) +
1182 #endif /* HAVE_STRUCT_IP_MREQN */
1184 ret = setsockopt (sock, system_level, system_name,
1185 &mreq, sizeof (mreq));
1189 /* Throw an exception */
1190 mono_raise_exception(get_socket_exception(WSAEINVAL));
1192 } else if (byte_val!=NULL) {
1193 int valsize=mono_array_length(byte_val);
1194 guchar *buf=mono_array_addr(byte_val, guchar, 0);
1196 ret=setsockopt(sock, system_level, system_name, buf, valsize);
1197 if(ret==SOCKET_ERROR) {
1198 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1201 ret=setsockopt(sock, system_level, system_name, &int_val,
1205 if(ret==SOCKET_ERROR) {
1206 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1210 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock,
1215 /* Currently, the values for how (recv=0, send=1, both=2) match
1218 ret=shutdown(sock, how);
1219 if(ret==SOCKET_ERROR) {
1220 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1224 static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
1225 MonoArray **h_aliases,
1226 MonoArray **h_addr_list)
1228 MonoDomain *domain = mono_domain_get ();
1231 if(he->h_length!=4 || he->h_addrtype!=AF_INET) {
1235 *h_name=mono_string_new(domain, he->h_name);
1238 while(he->h_aliases[i]!=NULL) {
1242 *h_aliases=mono_array_new(domain, mono_defaults.string_class, i);
1244 while(he->h_aliases[i]!=NULL) {
1247 alias=mono_string_new(domain, he->h_aliases[i]);
1248 mono_array_set(*h_aliases, MonoString *, i, alias);
1253 while(he->h_addr_list[i]!=NULL) {
1257 *h_addr_list=mono_array_new(domain, mono_defaults.string_class, i);
1259 while(he->h_addr_list[i]!=NULL) {
1260 MonoString *addr_string;
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]);
1269 addr_string=mono_string_new(domain, addr);
1270 mono_array_set(*h_addr_list, MonoString *, i, addr_string);
1277 extern gboolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
1282 hostname=mono_string_to_utf8(host);
1283 he=gethostbyname(hostname);
1290 return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
1293 #ifndef HAVE_INET_PTON
1295 inet_pton (int family, const char *address, void *inaddrp)
1297 if (family == AF_INET) {
1298 #ifdef HAVE_INET_ATON
1299 struct in_addr inaddr;
1301 if (!inet_aton (address, &inaddr))
1304 memcpy (inaddrp, &inaddr, sizeof (struct in_addr));
1307 /* assume the system has inet_addr(), if it doesn't
1308 have that we're pretty much screwed... */
1311 if (!strcmp (address, "255.255.255.255")) {
1312 /* special-case hack */
1313 inaddr = 0xffffffff;
1315 inaddr = inet_addr (address);
1317 #define INADDR_NONE ((in_addr_t) -1)
1319 if (inaddr == INADDR_NONE)
1323 memcpy (inaddrp, &inaddr, sizeof (guint32));
1325 #endif /* HAVE_INET_ATON */
1330 #endif /* !HAVE_INET_PTON */
1332 extern gboolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
1334 struct in_addr inaddr;
1338 address = mono_string_to_utf8 (addr);
1339 if (inet_pton (AF_INET, address, &inaddr) <= 0) {
1345 if ((he = gethostbyaddr ((char *) &inaddr, sizeof (inaddr), AF_INET)) == NULL)
1348 return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
1351 void mono_network_init(void)
1356 err=WSAStartup(MAKEWORD(2,0), &wsadata);
1358 g_error(G_GNUC_PRETTY_FUNCTION ": Couldn't initialise networking");
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);
1368 void mono_network_cleanup(void)