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);
219 static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level,
220 MonoSocketOptionName mono_name,
224 switch (mono_level) {
225 case SocketOptionLevel_Socket:
226 *system_level = SOL_SOCKET;
229 case SocketOptionName_DontLinger:
230 /* This is SO_LINGER, because the setsockopt
231 * internal call maps DontLinger to SO_LINGER
234 *system_name = SO_LINGER;
236 case SocketOptionName_Debug:
237 *system_name = SO_DEBUG;
240 case SocketOptionName_AcceptConnection:
241 *system_name = SO_ACCEPTCONN;
244 case SocketOptionName_ReuseAddress:
245 *system_name = SO_REUSEADDR;
247 case SocketOptionName_KeepAlive:
248 *system_name = SO_KEEPALIVE;
250 case SocketOptionName_DontRoute:
251 *system_name = SO_DONTROUTE;
253 case SocketOptionName_Broadcast:
254 *system_name = SO_BROADCAST;
256 case SocketOptionName_Linger:
257 *system_name = SO_LINGER;
259 case SocketOptionName_OutOfBandInline:
260 *system_name = SO_OOBINLINE;
262 case SocketOptionName_SendBuffer:
263 *system_name = SO_SNDBUF;
265 case SocketOptionName_ReceiveBuffer:
266 *system_name = SO_RCVBUF;
268 case SocketOptionName_SendLowWater:
269 *system_name = SO_SNDLOWAT;
271 case SocketOptionName_ReceiveLowWater:
272 *system_name = SO_RCVLOWAT;
274 case SocketOptionName_SendTimeout:
275 *system_name = SO_SNDTIMEO;
277 case SocketOptionName_ReceiveTimeout:
278 *system_name = SO_RCVTIMEO;
280 case SocketOptionName_Error:
281 *system_name = SO_ERROR;
283 case SocketOptionName_Type:
284 *system_name = SO_TYPE;
286 case SocketOptionName_ExclusiveAddressUse:
287 case SocketOptionName_UseLoopback:
288 case SocketOptionName_MaxConnections:
289 /* Can't figure out how to map these, so fall
293 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name);
298 case SocketOptionLevel_IP:
300 *system_level = SOL_IP;
303 static int cached = 0;
307 struct protoent *pent;
309 pent = getprotobyname ("IP");
310 proto = pent ? pent->p_proto : 0 /* 0 a good default value?? */;
314 *system_level = proto;
316 #endif /* HAVE_SOL_IP */
319 case SocketOptionName_IPOptions:
320 *system_name = IP_OPTIONS;
323 case SocketOptionName_HeaderIncluded:
324 *system_name = IP_HDRINCL;
328 case SocketOptionName_TypeOfService:
329 *system_name = IP_TOS;
333 case SocketOptionName_IpTimeToLive:
334 *system_name = IP_TTL;
337 case SocketOptionName_MulticastInterface:
338 *system_name = IP_MULTICAST_IF;
340 case SocketOptionName_MulticastTimeToLive:
341 *system_name = IP_MULTICAST_TTL;
343 case SocketOptionName_MulticastLoopback:
344 *system_name = IP_MULTICAST_LOOP;
346 case SocketOptionName_AddMembership:
347 *system_name = IP_ADD_MEMBERSHIP;
349 case SocketOptionName_DropMembership:
350 *system_name = IP_DROP_MEMBERSHIP;
352 #ifdef HAVE_IP_PKTINFO
353 case SocketOptionName_PacketInformation:
354 *system_name = IP_PKTINFO;
356 #endif /* HAVE_IP_PKTINFO */
357 case SocketOptionName_DontFragment:
358 case SocketOptionName_AddSourceMembership:
359 case SocketOptionName_DropSourceMembership:
360 case SocketOptionName_BlockSource:
361 case SocketOptionName_UnblockSource:
362 /* Can't figure out how to map these, so fall
366 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name);
371 case SocketOptionLevel_Tcp:
373 *system_level = SOL_TCP;
376 static int cached = 0;
380 struct protoent *pent;
382 pent = getprotobyname ("TCP");
383 proto = pent ? pent->p_proto : 6 /* is 6 a good default value?? */;
387 *system_level = proto;
389 #endif /* HAVE_SOL_TCP */
392 case SocketOptionName_NoDelay:
393 *system_name = TCP_NODELAY;
396 /* The documentation is talking complete
397 * bollocks here: rfc-1222 is titled
398 * 'Advancing the NSFNET Routing Architecture'
399 * and doesn't mention either of the words
400 * "expedite" or "urgent".
402 case SocketOptionName_BsdUrgent:
403 case SocketOptionName_Expedited:
406 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name);
411 case SocketOptionLevel_Udp:
412 g_warning("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level);
415 case SocketOptionName_NoChecksum:
416 case SocketOptionName_ChecksumCoverage:
418 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name);
425 g_warning("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level);
432 #define STASH_SYS_ASS(this) \
433 if(system_assembly == NULL) { \
434 system_assembly=this->vtable->klass->image; \
437 static MonoImage *system_assembly=NULL;
439 static MonoException *get_socket_exception(guint32 error_code)
441 /* Don't cache this exception, because we need the object
442 * constructor to set up the message from the sockets error code.
446 /* This is a bit of a kludge. The SocketException 0-arg
447 * constructor calls WSAGetLastError() to find the error code
448 * to use. Until we can init objects with parameters, this
451 WSASetLastError(error_code);
453 ex=(MonoException *)mono_exception_from_name(system_assembly,
454 "System.Net.Sockets",
459 gpointer ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject *this, gint32 family, gint32 type, gint32 proto)
470 sock_family=convert_family(family);
471 if(sock_family==-1) {
472 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
476 sock_proto=convert_proto(proto);
478 mono_raise_exception(get_socket_exception(WSAEPROTONOSUPPORT));
482 sock_type=convert_type(type);
484 mono_raise_exception(get_socket_exception(WSAESOCKTNOSUPPORT));
488 sock=socket(sock_family, sock_type, sock_proto);
489 if(sock==INVALID_SOCKET) {
490 mono_raise_exception(get_socket_exception(WSAGetLastError()));
494 /* .net seems to set this by default */
495 ret=setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof(true));
496 if(ret==SOCKET_ERROR) {
498 mono_raise_exception(get_socket_exception(WSAGetLastError()));
502 return(GUINT_TO_POINTER (sock));
505 /* FIXME: the SOCKET parameter (here and in other functions in this
506 * file) is really an IntPtr which needs to be converted to a guint32.
508 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock)
513 gint32 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
515 g_message(G_GNUC_PRETTY_FUNCTION ": returning %d", WSAGetLastError());
516 return(WSAGetLastError());
519 gint32 ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock)
523 ret=ioctlsocket(sock, FIONREAD, &amount);
524 if(ret==SOCKET_ERROR) {
525 mono_raise_exception(get_socket_exception(WSAGetLastError()));
532 void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock,
537 ret=ioctlsocket(sock, FIONBIO, &block);
538 if(ret==SOCKET_ERROR) {
539 mono_raise_exception(get_socket_exception(WSAGetLastError()));
543 gpointer ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock)
547 newsock=accept(sock, NULL, 0);
548 if(newsock==INVALID_SOCKET) {
549 mono_raise_exception(get_socket_exception(WSAGetLastError()));
553 return(GUINT_TO_POINTER (newsock));
556 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock,
561 ret=listen(sock, backlog);
562 if(ret==SOCKET_ERROR) {
563 mono_raise_exception(get_socket_exception(WSAGetLastError()));
567 static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr,
570 MonoDomain *domain = mono_domain_get ();
571 MonoObject *sockaddr_obj;
572 MonoClass *sockaddr_class;
573 MonoClassField *field;
575 MonoAddressFamily family;
577 /* Build a System.Net.SocketAddress object instance */
578 sockaddr_class=mono_class_from_name(system_assembly, "System.Net", "SocketAddress");
579 sockaddr_obj=mono_object_new(domain, sockaddr_class);
581 /* Locate the SocketAddress data buffer in the object */
582 field=mono_class_get_field_from_name(sockaddr_class, "data");
584 /* Make sure there is space for the family and size bytes */
585 data=mono_array_new(domain, mono_defaults.byte_class, sa_size+2);
587 /* The data buffer is laid out as follows:
588 * byte 0 is the address family
589 * byte 1 is the buffer length
590 * bytes 2 and 3 are the port info
591 * the rest is the address info
594 family=convert_to_mono_family(saddr->sa_family);
595 if(family==AddressFamily_Unknown) {
596 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
600 mono_array_set(data, guint8, 0, family);
601 mono_array_set(data, guint8, 1, sa_size+2);
603 if(saddr->sa_family==AF_INET) {
604 struct sockaddr_in *sa_in=(struct sockaddr_in *)saddr;
605 guint16 port=ntohs(sa_in->sin_port);
606 guint32 address=ntohl(sa_in->sin_addr.s_addr);
609 mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
612 mono_array_set(data, guint8, 2, (port>>8) & 0xff);
613 mono_array_set(data, guint8, 3, (port) & 0xff);
614 mono_array_set(data, guint8, 4, (address>>24) & 0xff);
615 mono_array_set(data, guint8, 5, (address>>16) & 0xff);
616 mono_array_set(data, guint8, 6, (address>>8) & 0xff);
617 mono_array_set(data, guint8, 7, (address) & 0xff);
619 *(MonoArray **)(((char *)sockaddr_obj) + field->offset)=data;
621 return(sockaddr_obj);
623 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
628 extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock)
634 salen=sizeof(struct sockaddr);
635 ret=getsockname(sock, &sa, &salen);
637 if(ret==SOCKET_ERROR) {
638 mono_raise_exception(get_socket_exception(WSAGetLastError()));
642 g_message(G_GNUC_PRETTY_FUNCTION ": bound to %s port %d", inet_ntoa((struct sockaddr_in)sa.sin_addr), ntohs((struct sockaddr_in)sa.sin_port));
645 return(create_object_from_sockaddr(&sa, salen));
648 extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock)
654 salen=sizeof(struct sockaddr);
655 ret=getpeername(sock, &sa, &salen);
657 if(ret==SOCKET_ERROR) {
658 mono_raise_exception(get_socket_exception(WSAGetLastError()));
662 g_message(G_GNUC_PRETTY_FUNCTION ": connected to %s port %d", inet_ntoa((struct sockaddr_in)sa.sin_addr), ntohs((struct sockaddr_in)sa.sin_port));
665 return(create_object_from_sockaddr(&sa, salen));
668 static struct sockaddr *create_sockaddr_from_object(MonoObject *saddr_obj,
671 MonoClassField *field;
676 /* Dig the SocketAddress data buffer out of the object */
677 field=mono_class_get_field_from_name(saddr_obj->vtable->klass, "data");
678 data=*(MonoArray **)(((char *)saddr_obj) + field->offset);
680 /* The data buffer is laid out as follows:
681 * byte 0 is the address family
682 * byte 1 is the buffer length
683 * bytes 2 and 3 are the port info
684 * the rest is the address info
686 len=mono_array_get(data, guint8, 1);
687 if((len<2) || (mono_array_length(data)!=len)) {
688 mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
691 family=convert_family(mono_array_get(data, guint8, 0));
692 if(family==AF_INET) {
693 struct sockaddr_in *sa=g_new0(struct sockaddr_in, 1);
694 guint16 port=(mono_array_get(data, guint8, 2) << 8) +
695 mono_array_get(data, guint8, 3);
696 guint32 address=(mono_array_get(data, guint8, 4) << 24) +
697 (mono_array_get(data, guint8, 5) << 16 ) +
698 (mono_array_get(data, guint8, 6) << 8) +
699 mono_array_get(data, guint8, 7);
701 sa->sin_family=family;
702 sa->sin_addr.s_addr=htonl(address);
703 sa->sin_port=htons(port);
705 *sa_size=sizeof(struct sockaddr_in);
706 return((struct sockaddr *)sa);
708 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
713 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock, MonoObject *sockaddr)
719 sa=create_sockaddr_from_object(sockaddr, &sa_size);
722 g_message(G_GNUC_PRETTY_FUNCTION ": binding to %s port %d", inet_ntoa(sa.sin_addr), port);
725 ret=bind(sock, sa, sa_size);
728 if(ret==SOCKET_ERROR) {
729 mono_raise_exception(get_socket_exception(WSAGetLastError()));
733 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock, MonoObject *sockaddr)
739 sa=create_sockaddr_from_object(sockaddr, &sa_size);
742 g_message(G_GNUC_PRETTY_FUNCTION ": connecting to %s port %d", inet_ntoa(sa.sin_addr), port);
745 ret=connect(sock, sa, sa_size);
748 if(ret==SOCKET_ERROR) {
749 mono_raise_exception(get_socket_exception(WSAGetLastError()));
753 gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags)
760 alen=mono_array_length(buffer);
761 if(offset+count>alen) {
765 buf=mono_array_addr(buffer, guchar, offset);
767 ret=recv(sock, buf, count, recvflags);
768 if(ret==SOCKET_ERROR) {
769 mono_raise_exception(get_socket_exception(WSAGetLastError()));
775 gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr)
784 alen=mono_array_length(buffer);
785 if(offset+count>alen) {
789 sa=create_sockaddr_from_object(*sockaddr, &sa_size);
791 buf=mono_array_addr(buffer, guchar, offset);
793 ret=recvfrom(sock, buf, count, recvflags, sa, &sa_size);
796 if(ret==SOCKET_ERROR) {
797 mono_raise_exception(get_socket_exception(WSAGetLastError()));
800 *sockaddr=create_object_from_sockaddr(sa, sa_size);
805 gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags)
812 alen=mono_array_length(buffer);
813 if(offset+count>alen) {
818 g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
821 buf=mono_array_addr(buffer, guchar, offset);
824 g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
827 ret=send(sock, buf, count, sendflags);
828 if(ret==SOCKET_ERROR) {
829 mono_raise_exception(get_socket_exception(WSAGetLastError()));
835 gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr)
844 alen=mono_array_length(buffer);
845 if(offset+count>alen) {
849 sa=create_sockaddr_from_object(sockaddr, &sa_size);
852 g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
855 buf=mono_array_addr(buffer, guchar, offset);
858 g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
861 ret=sendto(sock, buf, count, sendflags, sa, sa_size);
864 if(ret==SOCKET_ERROR) {
865 mono_raise_exception(get_socket_exception(WSAGetLastError()));
871 static SOCKET Socket_to_SOCKET(MonoObject *sockobj)
874 MonoClassField *field;
876 field=mono_class_get_field_from_name(sockobj->vtable->klass, "socket");
877 sock=*(SOCKET *)(((char *)sockobj)+field->offset);
882 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **read_socks, MonoArray **write_socks, MonoArray **err_socks, gint32 timeout)
884 fd_set readfds, writefds, errfds;
888 int readarrsize, writearrsize, errarrsize;
889 MonoDomain *domain=mono_domain_get();
890 MonoClass *sock_arr_class;
895 readarrsize=mono_array_length(*read_socks);
896 if(readarrsize>FD_SETSIZE) {
897 mono_raise_exception(get_socket_exception(WSAEFAULT));
902 for(i=0; i<readarrsize; i++) {
903 FD_SET(Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i)), &readfds);
906 writearrsize=mono_array_length(*write_socks);
907 if(writearrsize>FD_SETSIZE) {
908 mono_raise_exception(get_socket_exception(WSAEFAULT));
913 for(i=0; i<writearrsize; i++) {
914 FD_SET(Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i)), &writefds);
917 errarrsize=mono_array_length(*err_socks);
918 if(errarrsize>FD_SETSIZE) {
919 mono_raise_exception(get_socket_exception(WSAEFAULT));
924 for(i=0; i<errarrsize; i++) {
925 FD_SET(Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i)), &errfds);
928 /* Negative timeout meaning block until ready is only
929 * specified in Poll, not Select
932 divvy=div(timeout, 1000000);
933 tv.tv_sec=divvy.quot;
934 tv.tv_usec=divvy.rem*1000000;
936 ret=select(0, &readfds, &writefds, &errfds, &tv);
938 ret=select(0, &readfds, &writefds, &errfds, NULL);
941 if(ret==SOCKET_ERROR) {
942 mono_raise_exception(get_socket_exception(WSAGetLastError()));
946 sock_arr_class=((MonoObject *)*read_socks)->vtable->klass;
949 for(i=0; i<readarrsize; i++) {
950 if(FD_ISSET(Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i)), &readfds)) {
954 socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
956 for(i=0; i<readarrsize; i++) {
957 MonoObject *sock=mono_array_get(*read_socks, MonoObject *, i);
959 if(FD_ISSET(Socket_to_SOCKET(sock), &readfds)) {
960 mono_array_set(socks, MonoObject *, count, sock);
967 for(i=0; i<writearrsize; i++) {
968 if(FD_ISSET(Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i)), &writefds)) {
972 socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
974 for(i=0; i<writearrsize; i++) {
975 MonoObject *sock=mono_array_get(*write_socks, MonoObject *, i);
977 if(FD_ISSET(Socket_to_SOCKET(sock), &writefds)) {
978 mono_array_set(socks, MonoObject *, count, sock);
985 for(i=0; i<errarrsize; i++) {
986 if(FD_ISSET(Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i)), &errfds)) {
990 socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
992 for(i=0; i<errarrsize; i++) {
993 MonoObject *sock=mono_array_get(*err_socks, MonoObject *, i);
995 if(FD_ISSET(Socket_to_SOCKET(sock), &errfds)) {
996 mono_array_set(socks, MonoObject *, count, sock);
1003 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val)
1009 int valsize=sizeof(val);
1010 struct linger linger;
1011 int lingersize=sizeof(linger);
1012 MonoDomain *domain=mono_domain_get();
1014 MonoClass *obj_class;
1015 MonoClassField *field;
1017 ret=convert_sockopt_level_and_name(level, name, &system_level,
1020 mono_raise_exception(get_socket_exception(WSAENOPROTOOPT));
1024 /* No need to deal with MulticastOption names here, because
1025 * you cant getsockopt AddMembership or DropMembership (the
1026 * int getsockopt will error, causing an exception)
1029 case SocketOptionName_Linger:
1030 case SocketOptionName_DontLinger:
1031 ret=getsockopt(sock, system_level, system_name, &linger,
1036 ret=getsockopt(sock, system_level, system_name, &val,
1040 if(ret==SOCKET_ERROR) {
1041 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1046 case SocketOptionName_Linger:
1047 /* build a System.Net.Sockets.LingerOption */
1048 obj_class=mono_class_from_name(system_assembly,
1049 "System.Net.Sockets",
1051 obj=mono_object_new(domain, obj_class);
1053 /* Locate and set the fields "bool enabled" and "int
1056 field=mono_class_get_field_from_name(obj_class, "enabled");
1057 *(guint8 *)(((char *)obj)+field->offset)=linger.l_onoff;
1059 field=mono_class_get_field_from_name(obj_class, "seconds");
1060 *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
1064 case SocketOptionName_DontLinger:
1065 /* construct a bool int in val - true if linger is off */
1066 val=!linger.l_onoff;
1071 /* construct an Int32 object to hold val */
1072 obj=mono_object_new(domain, mono_defaults.int32_class);
1074 /* Locate and set the "value" field */
1075 field=mono_class_get_field_from_name(mono_defaults.int32_class,
1077 *(gint32 *)(((char *)obj)+field->offset)=val;
1083 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val)
1091 ret=convert_sockopt_level_and_name(level, name, &system_level,
1094 mono_raise_exception(get_socket_exception(WSAENOPROTOOPT));
1098 valsize=mono_array_length(*byte_val);
1099 buf=mono_array_addr(*byte_val, guchar, 0);
1101 ret=getsockopt(sock, system_level, system_name, buf, &valsize);
1102 if(ret==SOCKET_ERROR) {
1103 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1107 static struct in_addr ipaddress_to_struct_in_addr(MonoObject *ipaddr)
1109 struct in_addr inaddr;
1111 MonoClassField *field;
1113 field=mono_class_get_field_from_name(ipaddr->vtable->klass, "address");
1114 addr=*(guint64 *)(((char *)ipaddr)+field->offset);
1116 /* No idea why .net uses a 64bit type to hold a 32bit value */
1117 inaddr.s_addr=htonl((guint32)addr);
1122 void ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal(SOCKET sock, gint32 level, gint32 name, MonoObject *obj_val, MonoArray *byte_val, gint32 int_val)
1128 ret=convert_sockopt_level_and_name(level, name, &system_level,
1131 mono_raise_exception(get_socket_exception(WSAENOPROTOOPT));
1135 /* Only one of obj_val, byte_val or int_val has data */
1137 MonoClassField *field;
1138 struct linger linger;
1142 case SocketOptionName_DontLinger:
1145 valsize=sizeof(linger);
1146 ret=setsockopt(sock, system_level, system_name,
1150 case SocketOptionName_Linger:
1151 /* Dig out "bool enabled" and "int seconds"
1154 field=mono_class_get_field_from_name(obj_val->vtable->klass, "enabled");
1155 linger.l_onoff=*(guint8 *)(((char *)obj_val)+field->offset);
1156 field=mono_class_get_field_from_name(obj_val->vtable->klass, "seconds");
1157 linger.l_linger=*(guint32 *)(((char *)obj_val)+field->offset);
1159 valsize=sizeof(linger);
1160 ret=setsockopt(sock, system_level, system_name,
1163 case SocketOptionName_AddMembership:
1164 case SocketOptionName_DropMembership:
1166 #ifdef HAVE_STRUCT_IP_MREQN
1167 struct ip_mreqn mreq;
1169 struct ip_mreq mreq;
1170 #endif /* HAVE_STRUCT_IP_MREQN */
1172 /* pain! MulticastOption holds two IPAddress
1173 * members, so I have to dig the value out of
1176 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
1177 mreq.imr_multiaddr = ipaddress_to_struct_in_addr (*(gpointer *)(((char *)obj_val) +
1179 field = mono_class_get_field_from_name (obj_val->vtable->klass, "local");
1180 #ifdef HAVE_STRUCT_IP_MREQN
1181 mreq.imr_address = ipaddress_to_struct_in_addr (*(gpointer *)(((char *)obj_val) +
1184 mreq.imr_interface = ipaddress_to_struct_in_addr (*(gpointer *)(((char *)obj_val) +
1186 #endif /* HAVE_STRUCT_IP_MREQN */
1188 ret = setsockopt (sock, system_level, system_name,
1189 &mreq, sizeof (mreq));
1193 /* Throw an exception */
1194 mono_raise_exception(get_socket_exception(WSAEINVAL));
1196 } else if (byte_val!=NULL) {
1197 int valsize=mono_array_length(byte_val);
1198 guchar *buf=mono_array_addr(byte_val, guchar, 0);
1200 ret=setsockopt(sock, system_level, system_name, buf, valsize);
1201 if(ret==SOCKET_ERROR) {
1202 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1205 ret=setsockopt(sock, system_level, system_name, &int_val,
1209 if(ret==SOCKET_ERROR) {
1210 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1214 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock,
1219 /* Currently, the values for how (recv=0, send=1, both=2) match
1222 ret=shutdown(sock, how);
1223 if(ret==SOCKET_ERROR) {
1224 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1228 static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
1229 MonoArray **h_aliases,
1230 MonoArray **h_addr_list)
1232 MonoDomain *domain = mono_domain_get ();
1235 if(he->h_length!=4 || he->h_addrtype!=AF_INET) {
1239 *h_name=mono_string_new(domain, he->h_name);
1242 while(he->h_aliases[i]!=NULL) {
1246 *h_aliases=mono_array_new(domain, mono_defaults.string_class, i);
1248 while(he->h_aliases[i]!=NULL) {
1251 alias=mono_string_new(domain, he->h_aliases[i]);
1252 mono_array_set(*h_aliases, MonoString *, i, alias);
1257 while(he->h_addr_list[i]!=NULL) {
1261 *h_addr_list=mono_array_new(domain, mono_defaults.string_class, i);
1263 while(he->h_addr_list[i]!=NULL) {
1264 MonoString *addr_string;
1267 g_snprintf(addr, 16, "%u.%u.%u.%u",
1268 (unsigned char)he->h_addr_list[i][0],
1269 (unsigned char)he->h_addr_list[i][1],
1270 (unsigned char)he->h_addr_list[i][2],
1271 (unsigned char)he->h_addr_list[i][3]);
1273 addr_string=mono_string_new(domain, addr);
1274 mono_array_set(*h_addr_list, MonoString *, i, addr_string);
1281 extern gboolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
1286 hostname=mono_string_to_utf8(host);
1287 he=gethostbyname(hostname);
1294 return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
1297 #ifndef HAVE_INET_PTON
1299 inet_pton (int family, const char *address, void *inaddrp)
1301 if (family == AF_INET) {
1302 #ifdef HAVE_INET_ATON
1303 struct in_addr inaddr;
1305 if (!inet_aton (address, &inaddr))
1308 memcpy (inaddrp, &inaddr, sizeof (struct in_addr));
1311 /* assume the system has inet_addr(), if it doesn't
1312 have that we're pretty much screwed... */
1315 if (!strcmp (address, "255.255.255.255")) {
1316 /* special-case hack */
1317 inaddr = 0xffffffff;
1319 inaddr = inet_addr (address);
1321 #define INADDR_NONE ((in_addr_t) -1)
1323 if (inaddr == INADDR_NONE)
1327 memcpy (inaddrp, &inaddr, sizeof (guint32));
1329 #endif /* HAVE_INET_ATON */
1334 #endif /* !HAVE_INET_PTON */
1336 extern gboolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
1338 struct in_addr inaddr;
1342 address = mono_string_to_utf8 (addr);
1343 if (inet_pton (AF_INET, address, &inaddr) <= 0) {
1349 if ((he = gethostbyaddr ((char *) &inaddr, sizeof (inaddr), AF_INET)) == NULL)
1352 return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
1355 void mono_network_init(void)
1360 err=WSAStartup(MAKEWORD(2,0), &wsadata);
1362 g_error(G_GNUC_PRETTY_FUNCTION ": Couldn't initialise networking");
1367 g_message(G_GNUC_PRETTY_FUNCTION ": Using socket library: %s", wsadata.szDescription);
1368 g_message(G_GNUC_PRETTY_FUNCTION ": Socket system status: %s", wsadata.szSystemStatus);
1372 void mono_network_cleanup(void)