1 /* Copyright (C) 2003, 2005, 2006 Free Software Foundation
3 This file is part of libgcj.
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
12 #ifdef HAVE_NETINET_IN_H
13 #include <netinet/in.h>
15 #ifdef HAVE_ARPA_INET_H
16 #include <arpa/inet.h>
22 // Needed for bzero, implicitly used by FD_ZERO on IRIX 5.2
27 #include <gnu/java/net/PlainDatagramSocketImpl.h>
28 #include <java/io/IOException.h>
29 #include <java/io/InterruptedIOException.h>
30 #include <java/net/BindException.h>
31 #include <java/net/SocketException.h>
32 #include <java/net/SocketTimeoutException.h>
33 #include <java/net/InetAddress.h>
34 #include <java/net/NetworkInterface.h>
35 #include <java/net/DatagramPacket.h>
36 #include <java/net/PortUnreachableException.h>
37 #include <java/lang/InternalError.h>
38 #include <java/lang/Object.h>
39 #include <java/lang/Boolean.h>
40 #include <java/lang/Integer.h>
41 #include <java/net/UnknownHostException.h>
42 #include <java/net/ConnectException.h>
43 #include <java/lang/NullPointerException.h>
47 struct sockaddr_in address;
49 struct sockaddr_in6 address6;
55 #if HAVE_STRUCT_IP_MREQ
58 #if HAVE_STRUCT_IPV6_MREQ
59 struct ipv6_mreq mreq6;
67 struct in6_addr addr6;
72 // FIXME: routines here and/or in natPlainSocketImpl.cc could throw
73 // NoRouteToHostException; also consider UnknownHostException, ConnectException.
76 gnu::java::net::PlainDatagramSocketImpl::create ()
78 int sock = _Jv_socket (AF_INET, SOCK_DGRAM, 0);
82 char* strerr = strerror (errno);
83 throw new ::java::net::SocketException (JvNewStringUTF (strerr));
86 // We use native_fd in place of fd here. From leaving fd null we avoid
87 // the double close problem in FileDescriptor.finalize.
92 gnu::java::net::PlainDatagramSocketImpl::bind (jint lport,
93 ::java::net::InetAddress *host)
96 struct sockaddr *ptr = (struct sockaddr *) &u.address;
97 // FIXME: Use getaddrinfo() to get actual protocol instead of assuming ipv4.
98 jbyteArray haddress = host->addr;
99 jbyte *bytes = elements (haddress);
100 int len = haddress->length;
104 u.address.sin_family = AF_INET;
107 memcpy (&u.address.sin_addr, bytes, len);
109 u.address.sin_addr.s_addr = htonl (INADDR_ANY);
111 len = sizeof (struct sockaddr_in);
112 u.address.sin_port = htons (lport);
117 u.address6.sin6_family = AF_INET6;
118 memcpy (&u.address6.sin6_addr, bytes, len);
119 len = sizeof (struct sockaddr_in6);
120 u.address6.sin6_port = htons (lport);
124 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
126 if (_Jv_bind (native_fd, ptr, len) == 0)
128 socklen_t addrlen = sizeof(u);
132 else if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) == 0)
133 localPort = ntohs (u.address.sin_port);
137 /* Allow broadcast by default. */
139 if (::setsockopt (native_fd, SOL_SOCKET, SO_BROADCAST, (char *) &broadcast,
140 sizeof (broadcast)) != 0)
147 char* strerr = strerror (errno);
148 throw new ::java::net::BindException (JvNewStringUTF (strerr));
152 gnu::java::net::PlainDatagramSocketImpl::connect (::java::net::InetAddress *host,
156 throw new ::java::lang::NullPointerException;
159 jbyteArray haddress = host->addr;
160 jbyte *bytes = elements (haddress);
161 int len = haddress->length;
162 struct sockaddr *ptr = (struct sockaddr *) &u.address;
165 u.address.sin_family = AF_INET;
166 memcpy (&u.address.sin_addr, bytes, len);
167 len = sizeof (struct sockaddr_in);
168 u.address.sin_port = htons (rport);
173 u.address6.sin6_family = AF_INET6;
174 memcpy (&u.address6.sin6_addr, bytes, len);
175 len = sizeof (struct sockaddr_in6);
176 u.address6.sin6_port = htons (rport);
180 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
182 if (_Jv_connect (native_fd, ptr, len) == 0)
184 char* strerr = strerror (errno);
185 throw new ::java::net::ConnectException (JvNewStringUTF (strerr));
189 gnu::java::net::PlainDatagramSocketImpl::disconnect ()
191 struct sockaddr addr;
192 addr.sa_family = AF_UNSPEC;
193 // Ignore errors. This is lame but apparently required.
194 _Jv_connect (native_fd, &addr, sizeof (addr));
198 gnu::java::net::PlainDatagramSocketImpl::peek (::java::net::InetAddress *i)
200 // FIXME: Deal with Multicast and if the socket is connected.
202 socklen_t addrlen = sizeof(u);
204 ::recvfrom (native_fd, (char *) NULL, 0, MSG_PEEK, (sockaddr*) &u,
208 // FIXME: Deal with Multicast addressing and if the socket is connected.
211 if (u.address.sin_family == AF_INET)
213 raddr = JvNewByteArray (4);
214 memcpy (elements (raddr), &u.address.sin_addr, 4);
215 rport = ntohs (u.address.sin_port);
218 else if (u.address.sin_family == AF_INET6)
220 raddr = JvNewByteArray (16);
221 memcpy (elements (raddr), &u.address6.sin6_addr, 16);
222 rport = ntohs (u.address6.sin6_port);
226 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
231 char* strerr = strerror (errno);
233 if (errno == ECONNREFUSED)
234 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
236 throw new ::java::io::IOException (JvNewStringUTF (strerr));
240 gnu::java::net::PlainDatagramSocketImpl::peekData (::java::net::DatagramPacket *p)
242 // FIXME: Deal with Multicast and if the socket is connected.
244 socklen_t addrlen = sizeof(u);
245 jbyte *dbytes = elements (p->getData()) + p->getOffset();
246 jint maxlen = p->maxlen - p->getOffset();
249 // Do timeouts via select since SO_RCVTIMEO is not always available.
250 if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE)
255 FD_SET(native_fd, &rset);
256 tv.tv_sec = timeout / 1000;
257 tv.tv_usec = (timeout % 1000) * 1000;
259 if ((retval = _Jv_select (native_fd + 1, &rset, NULL, NULL, &tv)) < 0)
261 else if (retval == 0)
262 throw new ::java::net::SocketTimeoutException
263 (JvNewStringUTF ("PeekData timed out") );
267 ::recvfrom (native_fd, (char *) dbytes, maxlen, MSG_PEEK, (sockaddr*) &u,
271 // FIXME: Deal with Multicast addressing and if the socket is connected.
274 if (u.address.sin_family == AF_INET)
276 raddr = JvNewByteArray (4);
277 memcpy (elements (raddr), &u.address.sin_addr, 4);
278 rport = ntohs (u.address.sin_port);
281 else if (u.address.sin_family == AF_INET6)
283 raddr = JvNewByteArray (16);
284 memcpy (elements (raddr), &u.address6.sin6_addr, 16);
285 rport = ntohs (u.address6.sin6_port);
289 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
291 p->setAddress (::java::net::InetAddress::getByAddress (raddr));
293 p->length = (int) retlen;
297 char* strerr = strerror (errno);
299 if (errno == ECONNREFUSED)
300 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
302 throw new ::java::io::IOException (JvNewStringUTF (strerr));
305 // Close(shutdown) the socket.
307 gnu::java::net::PlainDatagramSocketImpl::close ()
309 // Avoid races from asynchronous finalization.
310 JvSynchronize sync (this);
312 // The method isn't declared to throw anything, so we disregard
314 _Jv_close (native_fd);
320 gnu::java::net::PlainDatagramSocketImpl::send (::java::net::DatagramPacket *p)
322 JvSynchronize lock (SEND_LOCK);
324 // FIXME: Deal with Multicast.
326 ::java::net::InetAddress *host = p->getAddress();
329 // If there is no host, maybe this socket was connected, in
330 // which case we try a plain send().
331 jbyte *dbytes = elements (p->getData()) + p->getOffset();
332 if (::send (native_fd, (char *) dbytes, p->getLength(), 0) >= 0)
337 jint rport = p->getPort();
340 jbyteArray haddress = host->addr;
341 jbyte *bytes = elements (haddress);
342 int len = haddress->length;
343 struct sockaddr *ptr = (struct sockaddr *) &u.address;
344 jbyte *dbytes = elements (p->getData()) + p->getOffset();
347 u.address.sin_family = AF_INET;
348 memcpy (&u.address.sin_addr, bytes, len);
349 len = sizeof (struct sockaddr_in);
350 u.address.sin_port = htons (rport);
355 u.address6.sin6_family = AF_INET6;
356 memcpy (&u.address6.sin6_addr, bytes, len);
357 len = sizeof (struct sockaddr_in6);
358 u.address6.sin6_port = htons (rport);
362 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
364 if (::sendto (native_fd, (char *) dbytes, p->getLength(), 0, ptr, len)
369 char* strerr = strerror (errno);
371 if (errno == ECONNREFUSED)
372 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
374 throw new ::java::io::IOException (JvNewStringUTF (strerr));
378 gnu::java::net::PlainDatagramSocketImpl::receive (::java::net::DatagramPacket *p)
380 JvSynchronize lock (RECEIVE_LOCK);
382 // FIXME: Deal with Multicast and if the socket is connected.
384 socklen_t addrlen = sizeof(u);
385 jbyte *dbytes = elements (p->getData()) + p->getOffset();
386 jint maxlen = p->maxlen - p->getOffset();
389 // Do timeouts via select since SO_RCVTIMEO is not always available.
390 if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE)
395 FD_SET(native_fd, &rset);
396 tv.tv_sec = timeout / 1000;
397 tv.tv_usec = (timeout % 1000) * 1000;
399 if ((retval = _Jv_select (native_fd + 1, &rset, NULL, NULL, &tv)) < 0)
401 else if (retval == 0)
402 throw new ::java::net::SocketTimeoutException
403 (JvNewStringUTF ("Receive timed out") );
407 ::recvfrom (native_fd, (char *) dbytes, maxlen, 0, (sockaddr*) &u,
411 // FIXME: Deal with Multicast addressing and if the socket is connected.
414 if (u.address.sin_family == AF_INET)
416 raddr = JvNewByteArray (4);
417 memcpy (elements (raddr), &u.address.sin_addr, 4);
418 rport = ntohs (u.address.sin_port);
421 else if (u.address.sin_family == AF_INET6)
423 raddr = JvNewByteArray (16);
424 memcpy (elements (raddr), &u.address6.sin6_addr, 16);
425 rport = ntohs (u.address6.sin6_port);
429 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
431 p->setAddress (::java::net::InetAddress::getByAddress (raddr));
433 p->length = (jint) retlen;
437 char* strerr = strerror (errno);
439 if (errno == ECONNREFUSED)
440 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
442 throw new ::java::io::IOException (JvNewStringUTF (strerr));
446 gnu::java::net::PlainDatagramSocketImpl::setTimeToLive (jint ttl)
448 // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
449 char val = (char) ttl;
450 socklen_t val_len = sizeof(val);
452 if (::setsockopt (native_fd, IPPROTO_IP, IP_MULTICAST_TTL, &val, val_len) == 0)
455 char* strerr = strerror (errno);
456 throw new ::java::io::IOException (JvNewStringUTF (strerr));
460 gnu::java::net::PlainDatagramSocketImpl::getTimeToLive ()
462 // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
464 socklen_t val_len = sizeof(val);
466 if (::getsockopt (native_fd, IPPROTO_IP, IP_MULTICAST_TTL, &val, &val_len) == 0)
467 return ((int) val) & 0xFF;
469 char* strerr = strerror (errno);
470 throw new ::java::io::IOException (JvNewStringUTF (strerr));
474 gnu::java::net::PlainDatagramSocketImpl::mcastGrp (::java::net::InetAddress *inetaddr,
475 ::java::net::NetworkInterface *,
478 // FIXME: implement use of NetworkInterface
480 jbyteArray haddress = inetaddr->addr;
481 #if HAVE_STRUCT_IP_MREQ || HAVE_STRUCT_IPV6_MREQ
483 jbyte *bytes = elements (haddress);
486 int len = haddress->length;
491 #if HAVE_STRUCT_IP_MREQ
495 opname = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
496 memcpy (&u.mreq.imr_multiaddr, bytes, len);
497 // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
498 // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
499 u.mreq.imr_interface.s_addr = htonl (INADDR_ANY);
500 len = sizeof (struct ip_mreq);
501 ptr = (const char *) &u.mreq;
504 #if HAVE_STRUCT_IPV6_MREQ
507 level = IPPROTO_IPV6;
509 /* Prefer new RFC 2553 names. */
510 #ifndef IPV6_JOIN_GROUP
511 #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
513 #ifndef IPV6_LEAVE_GROUP
514 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
517 opname = join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP;
518 memcpy (&u.mreq6.ipv6mr_multiaddr, bytes, len);
519 // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
520 // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
521 u.mreq6.ipv6mr_interface = 0;
522 len = sizeof (struct ipv6_mreq);
523 ptr = (const char *) &u.mreq6;
527 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
529 if (::setsockopt (native_fd, level, opname, ptr, len) == 0)
532 char* strerr = strerror (errno);
533 throw new ::java::io::IOException (JvNewStringUTF (strerr));
536 // Helper function to get the InetAddress for a given socket (file
538 static ::java::net::InetAddress *
539 getLocalAddress (int native_fd)
543 socklen_t addrlen = sizeof(u);
545 if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) != 0)
547 char* strerr = strerror (errno);
548 throw new ::java::net::SocketException (JvNewStringUTF (strerr));
550 if (u.address.sin_family == AF_INET)
552 laddr = JvNewByteArray (4);
553 memcpy (elements (laddr), &u.address.sin_addr, 4);
556 else if (u.address.sin_family == AF_INET6)
558 laddr = JvNewByteArray (16);
559 memcpy (elements (laddr), &u.address6.sin6_addr, 16);
563 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
565 return ::java::net::InetAddress::getByAddress (laddr);
569 gnu::java::net::PlainDatagramSocketImpl::setOption (jint optID,
570 ::java::lang::Object *value)
573 socklen_t val_len = sizeof (val);
576 throw new ::java::net::SocketException (JvNewStringUTF ("Socket closed"));
578 if (_Jv_IsInstanceOf (value, &::java::lang::Boolean::class$))
580 ::java::lang::Boolean *boolobj =
581 static_cast< ::java::lang::Boolean *> (value);
582 val = boolobj->booleanValue() ? 1 : 0;
584 else if (_Jv_IsInstanceOf (value, &::java::lang::Integer::class$))
586 ::java::lang::Integer *intobj =
587 static_cast< ::java::lang::Integer *> (value);
588 val = (int) intobj->intValue();
590 // Else assume value to be an InetAddress for use with IP_MULTICAST_IF.
594 case _Jv_TCP_NODELAY_ :
595 throw new ::java::net::SocketException (
596 JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
598 case _Jv_SO_LINGER_ :
599 throw new ::java::net::SocketException (
600 JvNewStringUTF ("SO_LINGER not valid for UDP"));
602 case _Jv_SO_KEEPALIVE_ :
603 throw new ::java::net::SocketException (
604 JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
607 case _Jv_SO_BROADCAST_ :
608 if (::setsockopt (native_fd, SOL_SOCKET, SO_BROADCAST, (char *) &val,
613 case _Jv_SO_OOBINLINE_ :
614 throw new ::java::net::SocketException (
615 JvNewStringUTF ("SO_OOBINLINE: not valid for UDP"));
618 case _Jv_SO_SNDBUF_ :
619 case _Jv_SO_RCVBUF_ :
620 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
622 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
623 if (::setsockopt (native_fd, SOL_SOCKET, opt, (char *) &val, val_len) != 0)
626 throw new ::java::lang::InternalError (
627 JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
630 case _Jv_SO_REUSEADDR_ :
631 #if defined(SO_REUSEADDR)
632 if (::setsockopt (native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
636 throw new ::java::lang::InternalError (
637 JvNewStringUTF ("SO_REUSEADDR not supported"));
640 case _Jv_SO_BINDADDR_ :
641 throw new ::java::net::SocketException (
642 JvNewStringUTF ("SO_BINDADDR: read only option"));
644 case _Jv_IP_MULTICAST_IF_ :
652 haddress = ((::java::net::InetAddress *) value)->addr;
653 bytes = elements (haddress);
654 len = haddress->length;
658 opname = IP_MULTICAST_IF;
659 memcpy (&u.addr, bytes, len);
660 len = sizeof (struct in_addr);
661 ptr = (const char *) &u.addr;
663 // Tru64 UNIX V5.0 has struct sockaddr_in6, but no IPV6_MULTICAST_IF
664 #if defined (HAVE_INET6) && defined (IPV6_MULTICAST_IF)
667 level = IPPROTO_IPV6;
668 opname = IPV6_MULTICAST_IF;
669 memcpy (&u.addr6, bytes, len);
670 len = sizeof (struct in6_addr);
671 ptr = (const char *) &u.addr6;
676 new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
678 if (::setsockopt (native_fd, level, opname, ptr, len) != 0)
682 case _Jv_IP_MULTICAST_IF2_ :
683 throw new ::java::net::SocketException (
684 JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
687 case _Jv_IP_MULTICAST_LOOP_ :
688 // cache the local address
689 if (localAddress == NULL)
690 localAddress = getLocalAddress (native_fd);
691 len = localAddress->addr->length;
695 opname = IP_MULTICAST_LOOP;
697 #if defined (HAVE_INET6) && defined (IPV6_MULTICAST_LOOP)
700 level = IPPROTO_IPV6;
701 opname = IPV6_MULTICAST_LOOP;
706 new ::java::net::SocketException (JvNewStringUTF ("invalid address length"));
707 if (::setsockopt (native_fd, level, opname, (char *) &val,
713 if (::setsockopt (native_fd, SOL_SOCKET, IP_TOS, (char *) &val,
718 case _Jv_SO_TIMEOUT_ :
726 char* strerr = strerror (errno);
727 throw new ::java::net::SocketException (JvNewStringUTF (strerr));
730 ::java::lang::Object *
731 gnu::java::net::PlainDatagramSocketImpl::getOption (jint optID)
734 socklen_t val_len = sizeof(val);
739 case _Jv_TCP_NODELAY_ :
740 throw new ::java::net::SocketException (
741 JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
743 case _Jv_SO_LINGER_ :
744 throw new ::java::net::SocketException (
745 JvNewStringUTF ("SO_LINGER not valid for UDP"));
747 case _Jv_SO_KEEPALIVE_ :
748 throw new ::java::net::SocketException (
749 JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
752 case _Jv_SO_BROADCAST_ :
753 if (::getsockopt (native_fd, SOL_SOCKET, SO_BROADCAST, (char *) &val,
756 return new ::java::lang::Boolean (val != 0);
758 case _Jv_SO_OOBINLINE_ :
759 throw new ::java::net::SocketException (
760 JvNewStringUTF ("SO_OOBINLINE not valid for UDP"));
763 case _Jv_SO_RCVBUF_ :
764 case _Jv_SO_SNDBUF_ :
765 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
767 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
768 if (::getsockopt (native_fd, SOL_SOCKET, opt, (char *) &val, &val_len) != 0)
771 return new ::java::lang::Integer (val);
773 throw new ::java::lang::InternalError (
774 JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
777 case _Jv_SO_BINDADDR_:
778 // cache the local address
779 if (localAddress == NULL)
780 localAddress = getLocalAddress (native_fd);
783 case _Jv_SO_REUSEADDR_ :
784 #if defined(SO_REUSEADDR)
785 if (::getsockopt (native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
788 return new ::java::lang::Boolean (val != 0);
790 throw new ::java::lang::InternalError (
791 JvNewStringUTF ("SO_REUSEADDR not supported"));
794 case _Jv_IP_MULTICAST_IF_ :
795 #ifdef HAVE_INET_NTOA
796 struct in_addr inaddr;
797 socklen_t inaddr_len;
800 inaddr_len = sizeof(inaddr);
801 if (::getsockopt (native_fd, IPPROTO_IP, IP_MULTICAST_IF, (char *) &inaddr,
805 bytes = inet_ntoa (inaddr);
807 return ::java::net::InetAddress::getByName (JvNewStringLatin1 (bytes));
809 throw new ::java::net::SocketException (
810 JvNewStringUTF ("IP_MULTICAST_IF: not available - no inet_ntoa()"));
813 case _Jv_SO_TIMEOUT_ :
814 return new ::java::lang::Integer (timeout);
817 case _Jv_IP_MULTICAST_IF2_ :
818 throw new ::java::net::SocketException (
819 JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
822 case _Jv_IP_MULTICAST_LOOP_ :
823 // cache the local address
824 localAddress = getLocalAddress (native_fd);
825 if (localAddress->addr->length == 4)
828 opname = IP_MULTICAST_LOOP;
830 #if defined (HAVE_INET6) && defined (IPV6_MULTICAST_LOOP)
831 else if (localAddress->addr->length == 16)
833 level = IPPROTO_IPV6;
834 opname = IPV6_MULTICAST_LOOP;
839 new ::java::net::SocketException (JvNewStringUTF ("invalid address length"));
840 if (::getsockopt (native_fd, level, opname, (char *) &val,
843 return new ::java::lang::Boolean (val != 0);
846 if (::getsockopt (native_fd, SOL_SOCKET, IP_TOS, (char *) &val,
849 return new ::java::lang::Integer (val);
856 char* strerr = strerror (errno);
857 throw new ::java::net::SocketException (JvNewStringUTF (strerr));