1 /* Copyright (C) 2003, 2005, 2006, 2012 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 #include <gnu/java/net/PlainDatagramSocketImpl.h>
23 #include <java/io/IOException.h>
24 #include <java/io/InterruptedIOException.h>
25 #include <java/net/BindException.h>
26 #include <java/net/SocketException.h>
27 #include <java/net/SocketTimeoutException.h>
28 #include <java/net/InetAddress.h>
29 #include <java/net/NetworkInterface.h>
30 #include <java/net/DatagramPacket.h>
31 #include <java/net/PortUnreachableException.h>
32 #include <java/lang/InternalError.h>
33 #include <java/lang/Object.h>
34 #include <java/lang/Boolean.h>
35 #include <java/lang/Integer.h>
36 #include <java/net/UnknownHostException.h>
37 #include <java/net/ConnectException.h>
38 #include <java/lang/NullPointerException.h>
42 struct sockaddr_in address;
44 struct sockaddr_in6 address6;
50 #if HAVE_STRUCT_IP_MREQ
53 #if HAVE_STRUCT_IPV6_MREQ
54 struct ipv6_mreq mreq6;
62 struct in6_addr addr6;
67 // FIXME: routines here and/or in natPlainSocketImpl.cc could throw
68 // NoRouteToHostException; also consider UnknownHostException, ConnectException.
71 gnu::java::net::PlainDatagramSocketImpl::create ()
73 int sock = _Jv_socket (AF_INET, SOCK_DGRAM, 0);
77 char* strerr = strerror (errno);
78 throw new ::java::net::SocketException (JvNewStringUTF (strerr));
81 // We use native_fd in place of fd here. From leaving fd null we avoid
82 // the double close problem in FileDescriptor.finalize.
87 gnu::java::net::PlainDatagramSocketImpl::bind (jint lport,
88 ::java::net::InetAddress *host)
91 struct sockaddr *ptr = (struct sockaddr *) &u.address;
92 // FIXME: Use getaddrinfo() to get actual protocol instead of assuming ipv4.
93 jbyteArray haddress = host->addr;
94 jbyte *bytes = elements (haddress);
95 int len = haddress->length;
99 u.address.sin_family = AF_INET;
102 memcpy (&u.address.sin_addr, bytes, len);
104 u.address.sin_addr.s_addr = htonl (INADDR_ANY);
106 len = sizeof (struct sockaddr_in);
107 u.address.sin_port = htons (lport);
112 u.address6.sin6_family = AF_INET6;
113 memcpy (&u.address6.sin6_addr, bytes, len);
114 len = sizeof (struct sockaddr_in6);
115 u.address6.sin6_port = htons (lport);
119 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
121 if (_Jv_bind (native_fd, ptr, len) == 0)
123 socklen_t addrlen = sizeof(u);
127 else if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) == 0)
128 localPort = ntohs (u.address.sin_port);
132 /* Allow broadcast by default. */
134 if (::setsockopt (native_fd, SOL_SOCKET, SO_BROADCAST, (char *) &broadcast,
135 sizeof (broadcast)) != 0)
142 char* strerr = strerror (errno);
143 throw new ::java::net::BindException (JvNewStringUTF (strerr));
147 gnu::java::net::PlainDatagramSocketImpl::connect (::java::net::InetAddress *host,
151 throw new ::java::lang::NullPointerException;
154 jbyteArray haddress = host->addr;
155 jbyte *bytes = elements (haddress);
156 int len = haddress->length;
157 struct sockaddr *ptr = (struct sockaddr *) &u.address;
160 u.address.sin_family = AF_INET;
161 memcpy (&u.address.sin_addr, bytes, len);
162 len = sizeof (struct sockaddr_in);
163 u.address.sin_port = htons (rport);
168 u.address6.sin6_family = AF_INET6;
169 memcpy (&u.address6.sin6_addr, bytes, len);
170 len = sizeof (struct sockaddr_in6);
171 u.address6.sin6_port = htons (rport);
175 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
177 if (_Jv_connect (native_fd, ptr, len) == 0)
179 char* strerr = strerror (errno);
180 throw new ::java::net::ConnectException (JvNewStringUTF (strerr));
184 gnu::java::net::PlainDatagramSocketImpl::disconnect ()
186 struct sockaddr addr;
187 addr.sa_family = AF_UNSPEC;
188 // Ignore errors. This is lame but apparently required.
189 _Jv_connect (native_fd, &addr, sizeof (addr));
193 gnu::java::net::PlainDatagramSocketImpl::peek (::java::net::InetAddress *i)
195 // FIXME: Deal with Multicast and if the socket is connected.
197 socklen_t addrlen = sizeof(u);
199 ::recvfrom (native_fd, (char *) NULL, 0, MSG_PEEK, (sockaddr*) &u,
203 // FIXME: Deal with Multicast addressing and if the socket is connected.
206 if (u.address.sin_family == AF_INET)
208 raddr = JvNewByteArray (4);
209 memcpy (elements (raddr), &u.address.sin_addr, 4);
210 rport = ntohs (u.address.sin_port);
213 else if (u.address.sin_family == AF_INET6)
215 raddr = JvNewByteArray (16);
216 memcpy (elements (raddr), &u.address6.sin6_addr, 16);
217 rport = ntohs (u.address6.sin6_port);
221 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
226 char* strerr = strerror (errno);
228 if (errno == ECONNREFUSED)
229 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
231 throw new ::java::io::IOException (JvNewStringUTF (strerr));
235 gnu::java::net::PlainDatagramSocketImpl::peekData (::java::net::DatagramPacket *p)
237 // FIXME: Deal with Multicast and if the socket is connected.
239 socklen_t addrlen = sizeof(u);
240 jbyte *dbytes = elements (p->getData()) + p->getOffset();
241 jint maxlen = p->maxlen - p->getOffset();
244 // Do timeouts via select since SO_RCVTIMEO is not always available.
245 if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE)
250 FD_SET(native_fd, &rset);
251 tv.tv_sec = timeout / 1000;
252 tv.tv_usec = (timeout % 1000) * 1000;
254 if ((retval = _Jv_select (native_fd + 1, &rset, NULL, NULL, &tv)) < 0)
256 else if (retval == 0)
257 throw new ::java::net::SocketTimeoutException
258 (JvNewStringUTF ("PeekData timed out") );
262 ::recvfrom (native_fd, (char *) dbytes, maxlen, MSG_PEEK, (sockaddr*) &u,
266 // FIXME: Deal with Multicast addressing and if the socket is connected.
269 if (u.address.sin_family == AF_INET)
271 raddr = JvNewByteArray (4);
272 memcpy (elements (raddr), &u.address.sin_addr, 4);
273 rport = ntohs (u.address.sin_port);
276 else if (u.address.sin_family == AF_INET6)
278 raddr = JvNewByteArray (16);
279 memcpy (elements (raddr), &u.address6.sin6_addr, 16);
280 rport = ntohs (u.address6.sin6_port);
284 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
286 p->setAddress (::java::net::InetAddress::getByAddress (raddr));
288 p->length = (int) retlen;
292 char* strerr = strerror (errno);
294 if (errno == ECONNREFUSED)
295 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
297 throw new ::java::io::IOException (JvNewStringUTF (strerr));
300 // Close(shutdown) the socket.
302 gnu::java::net::PlainDatagramSocketImpl::close ()
304 // Avoid races from asynchronous finalization.
305 JvSynchronize sync (this);
307 // The method isn't declared to throw anything, so we disregard
309 _Jv_close (native_fd);
315 gnu::java::net::PlainDatagramSocketImpl::send (::java::net::DatagramPacket *p)
317 JvSynchronize lock (SEND_LOCK);
319 // FIXME: Deal with Multicast.
321 ::java::net::InetAddress *host = p->getAddress();
324 // If there is no host, maybe this socket was connected, in
325 // which case we try a plain send().
326 jbyte *dbytes = elements (p->getData()) + p->getOffset();
327 if (::send (native_fd, (char *) dbytes, p->getLength(), 0) >= 0)
332 jint rport = p->getPort();
335 jbyteArray haddress = host->addr;
336 jbyte *bytes = elements (haddress);
337 int len = haddress->length;
338 struct sockaddr *ptr = (struct sockaddr *) &u.address;
339 jbyte *dbytes = elements (p->getData()) + p->getOffset();
342 u.address.sin_family = AF_INET;
343 memcpy (&u.address.sin_addr, bytes, len);
344 len = sizeof (struct sockaddr_in);
345 u.address.sin_port = htons (rport);
350 u.address6.sin6_family = AF_INET6;
351 memcpy (&u.address6.sin6_addr, bytes, len);
352 len = sizeof (struct sockaddr_in6);
353 u.address6.sin6_port = htons (rport);
357 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
359 if (::sendto (native_fd, (char *) dbytes, p->getLength(), 0, ptr, len)
364 char* strerr = strerror (errno);
366 if (errno == ECONNREFUSED)
367 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
369 throw new ::java::io::IOException (JvNewStringUTF (strerr));
373 gnu::java::net::PlainDatagramSocketImpl::receive (::java::net::DatagramPacket *p)
375 JvSynchronize lock (RECEIVE_LOCK);
377 // FIXME: Deal with Multicast and if the socket is connected.
379 socklen_t addrlen = sizeof(u);
380 jbyte *dbytes = elements (p->getData()) + p->getOffset();
381 jint maxlen = p->maxlen - p->getOffset();
384 // Do timeouts via select since SO_RCVTIMEO is not always available.
385 if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE)
390 FD_SET(native_fd, &rset);
391 tv.tv_sec = timeout / 1000;
392 tv.tv_usec = (timeout % 1000) * 1000;
394 if ((retval = _Jv_select (native_fd + 1, &rset, NULL, NULL, &tv)) < 0)
396 else if (retval == 0)
397 throw new ::java::net::SocketTimeoutException
398 (JvNewStringUTF ("Receive timed out") );
402 ::recvfrom (native_fd, (char *) dbytes, maxlen, 0, (sockaddr*) &u,
406 // FIXME: Deal with Multicast addressing and if the socket is connected.
409 if (u.address.sin_family == AF_INET)
411 raddr = JvNewByteArray (4);
412 memcpy (elements (raddr), &u.address.sin_addr, 4);
413 rport = ntohs (u.address.sin_port);
416 else if (u.address.sin_family == AF_INET6)
418 raddr = JvNewByteArray (16);
419 memcpy (elements (raddr), &u.address6.sin6_addr, 16);
420 rport = ntohs (u.address6.sin6_port);
424 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
426 p->setAddress (::java::net::InetAddress::getByAddress (raddr));
428 p->length = (jint) retlen;
432 char* strerr = strerror (errno);
434 if (errno == ECONNREFUSED)
435 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
437 throw new ::java::io::IOException (JvNewStringUTF (strerr));
441 gnu::java::net::PlainDatagramSocketImpl::setTimeToLive (jint ttl)
443 // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
444 char val = (char) ttl;
445 socklen_t val_len = sizeof(val);
447 if (::setsockopt (native_fd, IPPROTO_IP, IP_MULTICAST_TTL, &val, val_len) == 0)
450 char* strerr = strerror (errno);
451 throw new ::java::io::IOException (JvNewStringUTF (strerr));
455 gnu::java::net::PlainDatagramSocketImpl::getTimeToLive ()
457 // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
459 socklen_t val_len = sizeof(val);
461 if (::getsockopt (native_fd, IPPROTO_IP, IP_MULTICAST_TTL, &val, &val_len) == 0)
462 return ((int) val) & 0xFF;
464 char* strerr = strerror (errno);
465 throw new ::java::io::IOException (JvNewStringUTF (strerr));
469 gnu::java::net::PlainDatagramSocketImpl::mcastGrp (::java::net::InetAddress *inetaddr,
470 ::java::net::NetworkInterface *,
473 // FIXME: implement use of NetworkInterface
475 jbyteArray haddress = inetaddr->addr;
476 #if HAVE_STRUCT_IP_MREQ || HAVE_STRUCT_IPV6_MREQ
478 jbyte *bytes = elements (haddress);
481 int len = haddress->length;
486 #if HAVE_STRUCT_IP_MREQ
490 opname = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
491 memcpy (&u.mreq.imr_multiaddr, bytes, len);
492 // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
493 // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
494 u.mreq.imr_interface.s_addr = htonl (INADDR_ANY);
495 len = sizeof (struct ip_mreq);
496 ptr = (const char *) &u.mreq;
499 #if HAVE_STRUCT_IPV6_MREQ
502 level = IPPROTO_IPV6;
504 /* Prefer new RFC 2553 names. */
505 #ifndef IPV6_JOIN_GROUP
506 #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
508 #ifndef IPV6_LEAVE_GROUP
509 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
512 opname = join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP;
513 memcpy (&u.mreq6.ipv6mr_multiaddr, bytes, len);
514 // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
515 // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
516 u.mreq6.ipv6mr_interface = 0;
517 len = sizeof (struct ipv6_mreq);
518 ptr = (const char *) &u.mreq6;
522 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
524 if (::setsockopt (native_fd, level, opname, ptr, len) == 0)
527 char* strerr = strerror (errno);
528 throw new ::java::io::IOException (JvNewStringUTF (strerr));
531 // Helper function to get the InetAddress for a given socket (file
533 static ::java::net::InetAddress *
534 getLocalAddress (int native_fd)
538 socklen_t addrlen = sizeof(u);
540 if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) != 0)
542 char* strerr = strerror (errno);
543 throw new ::java::net::SocketException (JvNewStringUTF (strerr));
545 if (u.address.sin_family == AF_INET)
547 laddr = JvNewByteArray (4);
548 memcpy (elements (laddr), &u.address.sin_addr, 4);
551 else if (u.address.sin_family == AF_INET6)
553 laddr = JvNewByteArray (16);
554 memcpy (elements (laddr), &u.address6.sin6_addr, 16);
558 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
560 return ::java::net::InetAddress::getByAddress (laddr);
564 gnu::java::net::PlainDatagramSocketImpl::setOption (jint optID,
565 ::java::lang::Object *value)
568 socklen_t val_len = sizeof (val);
571 throw new ::java::net::SocketException (JvNewStringUTF ("Socket closed"));
573 if (_Jv_IsInstanceOf (value, &::java::lang::Boolean::class$))
575 ::java::lang::Boolean *boolobj =
576 static_cast< ::java::lang::Boolean *> (value);
577 val = boolobj->booleanValue() ? 1 : 0;
579 else if (_Jv_IsInstanceOf (value, &::java::lang::Integer::class$))
581 ::java::lang::Integer *intobj =
582 static_cast< ::java::lang::Integer *> (value);
583 val = (int) intobj->intValue();
585 // Else assume value to be an InetAddress for use with IP_MULTICAST_IF.
589 case _Jv_TCP_NODELAY_ :
590 throw new ::java::net::SocketException (
591 JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
593 case _Jv_SO_LINGER_ :
594 throw new ::java::net::SocketException (
595 JvNewStringUTF ("SO_LINGER not valid for UDP"));
597 case _Jv_SO_KEEPALIVE_ :
598 throw new ::java::net::SocketException (
599 JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
602 case _Jv_SO_BROADCAST_ :
603 if (::setsockopt (native_fd, SOL_SOCKET, SO_BROADCAST, (char *) &val,
608 case _Jv_SO_OOBINLINE_ :
609 throw new ::java::net::SocketException (
610 JvNewStringUTF ("SO_OOBINLINE: not valid for UDP"));
613 case _Jv_SO_SNDBUF_ :
614 case _Jv_SO_RCVBUF_ :
615 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
617 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
618 if (::setsockopt (native_fd, SOL_SOCKET, opt, (char *) &val, val_len) != 0)
621 throw new ::java::lang::InternalError (
622 JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
625 case _Jv_SO_REUSEADDR_ :
626 #if defined(SO_REUSEADDR)
627 if (::setsockopt (native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
631 throw new ::java::lang::InternalError (
632 JvNewStringUTF ("SO_REUSEADDR not supported"));
635 case _Jv_SO_BINDADDR_ :
636 throw new ::java::net::SocketException (
637 JvNewStringUTF ("SO_BINDADDR: read only option"));
639 case _Jv_IP_MULTICAST_IF_ :
647 haddress = ((::java::net::InetAddress *) value)->addr;
648 bytes = elements (haddress);
649 len = haddress->length;
653 opname = IP_MULTICAST_IF;
654 memcpy (&u.addr, bytes, len);
655 len = sizeof (struct in_addr);
656 ptr = (const char *) &u.addr;
661 level = IPPROTO_IPV6;
662 opname = IPV6_MULTICAST_IF;
663 memcpy (&u.addr6, bytes, len);
664 len = sizeof (struct in6_addr);
665 ptr = (const char *) &u.addr6;
670 new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
672 if (::setsockopt (native_fd, level, opname, ptr, len) != 0)
676 case _Jv_IP_MULTICAST_IF2_ :
677 throw new ::java::net::SocketException (
678 JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
681 case _Jv_IP_MULTICAST_LOOP_ :
682 // cache the local address
683 if (localAddress == NULL)
684 localAddress = getLocalAddress (native_fd);
685 len = localAddress->addr->length;
689 opname = IP_MULTICAST_LOOP;
691 #if defined (HAVE_INET6) && defined (IPV6_MULTICAST_LOOP)
694 level = IPPROTO_IPV6;
695 opname = IPV6_MULTICAST_LOOP;
700 new ::java::net::SocketException (JvNewStringUTF ("invalid address length"));
701 if (::setsockopt (native_fd, level, opname, (char *) &val,
707 if (::setsockopt (native_fd, SOL_SOCKET, IP_TOS, (char *) &val,
712 case _Jv_SO_TIMEOUT_ :
720 char* strerr = strerror (errno);
721 throw new ::java::net::SocketException (JvNewStringUTF (strerr));
724 ::java::lang::Object *
725 gnu::java::net::PlainDatagramSocketImpl::getOption (jint optID)
728 socklen_t val_len = sizeof(val);
733 case _Jv_TCP_NODELAY_ :
734 throw new ::java::net::SocketException (
735 JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
737 case _Jv_SO_LINGER_ :
738 throw new ::java::net::SocketException (
739 JvNewStringUTF ("SO_LINGER not valid for UDP"));
741 case _Jv_SO_KEEPALIVE_ :
742 throw new ::java::net::SocketException (
743 JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
746 case _Jv_SO_BROADCAST_ :
747 if (::getsockopt (native_fd, SOL_SOCKET, SO_BROADCAST, (char *) &val,
750 return new ::java::lang::Boolean (val != 0);
752 case _Jv_SO_OOBINLINE_ :
753 throw new ::java::net::SocketException (
754 JvNewStringUTF ("SO_OOBINLINE not valid for UDP"));
757 case _Jv_SO_RCVBUF_ :
758 case _Jv_SO_SNDBUF_ :
759 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
761 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
762 if (::getsockopt (native_fd, SOL_SOCKET, opt, (char *) &val, &val_len) != 0)
765 return new ::java::lang::Integer (val);
767 throw new ::java::lang::InternalError (
768 JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
771 case _Jv_SO_BINDADDR_:
772 // cache the local address
773 if (localAddress == NULL)
774 localAddress = getLocalAddress (native_fd);
777 case _Jv_SO_REUSEADDR_ :
778 #if defined(SO_REUSEADDR)
779 if (::getsockopt (native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
782 return new ::java::lang::Boolean (val != 0);
784 throw new ::java::lang::InternalError (
785 JvNewStringUTF ("SO_REUSEADDR not supported"));
788 case _Jv_IP_MULTICAST_IF_ :
789 #ifdef HAVE_INET_NTOA
790 struct in_addr inaddr;
791 socklen_t inaddr_len;
794 inaddr_len = sizeof(inaddr);
795 if (::getsockopt (native_fd, IPPROTO_IP, IP_MULTICAST_IF, (char *) &inaddr,
799 bytes = inet_ntoa (inaddr);
801 return ::java::net::InetAddress::getByName (JvNewStringLatin1 (bytes));
803 throw new ::java::net::SocketException (
804 JvNewStringUTF ("IP_MULTICAST_IF: not available - no inet_ntoa()"));
807 case _Jv_SO_TIMEOUT_ :
808 return new ::java::lang::Integer (timeout);
811 case _Jv_IP_MULTICAST_IF2_ :
812 throw new ::java::net::SocketException (
813 JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
816 case _Jv_IP_MULTICAST_LOOP_ :
817 // cache the local address
818 localAddress = getLocalAddress (native_fd);
819 if (localAddress->addr->length == 4)
822 opname = IP_MULTICAST_LOOP;
824 #if defined (HAVE_INET6) && defined (IPV6_MULTICAST_LOOP)
825 else if (localAddress->addr->length == 16)
827 level = IPPROTO_IPV6;
828 opname = IPV6_MULTICAST_LOOP;
833 new ::java::net::SocketException (JvNewStringUTF ("invalid address length"));
834 if (::getsockopt (native_fd, level, opname, (char *) &val,
837 return new ::java::lang::Boolean (val != 0);
840 if (::getsockopt (native_fd, SOL_SOCKET, IP_TOS, (char *) &val,
843 return new ::java::lang::Integer (val);
850 char* strerr = strerror (errno);
851 throw new ::java::net::SocketException (JvNewStringUTF (strerr));