1 /* Copyright (C) 2003 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>
44 struct sockaddr_in address;
46 struct sockaddr_in6 address6;
52 #if HAVE_STRUCT_IP_MREQ
55 #if HAVE_STRUCT_IPV6_MREQ
56 struct ipv6_mreq mreq6;
64 struct in6_addr addr6;
69 // FIXME: routines here and/or in natPlainSocketImpl.cc could throw
70 // NoRouteToHostException; also consider UnknownHostException, ConnectException.
73 gnu::java::net::PlainDatagramSocketImpl::create ()
75 int sock = _Jv_socket (AF_INET, SOCK_DGRAM, 0);
79 char* strerr = strerror (errno);
80 throw new ::java::net::SocketException (JvNewStringUTF (strerr));
83 _Jv_platform_close_on_exec (sock);
85 // We use native_fd in place of fd here. From leaving fd null we avoid
86 // the double close problem in FileDescriptor.finalize.
91 gnu::java::net::PlainDatagramSocketImpl::bind (jint lport,
92 ::java::net::InetAddress *host)
95 struct sockaddr *ptr = (struct sockaddr *) &u.address;
96 // FIXME: Use getaddrinfo() to get actual protocol instead of assuming ipv4.
97 jbyteArray haddress = host->addr;
98 jbyte *bytes = elements (haddress);
99 int len = haddress->length;
103 u.address.sin_family = AF_INET;
106 memcpy (&u.address.sin_addr, bytes, len);
108 u.address.sin_addr.s_addr = htonl (INADDR_ANY);
110 len = sizeof (struct sockaddr_in);
111 u.address.sin_port = htons (lport);
116 u.address6.sin6_family = AF_INET6;
117 memcpy (&u.address6.sin6_addr, bytes, len);
118 len = sizeof (struct sockaddr_in6);
119 u.address6.sin6_port = htons (lport);
123 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
125 if (_Jv_bind (native_fd, ptr, len) == 0)
127 socklen_t addrlen = sizeof(u);
131 else if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) == 0)
132 localPort = ntohs (u.address.sin_port);
136 /* Allow broadcast by default. */
138 if (::setsockopt (native_fd, SOL_SOCKET, SO_BROADCAST, (char *) &broadcast,
139 sizeof (broadcast)) != 0)
146 char* strerr = strerror (errno);
147 throw new ::java::net::BindException (JvNewStringUTF (strerr));
151 gnu::java::net::PlainDatagramSocketImpl::connect (::java::net::InetAddress *, jint)
153 throw new ::java::lang::InternalError (JvNewStringLatin1 (
154 "PlainDatagramSocketImpl::connect: not implemented yet"));
158 gnu::java::net::PlainDatagramSocketImpl::disconnect ()
160 throw new ::java::lang::InternalError (JvNewStringLatin1 (
161 "PlainDatagramSocketImpl::disconnect: not implemented yet"));
165 gnu::java::net::PlainDatagramSocketImpl::peek (::java::net::InetAddress *i)
167 // FIXME: Deal with Multicast and if the socket is connected.
169 socklen_t addrlen = sizeof(u);
171 ::recvfrom (native_fd, (char *) NULL, 0, MSG_PEEK, (sockaddr*) &u,
175 // FIXME: Deal with Multicast addressing and if the socket is connected.
178 if (u.address.sin_family == AF_INET)
180 raddr = JvNewByteArray (4);
181 memcpy (elements (raddr), &u.address.sin_addr, 4);
182 rport = ntohs (u.address.sin_port);
185 else if (u.address.sin_family == AF_INET6)
187 raddr = JvNewByteArray (16);
188 memcpy (elements (raddr), &u.address6.sin6_addr, 16);
189 rport = ntohs (u.address6.sin6_port);
193 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
198 char* strerr = strerror (errno);
200 if (errno == ECONNREFUSED)
201 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
203 throw new ::java::io::IOException (JvNewStringUTF (strerr));
207 gnu::java::net::PlainDatagramSocketImpl::peekData (::java::net::DatagramPacket *p)
209 // FIXME: Deal with Multicast and if the socket is connected.
211 socklen_t addrlen = sizeof(u);
212 jbyte *dbytes = elements (p->getData()) + p->getOffset();
213 jint maxlen = p->maxlen - p->getOffset();
216 // Do timeouts via select since SO_RCVTIMEO is not always available.
217 if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE)
222 FD_SET(native_fd, &rset);
223 tv.tv_sec = timeout / 1000;
224 tv.tv_usec = (timeout % 1000) * 1000;
226 if ((retval = _Jv_select (native_fd + 1, &rset, NULL, NULL, &tv)) < 0)
228 else if (retval == 0)
229 throw new ::java::net::SocketTimeoutException
230 (JvNewStringUTF ("PeekData timed out") );
234 ::recvfrom (native_fd, (char *) dbytes, maxlen, MSG_PEEK, (sockaddr*) &u,
238 // FIXME: Deal with Multicast addressing and if the socket is connected.
241 if (u.address.sin_family == AF_INET)
243 raddr = JvNewByteArray (4);
244 memcpy (elements (raddr), &u.address.sin_addr, 4);
245 rport = ntohs (u.address.sin_port);
248 else if (u.address.sin_family == AF_INET6)
250 raddr = JvNewByteArray (16);
251 memcpy (elements (raddr), &u.address6.sin6_addr, 16);
252 rport = ntohs (u.address6.sin6_port);
256 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
258 p->setAddress (new ::java::net::InetAddress (raddr, NULL));
260 p->length = (int) retlen;
264 char* strerr = strerror (errno);
266 if (errno == ECONNREFUSED)
267 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
269 throw new ::java::io::IOException (JvNewStringUTF (strerr));
272 // Close(shutdown) the socket.
274 gnu::java::net::PlainDatagramSocketImpl::close ()
276 // Avoid races from asynchronous finalization.
277 JvSynchronize sync (this);
279 // The method isn't declared to throw anything, so we disregard
281 _Jv_close (native_fd);
287 gnu::java::net::PlainDatagramSocketImpl::send (::java::net::DatagramPacket *p)
289 JvSynchronize lock (SEND_LOCK);
291 // FIXME: Deal with Multicast and if the socket is connected.
292 jint rport = p->getPort();
294 jbyteArray haddress = p->getAddress()->addr;
295 jbyte *bytes = elements (haddress);
296 int len = haddress->length;
297 struct sockaddr *ptr = (struct sockaddr *) &u.address;
298 jbyte *dbytes = elements (p->getData()) + p->getOffset();
301 u.address.sin_family = AF_INET;
302 memcpy (&u.address.sin_addr, bytes, len);
303 len = sizeof (struct sockaddr_in);
304 u.address.sin_port = htons (rport);
309 u.address6.sin6_family = AF_INET6;
310 memcpy (&u.address6.sin6_addr, bytes, len);
311 len = sizeof (struct sockaddr_in6);
312 u.address6.sin6_port = htons (rport);
316 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
318 if (::sendto (native_fd, (char *) dbytes, p->getLength(), 0, ptr, len) >= 0)
321 char* strerr = strerror (errno);
323 if (errno == ECONNREFUSED)
324 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
326 throw new ::java::io::IOException (JvNewStringUTF (strerr));
330 gnu::java::net::PlainDatagramSocketImpl::receive (::java::net::DatagramPacket *p)
332 JvSynchronize lock (RECEIVE_LOCK);
334 // FIXME: Deal with Multicast and if the socket is connected.
336 socklen_t addrlen = sizeof(u);
337 jbyte *dbytes = elements (p->getData()) + p->getOffset();
338 jint maxlen = p->maxlen - p->getOffset();
341 // Do timeouts via select since SO_RCVTIMEO is not always available.
342 if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE)
347 FD_SET(native_fd, &rset);
348 tv.tv_sec = timeout / 1000;
349 tv.tv_usec = (timeout % 1000) * 1000;
351 if ((retval = _Jv_select (native_fd + 1, &rset, NULL, NULL, &tv)) < 0)
353 else if (retval == 0)
354 throw new ::java::net::SocketTimeoutException
355 (JvNewStringUTF ("Receive timed out") );
359 ::recvfrom (native_fd, (char *) dbytes, maxlen, 0, (sockaddr*) &u,
363 // FIXME: Deal with Multicast addressing and if the socket is connected.
366 if (u.address.sin_family == AF_INET)
368 raddr = JvNewByteArray (4);
369 memcpy (elements (raddr), &u.address.sin_addr, 4);
370 rport = ntohs (u.address.sin_port);
373 else if (u.address.sin_family == AF_INET6)
375 raddr = JvNewByteArray (16);
376 memcpy (elements (raddr), &u.address6.sin6_addr, 16);
377 rport = ntohs (u.address6.sin6_port);
381 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
383 p->setAddress (new ::java::net::InetAddress (raddr, NULL));
385 p->length = (jint) retlen;
389 char* strerr = strerror (errno);
391 if (errno == ECONNREFUSED)
392 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
394 throw new ::java::io::IOException (JvNewStringUTF (strerr));
398 gnu::java::net::PlainDatagramSocketImpl::setTimeToLive (jint ttl)
400 // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
401 char val = (char) ttl;
402 socklen_t val_len = sizeof(val);
404 if (::setsockopt (native_fd, IPPROTO_IP, IP_MULTICAST_TTL, &val, val_len) == 0)
407 char* strerr = strerror (errno);
408 throw new ::java::io::IOException (JvNewStringUTF (strerr));
412 gnu::java::net::PlainDatagramSocketImpl::getTimeToLive ()
414 // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
416 socklen_t val_len = sizeof(val);
418 if (::getsockopt (native_fd, IPPROTO_IP, IP_MULTICAST_TTL, &val, &val_len) == 0)
419 return ((int) val) & 0xFF;
421 char* strerr = strerror (errno);
422 throw new ::java::io::IOException (JvNewStringUTF (strerr));
426 gnu::java::net::PlainDatagramSocketImpl::mcastGrp (::java::net::InetAddress *inetaddr,
427 ::java::net::NetworkInterface *,
430 // FIXME: implement use of NetworkInterface
433 jbyteArray haddress = inetaddr->addr;
434 jbyte *bytes = elements (haddress);
435 int len = haddress->length;
440 #if HAVE_STRUCT_IP_MREQ
444 opname = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
445 memcpy (&u.mreq.imr_multiaddr, bytes, len);
446 // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
447 // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
448 u.mreq.imr_interface.s_addr = htonl (INADDR_ANY);
449 len = sizeof (struct ip_mreq);
450 ptr = (const char *) &u.mreq;
453 #if HAVE_STRUCT_IPV6_MREQ
456 level = IPPROTO_IPV6;
458 /* Prefer new RFC 2553 names. */
459 #ifndef IPV6_JOIN_GROUP
460 #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
462 #ifndef IPV6_LEAVE_GROUP
463 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
466 opname = join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP;
467 memcpy (&u.mreq6.ipv6mr_multiaddr, bytes, len);
468 // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
469 // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
470 u.mreq6.ipv6mr_interface = 0;
471 len = sizeof (struct ipv6_mreq);
472 ptr = (const char *) &u.mreq6;
476 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
478 if (::setsockopt (native_fd, level, opname, ptr, len) == 0)
481 char* strerr = strerror (errno);
482 throw new ::java::io::IOException (JvNewStringUTF (strerr));
486 gnu::java::net::PlainDatagramSocketImpl::setOption (jint optID,
487 ::java::lang::Object *value)
490 socklen_t val_len = sizeof (val);
493 throw new ::java::net::SocketException (JvNewStringUTF ("Socket closed"));
495 if (_Jv_IsInstanceOf (value, &::java::lang::Boolean::class$))
497 ::java::lang::Boolean *boolobj =
498 static_cast< ::java::lang::Boolean *> (value);
499 val = boolobj->booleanValue() ? 1 : 0;
501 else if (_Jv_IsInstanceOf (value, &::java::lang::Integer::class$))
503 ::java::lang::Integer *intobj =
504 static_cast< ::java::lang::Integer *> (value);
505 val = (int) intobj->intValue();
507 // Else assume value to be an InetAddress for use with IP_MULTICAST_IF.
511 case _Jv_TCP_NODELAY_ :
512 throw new ::java::net::SocketException (
513 JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
515 case _Jv_SO_LINGER_ :
516 throw new ::java::net::SocketException (
517 JvNewStringUTF ("SO_LINGER not valid for UDP"));
519 case _Jv_SO_KEEPALIVE_ :
520 throw new ::java::net::SocketException (
521 JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
524 case _Jv_SO_BROADCAST_ :
525 if (::setsockopt (native_fd, SOL_SOCKET, SO_BROADCAST, (char *) &val,
530 case _Jv_SO_OOBINLINE_ :
531 throw new ::java::net::SocketException (
532 JvNewStringUTF ("SO_OOBINLINE: not valid for UDP"));
535 case _Jv_SO_SNDBUF_ :
536 case _Jv_SO_RCVBUF_ :
537 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
539 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
540 if (::setsockopt (native_fd, SOL_SOCKET, opt, (char *) &val, val_len) != 0)
543 throw new ::java::lang::InternalError (
544 JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
547 case _Jv_SO_REUSEADDR_ :
548 #if defined(SO_REUSEADDR)
549 if (::setsockopt (native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
553 throw new ::java::lang::InternalError (
554 JvNewStringUTF ("SO_REUSEADDR not supported"));
557 case _Jv_SO_BINDADDR_ :
558 throw new ::java::net::SocketException (
559 JvNewStringUTF ("SO_BINDADDR: read only option"));
561 case _Jv_IP_MULTICAST_IF_ :
569 haddress = ((::java::net::InetAddress *) value)->addr;
570 bytes = elements (haddress);
571 len = haddress->length;
575 opname = IP_MULTICAST_IF;
576 memcpy (&u.addr, bytes, len);
577 len = sizeof (struct in_addr);
578 ptr = (const char *) &u.addr;
580 // Tru64 UNIX V5.0 has struct sockaddr_in6, but no IPV6_MULTICAST_IF
581 #if defined (HAVE_INET6) && defined (IPV6_MULTICAST_IF)
584 level = IPPROTO_IPV6;
585 opname = IPV6_MULTICAST_IF;
586 memcpy (&u.addr6, bytes, len);
587 len = sizeof (struct in6_addr);
588 ptr = (const char *) &u.addr6;
593 new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
595 if (::setsockopt (native_fd, level, opname, ptr, len) != 0)
599 case _Jv_IP_MULTICAST_IF2_ :
600 throw new ::java::net::SocketException (
601 JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
604 case _Jv_IP_MULTICAST_LOOP_ :
605 haddress = ((::java::net::InetAddress *) value)->addr;
606 len = haddress->length;
610 opname = IP_MULTICAST_LOOP;
612 #if defined (HAVE_INET6) && defined (IPV6_MULTICAST_LOOP)
615 level = IPPROTO_IPV6;
616 opname = IPV6_MULTICAST_LOOP;
621 new ::java::net::SocketException (JvNewStringUTF ("invalid address length"));
622 if (::setsockopt (native_fd, level, opname, (char *) &val,
628 if (::setsockopt (native_fd, SOL_SOCKET, IP_TOS, (char *) &val,
633 case _Jv_SO_TIMEOUT_ :
641 char* strerr = strerror (errno);
642 throw new ::java::net::SocketException (JvNewStringUTF (strerr));
645 ::java::lang::Object *
646 gnu::java::net::PlainDatagramSocketImpl::getOption (jint optID)
649 socklen_t val_len = sizeof(val);
651 socklen_t addrlen = sizeof(u);
656 case _Jv_TCP_NODELAY_ :
657 throw new ::java::net::SocketException (
658 JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
660 case _Jv_SO_LINGER_ :
661 throw new ::java::net::SocketException (
662 JvNewStringUTF ("SO_LINGER not valid for UDP"));
664 case _Jv_SO_KEEPALIVE_ :
665 throw new ::java::net::SocketException (
666 JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
669 case _Jv_SO_BROADCAST_ :
670 if (::getsockopt (native_fd, SOL_SOCKET, SO_BROADCAST, (char *) &val,
673 return new ::java::lang::Boolean (val != 0);
675 case _Jv_SO_OOBINLINE_ :
676 throw new ::java::net::SocketException (
677 JvNewStringUTF ("SO_OOBINLINE not valid for UDP"));
680 case _Jv_SO_RCVBUF_ :
681 case _Jv_SO_SNDBUF_ :
682 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
684 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
685 if (::getsockopt (native_fd, SOL_SOCKET, opt, (char *) &val, &val_len) != 0)
688 return new ::java::lang::Integer (val);
690 throw new ::java::lang::InternalError (
691 JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
694 case _Jv_SO_BINDADDR_:
695 // cache the local address
696 if (localAddress == NULL)
699 if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) != 0)
701 if (u.address.sin_family == AF_INET)
703 laddr = JvNewByteArray (4);
704 memcpy (elements (laddr), &u.address.sin_addr, 4);
707 else if (u.address.sin_family == AF_INET6)
709 laddr = JvNewByteArray (16);
710 memcpy (elements (laddr), &u.address6.sin6_addr, 16);
714 throw new ::java::net::SocketException (
715 JvNewStringUTF ("invalid family"));
716 localAddress = new ::java::net::InetAddress (laddr, NULL);
720 case _Jv_SO_REUSEADDR_ :
721 #if defined(SO_REUSEADDR)
722 if (::getsockopt (native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
725 return new ::java::lang::Boolean (val != 0);
727 throw new ::java::lang::InternalError (
728 JvNewStringUTF ("SO_REUSEADDR not supported"));
731 case _Jv_IP_MULTICAST_IF_ :
732 #ifdef HAVE_INET_NTOA
733 struct in_addr inaddr;
734 socklen_t inaddr_len;
737 inaddr_len = sizeof(inaddr);
738 if (::getsockopt (native_fd, IPPROTO_IP, IP_MULTICAST_IF, (char *) &inaddr,
742 bytes = inet_ntoa (inaddr);
744 return ::java::net::InetAddress::getByName (JvNewStringLatin1 (bytes));
746 throw new ::java::net::SocketException (
747 JvNewStringUTF ("IP_MULTICAST_IF: not available - no inet_ntoa()"));
750 case _Jv_SO_TIMEOUT_ :
751 return new ::java::lang::Integer (timeout);
754 case _Jv_IP_MULTICAST_IF2_ :
755 throw new ::java::net::SocketException (
756 JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
759 case _Jv_IP_MULTICAST_LOOP_ :
760 // cache the local address
761 if (localAddress == NULL)
764 if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) != 0)
766 if (u.address.sin_family == AF_INET)
768 laddr = JvNewByteArray (4);
769 memcpy (elements (laddr), &u.address.sin_addr, 4);
772 else if (u.address.sin_family == AF_INET6)
774 laddr = JvNewByteArray (16);
775 memcpy (elements (laddr), &u.address6.sin6_addr, 16);
779 throw new ::java::net::SocketException (
780 JvNewStringUTF ("invalid family"));
781 localAddress = new ::java::net::InetAddress (laddr, NULL);
784 if (localAddress->addr->length == 4)
787 opname = IP_MULTICAST_LOOP;
789 #if defined (HAVE_INET6) && defined (IPV6_MULTICAST_LOOP)
790 else if (localAddress->addr->length == 16)
792 level = IPPROTO_IPV6;
793 opname = IPV6_MULTICAST_LOOP;
798 new ::java::net::SocketException (JvNewStringUTF ("invalid address length"));
799 if (::getsockopt (native_fd, level, opname, (char *) &val,
802 return new ::java::lang::Boolean (val != 0);
805 if (::getsockopt (native_fd, SOL_SOCKET, IP_TOS, (char *) &val,
808 return new ::java::lang::Integer (val);
815 char* strerr = strerror (errno);
816 throw new ::java::net::SocketException (JvNewStringUTF (strerr));