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/InetAddress.h>
33 #include <java/net/NetworkInterface.h>
34 #include <java/net/DatagramPacket.h>
35 #include <java/net/PortUnreachableException.h>
36 #include <java/lang/InternalError.h>
37 #include <java/lang/Object.h>
38 #include <java/lang/Boolean.h>
39 #include <java/lang/Integer.h>
43 struct sockaddr_in address;
45 struct sockaddr_in6 address6;
51 #if HAVE_STRUCT_IP_MREQ
54 #if HAVE_STRUCT_IPV6_MREQ
55 struct ipv6_mreq mreq6;
63 struct in6_addr addr6;
68 // FIXME: routines here and/or in natPlainSocketImpl.cc could throw
69 // NoRouteToHostException; also consider UnknownHostException, ConnectException.
72 gnu::java::net::PlainDatagramSocketImpl::create ()
74 int sock = _Jv_socket (AF_INET, SOCK_DGRAM, 0);
78 char* strerr = strerror (errno);
79 throw new ::java::net::SocketException (JvNewStringUTF (strerr));
82 _Jv_platform_close_on_exec (sock);
84 // We use fnum in place of fd here. From leaving fd null we avoid
85 // the double close problem in FileDescriptor.finalize.
90 gnu::java::net::PlainDatagramSocketImpl::bind (jint lport,
91 ::java::net::InetAddress *host)
94 struct sockaddr *ptr = (struct sockaddr *) &u.address;
95 // FIXME: Use getaddrinfo() to get actual protocol instead of assuming ipv4.
96 jbyteArray haddress = host->addr;
97 jbyte *bytes = elements (haddress);
98 int len = haddress->length;
102 u.address.sin_family = AF_INET;
105 memcpy (&u.address.sin_addr, bytes, len);
107 u.address.sin_addr.s_addr = htonl (INADDR_ANY);
109 len = sizeof (struct sockaddr_in);
110 u.address.sin_port = htons (lport);
115 u.address6.sin6_family = AF_INET6;
116 memcpy (&u.address6.sin6_addr, bytes, len);
117 len = sizeof (struct sockaddr_in6);
118 u.address6.sin6_port = htons (lport);
122 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
124 if (_Jv_bind (fnum, ptr, len) == 0)
126 socklen_t addrlen = sizeof(u);
130 else if (::getsockname (fnum, (sockaddr*) &u, &addrlen) == 0)
131 localPort = ntohs (u.address.sin_port);
135 /* Allow broadcast by default. */
137 if (::setsockopt (fnum, SOL_SOCKET, SO_BROADCAST, (char *) &broadcast,
138 sizeof (broadcast)) != 0)
145 char* strerr = strerror (errno);
146 throw new ::java::net::BindException (JvNewStringUTF (strerr));
150 gnu::java::net::PlainDatagramSocketImpl::connect (::java::net::InetAddress *, jint)
152 throw new ::java::lang::InternalError (JvNewStringLatin1 (
153 "PlainDatagramSocketImpl::connect: not implemented yet"));
157 gnu::java::net::PlainDatagramSocketImpl::disconnect ()
159 throw new ::java::lang::InternalError (JvNewStringLatin1 (
160 "PlainDatagramSocketImpl::disconnect: not implemented yet"));
164 gnu::java::net::PlainDatagramSocketImpl::peek (::java::net::InetAddress *i)
166 // FIXME: Deal with Multicast and if the socket is connected.
168 socklen_t addrlen = sizeof(u);
170 ::recvfrom (fnum, (char *) NULL, 0, MSG_PEEK, (sockaddr*) &u,
174 // FIXME: Deal with Multicast addressing and if the socket is connected.
177 if (u.address.sin_family == AF_INET)
179 raddr = JvNewByteArray (4);
180 memcpy (elements (raddr), &u.address.sin_addr, 4);
181 rport = ntohs (u.address.sin_port);
184 else if (u.address.sin_family == AF_INET6)
186 raddr = JvNewByteArray (16);
187 memcpy (elements (raddr), &u.address6.sin6_addr, 16);
188 rport = ntohs (u.address6.sin6_port);
192 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
197 char* strerr = strerror (errno);
199 if (errno == ECONNREFUSED)
200 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
202 throw new ::java::io::IOException (JvNewStringUTF (strerr));
206 gnu::java::net::PlainDatagramSocketImpl::peekData (::java::net::DatagramPacket *p)
208 // FIXME: Deal with Multicast and if the socket is connected.
210 socklen_t addrlen = sizeof(u);
211 jbyte *dbytes = elements (p->getData());
214 // Do timeouts via select since SO_RCVTIMEO is not always available.
215 if (timeout > 0 && fnum >= 0 && fnum < FD_SETSIZE)
221 tv.tv_sec = timeout / 1000;
222 tv.tv_usec = (timeout % 1000) * 1000;
224 if ((retval = _Jv_select (fnum + 1, &rset, NULL, NULL, &tv)) < 0)
226 else if (retval == 0)
227 throw new ::java::io::InterruptedIOException ();
231 ::recvfrom (fnum, (char *) dbytes, p->getLength(), MSG_PEEK, (sockaddr*) &u,
235 // FIXME: Deal with Multicast addressing and if the socket is connected.
238 if (u.address.sin_family == AF_INET)
240 raddr = JvNewByteArray (4);
241 memcpy (elements (raddr), &u.address.sin_addr, 4);
242 rport = ntohs (u.address.sin_port);
245 else if (u.address.sin_family == AF_INET6)
247 raddr = JvNewByteArray (16);
248 memcpy (elements (raddr), &u.address6.sin6_addr, 16);
249 rport = ntohs (u.address6.sin6_port);
253 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
255 p->setAddress (new ::java::net::InetAddress (raddr, NULL));
257 p->setLength ((jint) retlen);
261 char* strerr = strerror (errno);
263 if (errno == ECONNREFUSED)
264 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
266 throw new ::java::io::IOException (JvNewStringUTF (strerr));
269 // Close(shutdown) the socket.
271 gnu::java::net::PlainDatagramSocketImpl::close ()
273 // Avoid races from asynchronous finalization.
274 JvSynchronize sync (this);
276 // The method isn't declared to throw anything, so we disregard
284 gnu::java::net::PlainDatagramSocketImpl::send (::java::net::DatagramPacket *p)
286 // FIXME: Deal with Multicast and if the socket is connected.
287 jint rport = p->getPort();
289 jbyteArray haddress = p->getAddress()->addr;
290 jbyte *bytes = elements (haddress);
291 int len = haddress->length;
292 struct sockaddr *ptr = (struct sockaddr *) &u.address;
293 jbyte *dbytes = elements (p->getData());
296 u.address.sin_family = AF_INET;
297 memcpy (&u.address.sin_addr, bytes, len);
298 len = sizeof (struct sockaddr_in);
299 u.address.sin_port = htons (rport);
304 u.address6.sin6_family = AF_INET6;
305 memcpy (&u.address6.sin6_addr, bytes, len);
306 len = sizeof (struct sockaddr_in6);
307 u.address6.sin6_port = htons (rport);
311 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
313 if (::sendto (fnum, (char *) dbytes, p->getLength(), 0, ptr, len) >= 0)
316 char* strerr = strerror (errno);
318 if (errno == ECONNREFUSED)
319 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
321 throw new ::java::io::IOException (JvNewStringUTF (strerr));
325 gnu::java::net::PlainDatagramSocketImpl::receive (::java::net::DatagramPacket *p)
327 // FIXME: Deal with Multicast and if the socket is connected.
329 socklen_t addrlen = sizeof(u);
330 jbyte *dbytes = elements (p->getData());
333 // Do timeouts via select since SO_RCVTIMEO is not always available.
334 if (timeout > 0 && fnum >= 0 && fnum < FD_SETSIZE)
340 tv.tv_sec = timeout / 1000;
341 tv.tv_usec = (timeout % 1000) * 1000;
343 if ((retval = _Jv_select (fnum + 1, &rset, NULL, NULL, &tv)) < 0)
345 else if (retval == 0)
346 throw new ::java::io::InterruptedIOException ();
350 ::recvfrom (fnum, (char *) dbytes, p->getLength(), 0, (sockaddr*) &u,
354 // FIXME: Deal with Multicast addressing and if the socket is connected.
357 if (u.address.sin_family == AF_INET)
359 raddr = JvNewByteArray (4);
360 memcpy (elements (raddr), &u.address.sin_addr, 4);
361 rport = ntohs (u.address.sin_port);
364 else if (u.address.sin_family == AF_INET6)
366 raddr = JvNewByteArray (16);
367 memcpy (elements (raddr), &u.address6.sin6_addr, 16);
368 rport = ntohs (u.address6.sin6_port);
372 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
374 p->setAddress (new ::java::net::InetAddress (raddr, NULL));
376 p->setLength ((jint) retlen);
380 char* strerr = strerror (errno);
382 if (errno == ECONNREFUSED)
383 throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
385 throw new ::java::io::IOException (JvNewStringUTF (strerr));
389 gnu::java::net::PlainDatagramSocketImpl::setTimeToLive (jint ttl)
391 // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
392 char val = (char) ttl;
393 socklen_t val_len = sizeof(val);
395 if (::setsockopt (fnum, IPPROTO_IP, IP_MULTICAST_TTL, &val, val_len) == 0)
398 char* strerr = strerror (errno);
399 throw new ::java::io::IOException (JvNewStringUTF (strerr));
403 gnu::java::net::PlainDatagramSocketImpl::getTimeToLive ()
405 // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
407 socklen_t val_len = sizeof(val);
409 if (::getsockopt (fnum, IPPROTO_IP, IP_MULTICAST_TTL, &val, &val_len) == 0)
410 return ((int) val) & 0xFF;
412 char* strerr = strerror (errno);
413 throw new ::java::io::IOException (JvNewStringUTF (strerr));
417 gnu::java::net::PlainDatagramSocketImpl::mcastGrp (::java::net::InetAddress *inetaddr,
418 ::java::net::NetworkInterface *,
421 // FIXME: implement use of NetworkInterface
424 jbyteArray haddress = inetaddr->addr;
425 jbyte *bytes = elements (haddress);
426 int len = haddress->length;
431 #if HAVE_STRUCT_IP_MREQ
435 opname = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
436 memcpy (&u.mreq.imr_multiaddr, bytes, len);
437 // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
438 // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
439 u.mreq.imr_interface.s_addr = htonl (INADDR_ANY);
440 len = sizeof (struct ip_mreq);
441 ptr = (const char *) &u.mreq;
444 #if HAVE_STRUCT_IPV6_MREQ
447 level = IPPROTO_IPV6;
449 /* Prefer new RFC 2553 names. */
450 #ifndef IPV6_JOIN_GROUP
451 #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
453 #ifndef IPV6_LEAVE_GROUP
454 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
457 opname = join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP;
458 memcpy (&u.mreq6.ipv6mr_multiaddr, bytes, len);
459 // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
460 // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
461 u.mreq6.ipv6mr_interface = 0;
462 len = sizeof (struct ipv6_mreq);
463 ptr = (const char *) &u.mreq6;
467 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
469 if (::setsockopt (fnum, level, opname, ptr, len) == 0)
472 char* strerr = strerror (errno);
473 throw new ::java::io::IOException (JvNewStringUTF (strerr));
477 gnu::java::net::PlainDatagramSocketImpl::setOption (jint optID,
478 ::java::lang::Object *value)
481 socklen_t val_len = sizeof (val);
484 throw new ::java::net::SocketException (JvNewStringUTF ("Socket closed"));
486 if (_Jv_IsInstanceOf (value, &::java::lang::Boolean::class$))
488 ::java::lang::Boolean *boolobj =
489 static_cast< ::java::lang::Boolean *> (value);
490 val = boolobj->booleanValue() ? 1 : 0;
492 else if (_Jv_IsInstanceOf (value, &::java::lang::Integer::class$))
494 ::java::lang::Integer *intobj =
495 static_cast< ::java::lang::Integer *> (value);
496 val = (int) intobj->intValue();
498 // Else assume value to be an InetAddress for use with IP_MULTICAST_IF.
502 case _Jv_TCP_NODELAY_ :
503 throw new ::java::net::SocketException (
504 JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
506 case _Jv_SO_LINGER_ :
507 throw new ::java::net::SocketException (
508 JvNewStringUTF ("SO_LINGER not valid for UDP"));
510 case _Jv_SO_KEEPALIVE_ :
511 throw new ::java::net::SocketException (
512 JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
515 case _Jv_SO_BROADCAST_ :
516 if (::setsockopt (fnum, SOL_SOCKET, SO_BROADCAST, (char *) &val,
521 case _Jv_SO_OOBINLINE_ :
522 throw new ::java::net::SocketException (
523 JvNewStringUTF ("SO_OOBINLINE: not valid for UDP"));
526 case _Jv_SO_SNDBUF_ :
527 case _Jv_SO_RCVBUF_ :
528 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
530 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
531 if (::setsockopt (fnum, SOL_SOCKET, opt, (char *) &val, val_len) != 0)
534 throw new ::java::lang::InternalError (
535 JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
538 case _Jv_SO_REUSEADDR_ :
539 #if defined(SO_REUSEADDR)
540 if (::setsockopt (fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
544 throw new ::java::lang::InternalError (
545 JvNewStringUTF ("SO_REUSEADDR not supported"));
548 case _Jv_SO_BINDADDR_ :
549 throw new ::java::net::SocketException (
550 JvNewStringUTF ("SO_BINDADDR: read only option"));
552 case _Jv_IP_MULTICAST_IF_ :
560 haddress = ((::java::net::InetAddress *) value)->addr;
561 bytes = elements (haddress);
562 len = haddress->length;
566 opname = IP_MULTICAST_IF;
567 memcpy (&u.addr, bytes, len);
568 len = sizeof (struct in_addr);
569 ptr = (const char *) &u.addr;
571 // Tru64 UNIX V5.0 has struct sockaddr_in6, but no IPV6_MULTICAST_IF
572 #if defined (HAVE_INET6) && defined (IPV6_MULTICAST_IF)
575 level = IPPROTO_IPV6;
576 opname = IPV6_MULTICAST_IF;
577 memcpy (&u.addr6, bytes, len);
578 len = sizeof (struct in6_addr);
579 ptr = (const char *) &u.addr6;
584 new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
586 if (::setsockopt (fnum, level, opname, ptr, len) != 0)
590 case _Jv_IP_MULTICAST_IF2_ :
591 throw new ::java::net::SocketException (
592 JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
595 case _Jv_IP_MULTICAST_LOOP_ :
596 throw new ::java::net::SocketException (
597 JvNewStringUTF ("IP_MULTICAST_LOOP: not yet implemented"));
601 if (::setsockopt (fnum, SOL_SOCKET, IP_TOS, (char *) &val,
606 case _Jv_SO_TIMEOUT_ :
614 char* strerr = strerror (errno);
615 throw new ::java::net::SocketException (JvNewStringUTF (strerr));
618 ::java::lang::Object *
619 gnu::java::net::PlainDatagramSocketImpl::getOption (jint optID)
622 socklen_t val_len = sizeof(val);
624 socklen_t addrlen = sizeof(u);
628 case _Jv_TCP_NODELAY_ :
629 throw new ::java::net::SocketException (
630 JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
632 case _Jv_SO_LINGER_ :
633 throw new ::java::net::SocketException (
634 JvNewStringUTF ("SO_LINGER not valid for UDP"));
636 case _Jv_SO_KEEPALIVE_ :
637 throw new ::java::net::SocketException (
638 JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
641 case _Jv_SO_BROADCAST_ :
642 if (::getsockopt (fnum, SOL_SOCKET, SO_BROADCAST, (char *) &val,
645 return new ::java::lang::Boolean (val != 0);
647 case _Jv_SO_OOBINLINE_ :
648 throw new ::java::net::SocketException (
649 JvNewStringUTF ("SO_OOBINLINE not valid for UDP"));
652 case _Jv_SO_RCVBUF_ :
653 case _Jv_SO_SNDBUF_ :
654 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
656 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
657 if (::getsockopt (fnum, SOL_SOCKET, opt, (char *) &val, &val_len) != 0)
660 return new ::java::lang::Integer (val);
662 throw new ::java::lang::InternalError (
663 JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
666 case _Jv_SO_BINDADDR_:
667 // cache the local address
668 if (localAddress == NULL)
671 if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != 0)
673 if (u.address.sin_family == AF_INET)
675 laddr = JvNewByteArray (4);
676 memcpy (elements (laddr), &u.address.sin_addr, 4);
679 else if (u.address.sin_family == AF_INET6)
681 laddr = JvNewByteArray (16);
682 memcpy (elements (laddr), &u.address6.sin6_addr, 16);
686 throw new ::java::net::SocketException (
687 JvNewStringUTF ("invalid family"));
688 localAddress = new ::java::net::InetAddress (laddr, NULL);
692 case _Jv_SO_REUSEADDR_ :
693 #if defined(SO_REUSEADDR)
694 if (::getsockopt (fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
697 return new ::java::lang::Boolean (val != 0);
699 throw new ::java::lang::InternalError (
700 JvNewStringUTF ("SO_REUSEADDR not supported"));
703 case _Jv_IP_MULTICAST_IF_ :
704 #ifdef HAVE_INET_NTOA
705 struct in_addr inaddr;
706 socklen_t inaddr_len;
709 inaddr_len = sizeof(inaddr);
710 if (::getsockopt (fnum, IPPROTO_IP, IP_MULTICAST_IF, (char *) &inaddr,
714 bytes = inet_ntoa (inaddr);
716 return ::java::net::InetAddress::getByName (JvNewStringLatin1 (bytes));
718 throw new ::java::net::SocketException (
719 JvNewStringUTF ("IP_MULTICAST_IF: not available - no inet_ntoa()"));
722 case _Jv_SO_TIMEOUT_ :
723 return new ::java::lang::Integer (timeout);
726 case _Jv_IP_MULTICAST_IF2_ :
727 throw new ::java::net::SocketException (
728 JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
731 case _Jv_IP_MULTICAST_LOOP_ :
732 if (::getsockopt (fnum, SOL_SOCKET, IP_MULTICAST_LOOP, (char *) &val,
735 return new ::java::lang::Boolean (val != 0);
738 if (::getsockopt (fnum, SOL_SOCKET, IP_TOS, (char *) &val,
741 return new ::java::lang::Integer (val);
748 char* strerr = strerror (errno);
749 throw new ::java::net::SocketException (JvNewStringUTF (strerr));