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 gpointer 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()));
501 return(GUINT_TO_POINTER (sock));
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.
507 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock)
512 gint32 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
514 g_message(G_GNUC_PRETTY_FUNCTION ": returning %d", WSAGetLastError());
515 return(WSAGetLastError());
518 gint32 ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock)
522 ret=ioctlsocket(sock, FIONREAD, &amount);
523 if(ret==SOCKET_ERROR) {
524 mono_raise_exception(get_socket_exception(WSAGetLastError()));
531 void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock,
536 ret=ioctlsocket(sock, FIONBIO, &block);
537 if(ret==SOCKET_ERROR) {
538 mono_raise_exception(get_socket_exception(WSAGetLastError()));
542 gpointer ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock)
546 newsock=accept(sock, NULL, 0);
547 if(newsock==INVALID_SOCKET) {
548 mono_raise_exception(get_socket_exception(WSAGetLastError()));
552 return(GUINT_TO_POINTER (newsock));
555 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock,
560 ret=listen(sock, backlog);
561 if(ret==SOCKET_ERROR) {
562 mono_raise_exception(get_socket_exception(WSAGetLastError()));
566 static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr,
569 MonoDomain *domain = mono_domain_get ();
570 MonoObject *sockaddr_obj;
571 MonoClass *sockaddr_class;
572 MonoClassField *field;
574 MonoAddressFamily family;
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);
580 /* Locate the SocketAddress data buffer in the object */
581 field=mono_class_get_field_from_name(sockaddr_class, "data");
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);
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
593 family=convert_to_mono_family(saddr->sa_family);
594 if(family==AddressFamily_Unknown) {
595 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
599 mono_array_set(data, guint8, 0, family);
600 mono_array_set(data, guint8, 1, sa_size+2);
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);
608 mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
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);
618 *(MonoArray **)(((char *)sockaddr_obj) + field->offset)=data;
620 return(sockaddr_obj);
622 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
627 extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock)
633 salen=sizeof(struct sockaddr);
634 ret=getsockname(sock, &sa, &salen);
636 if(ret==SOCKET_ERROR) {
637 mono_raise_exception(get_socket_exception(WSAGetLastError()));
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));
644 return(create_object_from_sockaddr(&sa, salen));
647 extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock)
653 salen=sizeof(struct sockaddr);
654 ret=getpeername(sock, &sa, &salen);
656 if(ret==SOCKET_ERROR) {
657 mono_raise_exception(get_socket_exception(WSAGetLastError()));
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));
664 return(create_object_from_sockaddr(&sa, salen));
667 static struct sockaddr *create_sockaddr_from_object(MonoObject *saddr_obj,
670 MonoClassField *field;
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);
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
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"));
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);
700 sa->sin_family=family;
701 sa->sin_addr.s_addr=htonl(address);
702 sa->sin_port=htons(port);
704 *sa_size=sizeof(struct sockaddr_in);
705 return((struct sockaddr *)sa);
707 mono_raise_exception(get_socket_exception(WSAEAFNOSUPPORT));
712 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock, MonoObject *sockaddr)
718 sa=create_sockaddr_from_object(sockaddr, &sa_size);
721 g_message(G_GNUC_PRETTY_FUNCTION ": binding to %s port %d", inet_ntoa(sa.sin_addr), port);
724 ret=bind(sock, sa, sa_size);
727 if(ret==SOCKET_ERROR) {
728 mono_raise_exception(get_socket_exception(WSAGetLastError()));
732 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock, MonoObject *sockaddr)
738 sa=create_sockaddr_from_object(sockaddr, &sa_size);
741 g_message(G_GNUC_PRETTY_FUNCTION ": connecting to %s port %d", inet_ntoa(sa.sin_addr), port);
744 ret=connect(sock, sa, sa_size);
747 if(ret==SOCKET_ERROR) {
748 mono_raise_exception(get_socket_exception(WSAGetLastError()));
752 gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags)
759 alen=mono_array_length(buffer);
760 if(offset+count>alen) {
764 buf=mono_array_addr(buffer, guchar, offset);
766 ret=recv(sock, buf, count, recvflags);
767 if(ret==SOCKET_ERROR) {
768 mono_raise_exception(get_socket_exception(WSAGetLastError()));
774 gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr)
783 alen=mono_array_length(buffer);
784 if(offset+count>alen) {
788 sa=create_sockaddr_from_object(*sockaddr, &sa_size);
790 buf=mono_array_addr(buffer, guchar, offset);
792 ret=recvfrom(sock, buf, count, recvflags, sa, &sa_size);
795 if(ret==SOCKET_ERROR) {
796 mono_raise_exception(get_socket_exception(WSAGetLastError()));
799 *sockaddr=create_object_from_sockaddr(sa, sa_size);
804 gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags)
811 alen=mono_array_length(buffer);
812 if(offset+count>alen) {
817 g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
820 buf=mono_array_addr(buffer, guchar, offset);
823 g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
826 ret=send(sock, buf, count, sendflags);
827 if(ret==SOCKET_ERROR) {
828 mono_raise_exception(get_socket_exception(WSAGetLastError()));
834 gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr)
843 alen=mono_array_length(buffer);
844 if(offset+count>alen) {
848 sa=create_sockaddr_from_object(sockaddr, &sa_size);
851 g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
854 buf=mono_array_addr(buffer, guchar, offset);
857 g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
860 ret=sendto(sock, buf, count, sendflags, sa, sa_size);
863 if(ret==SOCKET_ERROR) {
864 mono_raise_exception(get_socket_exception(WSAGetLastError()));
870 static SOCKET Socket_to_SOCKET(MonoObject *sockobj)
873 MonoClassField *field;
875 field=mono_class_get_field_from_name(sockobj->vtable->klass, "socket");
876 sock=*(SOCKET *)(((char *)sockobj)+field->offset);
881 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **read_socks, MonoArray **write_socks, MonoArray **err_socks, gint32 timeout)
883 fd_set readfds, writefds, errfds;
887 int readarrsize, writearrsize, errarrsize;
888 MonoDomain *domain=mono_domain_get();
889 MonoClass *sock_arr_class;
894 readarrsize=mono_array_length(*read_socks);
895 if(readarrsize>FD_SETSIZE) {
896 mono_raise_exception(get_socket_exception(WSAEFAULT));
901 for(i=0; i<readarrsize; i++) {
902 FD_SET(Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i)), &readfds);
905 writearrsize=mono_array_length(*write_socks);
906 if(writearrsize>FD_SETSIZE) {
907 mono_raise_exception(get_socket_exception(WSAEFAULT));
912 for(i=0; i<writearrsize; i++) {
913 FD_SET(Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i)), &writefds);
916 errarrsize=mono_array_length(*err_socks);
917 if(errarrsize>FD_SETSIZE) {
918 mono_raise_exception(get_socket_exception(WSAEFAULT));
923 for(i=0; i<errarrsize; i++) {
924 FD_SET(Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i)), &errfds);
927 /* Negative timeout meaning block until ready is only
928 * specified in Poll, not Select
931 divvy=div(timeout, 1000000);
932 tv.tv_sec=divvy.quot;
933 tv.tv_usec=divvy.rem*1000000;
935 ret=select(0, &readfds, &writefds, &errfds, &tv);
937 ret=select(0, &readfds, &writefds, &errfds, NULL);
940 if(ret==SOCKET_ERROR) {
941 mono_raise_exception(get_socket_exception(WSAGetLastError()));
945 sock_arr_class=((MonoObject *)*read_socks)->vtable->klass;
948 for(i=0; i<readarrsize; i++) {
949 if(FD_ISSET(Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i)), &readfds)) {
953 socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
955 for(i=0; i<readarrsize; i++) {
956 MonoObject *sock=mono_array_get(*read_socks, MonoObject *, i);
958 if(FD_ISSET(Socket_to_SOCKET(sock), &readfds)) {
959 mono_array_set(socks, MonoObject *, count, sock);
966 for(i=0; i<writearrsize; i++) {
967 if(FD_ISSET(Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i)), &writefds)) {
971 socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
973 for(i=0; i<writearrsize; i++) {
974 MonoObject *sock=mono_array_get(*write_socks, MonoObject *, i);
976 if(FD_ISSET(Socket_to_SOCKET(sock), &writefds)) {
977 mono_array_set(socks, MonoObject *, count, sock);
984 for(i=0; i<errarrsize; i++) {
985 if(FD_ISSET(Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i)), &errfds)) {
989 socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
991 for(i=0; i<errarrsize; i++) {
992 MonoObject *sock=mono_array_get(*err_socks, MonoObject *, i);
994 if(FD_ISSET(Socket_to_SOCKET(sock), &errfds)) {
995 mono_array_set(socks, MonoObject *, count, sock);
1002 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val)
1008 int valsize=sizeof(val);
1009 struct linger linger;
1010 int lingersize=sizeof(linger);
1011 MonoDomain *domain=mono_domain_get();
1013 MonoClass *obj_class;
1014 MonoClassField *field;
1016 ret=convert_sockopt_level_and_name(level, name, &system_level,
1019 mono_raise_exception(get_socket_exception(WSAENOPROTOOPT));
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)
1028 case SocketOptionName_Linger:
1029 case SocketOptionName_DontLinger:
1030 ret=getsockopt(sock, system_level, system_name, &linger,
1035 ret=getsockopt(sock, system_level, system_name, &val,
1039 if(ret==SOCKET_ERROR) {
1040 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1045 case SocketOptionName_Linger:
1046 /* build a System.Net.Sockets.LingerOption */
1047 obj_class=mono_class_from_name(system_assembly,
1048 "System.Net.Sockets",
1050 obj=mono_object_new(domain, obj_class);
1052 /* Locate and set the fields "bool enabled" and "int
1055 field=mono_class_get_field_from_name(obj_class, "enabled");
1056 *(guint8 *)(((char *)obj)+field->offset)=linger.l_onoff;
1058 field=mono_class_get_field_from_name(obj_class, "seconds");
1059 *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
1063 case SocketOptionName_DontLinger:
1064 /* construct a bool int in val - true if linger is off */
1065 val=!linger.l_onoff;
1070 /* construct an Int32 object to hold val */
1071 obj=mono_object_new(domain, mono_defaults.int32_class);
1073 /* Locate and set the "value" field */
1074 field=mono_class_get_field_from_name(mono_defaults.int32_class,
1076 *(gint32 *)(((char *)obj)+field->offset)=val;
1082 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val)
1090 ret=convert_sockopt_level_and_name(level, name, &system_level,
1093 mono_raise_exception(get_socket_exception(WSAENOPROTOOPT));
1097 valsize=mono_array_length(*byte_val);
1098 buf=mono_array_addr(*byte_val, guchar, 0);
1100 ret=getsockopt(sock, system_level, system_name, buf, &valsize);
1101 if(ret==SOCKET_ERROR) {
1102 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1106 static struct in_addr ipaddress_to_struct_in_addr(MonoObject *ipaddr)
1108 struct in_addr inaddr;
1110 MonoClassField *field;
1112 field=mono_class_get_field_from_name(ipaddr->vtable->klass, "address");
1113 addr=*(guint64 *)(((char *)ipaddr)+field->offset);
1115 /* No idea why .net uses a 64bit type to hold a 32bit value */
1116 inaddr.s_addr=htonl((guint32)addr);
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)
1127 ret=convert_sockopt_level_and_name(level, name, &system_level,
1130 mono_raise_exception(get_socket_exception(WSAENOPROTOOPT));
1134 /* Only one of obj_val, byte_val or int_val has data */
1136 MonoClassField *field;
1137 struct linger linger;
1141 case SocketOptionName_DontLinger:
1144 valsize=sizeof(linger);
1145 ret=setsockopt(sock, system_level, system_name,
1149 case SocketOptionName_Linger:
1150 /* Dig out "bool enabled" and "int seconds"
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);
1158 valsize=sizeof(linger);
1159 ret=setsockopt(sock, system_level, system_name,
1162 case SocketOptionName_AddMembership:
1163 case SocketOptionName_DropMembership:
1165 #ifdef HAVE_STRUCT_IP_MREQN
1166 struct ip_mreqn mreq;
1168 struct ip_mreq mreq;
1169 #endif /* HAVE_STRUCT_IP_MREQN */
1171 /* pain! MulticastOption holds two IPAddress
1172 * members, so I have to dig the value out of
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) +
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) +
1183 mreq.imr_interface = ipaddress_to_struct_in_addr (*(gpointer *)(((char *)obj_val) +
1185 #endif /* HAVE_STRUCT_IP_MREQN */
1187 ret = setsockopt (sock, system_level, system_name,
1188 &mreq, sizeof (mreq));
1192 /* Throw an exception */
1193 mono_raise_exception(get_socket_exception(WSAEINVAL));
1195 } else if (byte_val!=NULL) {
1196 int valsize=mono_array_length(byte_val);
1197 guchar *buf=mono_array_addr(byte_val, guchar, 0);
1199 ret=setsockopt(sock, system_level, system_name, buf, valsize);
1200 if(ret==SOCKET_ERROR) {
1201 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1204 ret=setsockopt(sock, system_level, system_name, &int_val,
1208 if(ret==SOCKET_ERROR) {
1209 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1213 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock,
1218 /* Currently, the values for how (recv=0, send=1, both=2) match
1221 ret=shutdown(sock, how);
1222 if(ret==SOCKET_ERROR) {
1223 mono_raise_exception(get_socket_exception(WSAGetLastError()));
1227 static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
1228 MonoArray **h_aliases,
1229 MonoArray **h_addr_list)
1231 MonoDomain *domain = mono_domain_get ();
1234 if(he->h_length!=4 || he->h_addrtype!=AF_INET) {
1238 *h_name=mono_string_new(domain, he->h_name);
1241 while(he->h_aliases[i]!=NULL) {
1245 *h_aliases=mono_array_new(domain, mono_defaults.string_class, i);
1247 while(he->h_aliases[i]!=NULL) {
1250 alias=mono_string_new(domain, he->h_aliases[i]);
1251 mono_array_set(*h_aliases, MonoString *, i, alias);
1256 while(he->h_addr_list[i]!=NULL) {
1260 *h_addr_list=mono_array_new(domain, mono_defaults.string_class, i);
1262 while(he->h_addr_list[i]!=NULL) {
1263 MonoString *addr_string;
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]);
1272 addr_string=mono_string_new(domain, addr);
1273 mono_array_set(*h_addr_list, MonoString *, i, addr_string);
1280 extern gboolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
1285 hostname=mono_string_to_utf8(host);
1286 he=gethostbyname(hostname);
1293 return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
1296 #ifndef HAVE_INET_PTON
1298 inet_pton (int family, const char *address, void *inaddrp)
1300 if (family == AF_INET) {
1301 #ifdef HAVE_INET_ATON
1302 struct in_addr inaddr;
1304 if (!inet_aton (address, &inaddr))
1307 memcpy (inaddrp, &inaddr, sizeof (struct in_addr));
1310 /* assume the system has inet_addr(), if it doesn't
1311 have that we're pretty much screwed... */
1314 if (!strcmp (address, "255.255.255.255")) {
1315 /* special-case hack */
1316 inaddr = 0xffffffff;
1318 inaddr = inet_addr (address);
1320 #define INADDR_NONE ((in_addr_t) -1)
1322 if (inaddr == INADDR_NONE)
1326 memcpy (inaddrp, &inaddr, sizeof (guint32));
1328 #endif /* HAVE_INET_ATON */
1333 #endif /* !HAVE_INET_PTON */
1335 extern gboolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
1337 struct in_addr inaddr;
1341 address = mono_string_to_utf8 (addr);
1342 if (inet_pton (AF_INET, address, &inaddr) <= 0) {
1348 if ((he = gethostbyaddr ((char *) &inaddr, sizeof (inaddr), AF_INET)) == NULL)
1351 return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
1354 void mono_network_init(void)
1359 err=WSAStartup(MAKEWORD(2,0), &wsadata);
1361 g_error(G_GNUC_PRETTY_FUNCTION ": Couldn't initialise networking");
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);
1371 void mono_network_cleanup(void)