1 /* Copyright (C) 1999, 2000 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
17 #define ENOPROTOOPT 109
20 #ifdef HAVE_SYS_SOCKET_H
21 #include <sys/socket.h>
23 #ifdef HAVE_NETINET_IN_H
24 #include <netinet/in.h>
26 #ifdef HAVE_ARPA_INET_H
27 #include <arpa/inet.h>
34 // Needed for bzero, implicitly used by FD_ZERO on IRIX 5.2
38 #ifndef DISABLE_JAVA_NET
39 // Avoid macro definitions of bind from system headers, e.g. on
40 // Solaris 7 with _XOPEN_SOURCE. FIXME
42 _Jv_bind (int fd, struct sockaddr *addr, int addrlen)
44 return ::bind (fd, addr, addrlen);
46 #endif /* DISABLE_JAVA_NET */
53 #include <java/io/IOException.h>
54 #include <java/io/FileDescriptor.h>
55 #include <java/io/InterruptedIOException.h>
56 #include <java/net/BindException.h>
57 #include <java/net/SocketException.h>
58 #include <java/net/PlainDatagramSocketImpl.h>
59 #include <java/net/InetAddress.h>
60 #include <java/net/DatagramPacket.h>
61 #include <java/lang/InternalError.h>
62 #include <java/lang/Object.h>
63 #include <java/lang/Boolean.h>
64 #include <java/lang/Integer.h>
66 // FIXME: remove these
67 #define BooleanClass java::lang::Boolean::class$
68 #define IntegerClass java::lang::Integer::class$
70 #ifdef DISABLE_JAVA_NET
73 java::net::PlainDatagramSocketImpl::create ()
75 throw new SocketException (
76 JvNewStringLatin1 ("DatagramSocketImpl.create: unimplemented"));
80 java::net::PlainDatagramSocketImpl::bind (jint, java::net::InetAddress *)
82 throw new BindException (
83 JvNewStringLatin1 ("DatagramSocketImpl.bind: unimplemented"));
87 java::net::PlainDatagramSocketImpl::peek (java::net::InetAddress *)
89 throw new java::io::IOException (
90 JvNewStringLatin1 ("DatagramSocketImpl.peek: unimplemented"));
94 java::net::PlainDatagramSocketImpl::send (java::net::DatagramPacket *)
96 throw new java::io::IOException (
97 JvNewStringLatin1 ("DatagramSocketImpl.send: unimplemented"));
101 java::net::PlainDatagramSocketImpl::receive (java::net::DatagramPacket *)
103 throw new java::io::IOException (
104 JvNewStringLatin1 ("DatagramSocketImpl.receive: unimplemented"));
108 java::net::PlainDatagramSocketImpl::setTimeToLive (jint)
110 throw new java::io::IOException (
111 JvNewStringLatin1 ("DatagramSocketImpl.setTimeToLive: unimplemented"));
115 java::net::PlainDatagramSocketImpl::getTimeToLive ()
117 throw new java::io::IOException (
118 JvNewStringLatin1 ("DatagramSocketImpl.getTimeToLive: unimplemented"));
122 java::net::PlainDatagramSocketImpl::mcastGrp (java::net::InetAddress *,
125 throw new java::io::IOException (
126 JvNewStringLatin1 ("DatagramSocketImpl.mcastGrp: unimplemented"));
130 java::net::PlainDatagramSocketImpl::setOption (jint, java::lang::Object *)
132 throw new SocketException (
133 JvNewStringLatin1 ("DatagramSocketImpl.setOption: unimplemented"));
137 java::net::PlainDatagramSocketImpl::getOption (jint)
139 throw new SocketException (
140 JvNewStringLatin1 ("DatagramSocketImpl.getOption: unimplemented"));
143 #else /* DISABLE_JAVA_NET */
145 #ifndef HAVE_SOCKLEN_T
146 typedef int socklen_t;
151 struct sockaddr_in address;
153 struct sockaddr_in6 address6;
159 #if HAVE_STRUCT_IP_MREQ
162 #if HAVE_STRUCT_IPV6_MREQ
163 struct ipv6_mreq mreq6;
171 struct in6_addr addr6;
176 // FIXME: routines here and/or in natPlainSocketImpl.cc could throw
177 // NoRouteToHostException; also consider UnknownHostException, ConnectException.
180 java::net::PlainDatagramSocketImpl::create ()
182 int sock = ::socket (AF_INET, SOCK_DGRAM, 0);
185 char* strerr = strerror (errno);
186 throw new java::net::SocketException (JvNewStringUTF (strerr));
189 fd = new java::io::FileDescriptor (sock);
193 java::net::PlainDatagramSocketImpl::bind (jint lport,
194 java::net::InetAddress *host)
197 struct sockaddr *ptr = (struct sockaddr *) &u.address;
198 // FIXME: Use getaddrinfo() to get actual protocol instead of assuming ipv4.
199 jbyteArray haddress = host->addr;
200 jbyte *bytes = elements (haddress);
201 int len = haddress->length;
205 u.address.sin_family = AF_INET;
207 memcpy (&u.address.sin_addr, bytes, len);
209 u.address.sin_addr.s_addr = htonl (INADDR_ANY);
210 len = sizeof (struct sockaddr_in);
211 u.address.sin_port = htons (lport);
216 u.address6.sin6_family = AF_INET6;
217 memcpy (&u.address6.sin6_addr, bytes, len);
218 len = sizeof (struct sockaddr_in6);
219 u.address6.sin6_port = htons (lport);
223 throw new java::net::SocketException (JvNewStringUTF ("invalid length"));
225 if (_Jv_bind (fnum, ptr, len) == 0)
227 socklen_t addrlen = sizeof(u);
230 else if (::getsockname (fnum, (sockaddr*) &u, &addrlen) == 0)
231 localPort = ntohs (u.address.sin_port);
234 /* Allow broadcast by default. */
236 if (::setsockopt (fnum, SOL_SOCKET, SO_BROADCAST, (char *) &broadcast,
237 sizeof (broadcast)) != 0)
242 char* strerr = strerror (errno);
243 throw new java::net::BindException (JvNewStringUTF (strerr));
247 java::net::PlainDatagramSocketImpl::peek (java::net::InetAddress *i)
249 // FIXME: Deal with Multicast and if the socket is connected.
251 socklen_t addrlen = sizeof(u);
253 ::recvfrom (fnum, (char *) NULL, 0, MSG_PEEK, (sockaddr*) &u,
257 // FIXME: Deal with Multicast addressing and if the socket is connected.
260 if (u.address.sin_family == AF_INET)
262 raddr = JvNewByteArray (4);
263 memcpy (elements (raddr), &u.address.sin_addr, 4);
264 rport = ntohs (u.address.sin_port);
267 else if (u.address.sin_family == AF_INET6)
269 raddr = JvNewByteArray (16);
270 memcpy (elements (raddr), &u.address6.sin6_addr, 16);
271 rport = ntohs (u.address6.sin6_port);
275 throw new java::net::SocketException (JvNewStringUTF ("invalid family"));
280 char* strerr = strerror (errno);
281 throw new java::io::IOException (JvNewStringUTF (strerr));
285 java::net::PlainDatagramSocketImpl::send (java::net::DatagramPacket *p)
287 // FIXME: Deal with Multicast and if the socket is connected.
288 jint rport = p->getPort();
290 jbyteArray haddress = p->getAddress()->addr;
291 jbyte *bytes = elements (haddress);
292 int len = haddress->length;
293 struct sockaddr *ptr = (struct sockaddr *) &u.address;
294 jbyte *dbytes = elements (p->getData());
297 u.address.sin_family = AF_INET;
298 memcpy (&u.address.sin_addr, bytes, len);
299 len = sizeof (struct sockaddr_in);
300 u.address.sin_port = htons (rport);
305 u.address6.sin6_family = AF_INET6;
306 memcpy (&u.address6.sin6_addr, bytes, len);
307 len = sizeof (struct sockaddr_in6);
308 u.address6.sin6_port = htons (rport);
312 throw new java::net::SocketException (JvNewStringUTF ("invalid length"));
314 if (::sendto (fnum, (char *) dbytes, p->getLength(), 0, ptr, len) >= 0)
317 char* strerr = strerror (errno);
318 throw new java::io::IOException (JvNewStringUTF (strerr));
322 java::net::PlainDatagramSocketImpl::receive (java::net::DatagramPacket *p)
324 // FIXME: Deal with Multicast and if the socket is connected.
326 socklen_t addrlen = sizeof(u);
327 jbyte *dbytes = elements (p->getData());
330 // FIXME: implement timeout support for Win32
332 // Do timeouts via select since SO_RCVTIMEO is not always available.
339 tv.tv_sec = timeout / 1000;
340 tv.tv_usec = (timeout % 1000) * 1000;
342 if ((retval = _Jv_select (fnum + 1, &rset, NULL, NULL, &tv)) < 0)
344 else if (retval == 0)
345 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 InetAddress (raddr, NULL));
376 p->setLength ((jint) retlen);
379 char* strerr = strerror (errno);
380 throw new java::io::IOException (JvNewStringUTF (strerr));
384 java::net::PlainDatagramSocketImpl::setTimeToLive (jint ttl)
386 // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
387 char val = (char) ttl;
388 socklen_t val_len = sizeof(val);
389 if (::setsockopt (fnum, IPPROTO_IP, IP_MULTICAST_TTL, &val, val_len) == 0)
392 char* strerr = strerror (errno);
393 throw new java::io::IOException (JvNewStringUTF (strerr));
397 java::net::PlainDatagramSocketImpl::getTimeToLive ()
399 // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
401 socklen_t val_len = sizeof(val);
402 if (::getsockopt (fnum, IPPROTO_IP, IP_MULTICAST_TTL, &val, &val_len) == 0)
403 return ((int) val) & 0xFF;
405 char* strerr = strerror (errno);
406 throw new java::io::IOException (JvNewStringUTF (strerr));
410 java::net::PlainDatagramSocketImpl::mcastGrp (java::net::InetAddress *inetaddr,
414 jbyteArray haddress = inetaddr->addr;
415 jbyte *bytes = elements (haddress);
416 int len = haddress->length;
421 #if HAVE_STRUCT_IP_MREQ
425 opname = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
426 memcpy (&u.mreq.imr_multiaddr, bytes, len);
427 // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
428 // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
429 u.mreq.imr_interface.s_addr = htonl (INADDR_ANY);
430 len = sizeof (struct ip_mreq);
431 ptr = (const char *) &u.mreq;
434 #if HAVE_STRUCT_IPV6_MREQ
437 level = IPPROTO_IPV6;
439 /* Prefer new RFC 2553 names. */
440 #ifndef IPV6_JOIN_GROUP
441 #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
443 #ifndef IPV6_LEAVE_GROUP
444 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
447 opname = join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP;
448 memcpy (&u.mreq6.ipv6mr_multiaddr, bytes, len);
449 // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
450 // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
451 u.mreq6.ipv6mr_interface = 0;
452 len = sizeof (struct ipv6_mreq);
453 ptr = (const char *) &u.mreq6;
457 throw new java::net::SocketException (JvNewStringUTF ("invalid length"));
459 if (::setsockopt (fnum, level, opname, ptr, len) == 0)
462 char* strerr = strerror (errno);
463 throw new java::io::IOException (JvNewStringUTF (strerr));
467 java::net::PlainDatagramSocketImpl::setOption (jint optID,
468 java::lang::Object *value)
471 socklen_t val_len = sizeof (val);
473 if (_Jv_IsInstanceOf (value, &BooleanClass))
475 java::lang::Boolean *boolobj =
476 static_cast<java::lang::Boolean *> (value);
477 val = boolobj->booleanValue() ? 1 : 0;
479 else if (_Jv_IsInstanceOf (value, &IntegerClass))
481 java::lang::Integer *intobj =
482 static_cast<java::lang::Integer *> (value);
483 val = (int) intobj->intValue();
485 // Else assume value to be an InetAddress for use with IP_MULTICAST_IF.
489 case _Jv_TCP_NODELAY_ :
490 throw new java::net::SocketException (
491 JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
493 case _Jv_SO_LINGER_ :
494 throw new java::net::SocketException (
495 JvNewStringUTF ("SO_LINGER not valid for UDP"));
497 case _Jv_SO_SNDBUF_ :
498 case _Jv_SO_RCVBUF_ :
499 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
501 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
502 if (::setsockopt (fnum, SOL_SOCKET, opt, (char *) &val, val_len) != 0)
505 throw new java::lang::InternalError (
506 JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
509 case _Jv_SO_REUSEADDR_ :
510 #if defined(SO_REUSEADDR)
511 if (::setsockopt (fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
515 throw new java::lang::InternalError (
516 JvNewStringUTF ("SO_REUSEADDR not supported"));
519 case _Jv_SO_BINDADDR_ :
520 throw new java::net::SocketException (
521 JvNewStringUTF ("SO_BINDADDR: read only option"));
523 case _Jv_IP_MULTICAST_IF_ :
531 haddress = ((java::net::InetAddress *) value)->addr;
532 bytes = elements (haddress);
533 len = haddress->length;
537 opname = IP_MULTICAST_IF;
538 memcpy (&u.addr, bytes, len);
539 len = sizeof (struct in_addr);
540 ptr = (const char *) &u.addr;
542 // Tru64 UNIX V5.0 has struct sockaddr_in6, but no IPV6_MULTICAST_IF
543 #if defined (HAVE_INET6) && defined (IPV6_MULTICAST_IF)
546 level = IPPROTO_IPV6;
547 opname = IPV6_MULTICAST_IF;
548 memcpy (&u.addr6, bytes, len);
549 len = sizeof (struct in6_addr);
550 ptr = (const char *) &u.addr6;
555 new java::net::SocketException (JvNewStringUTF ("invalid length"));
557 if (::setsockopt (fnum, level, opname, ptr, len) != 0)
560 case _Jv_SO_TIMEOUT_ :
568 char* strerr = strerror (errno);
569 throw new java::net::SocketException (JvNewStringUTF (strerr));
573 java::net::PlainDatagramSocketImpl::getOption (jint optID)
576 socklen_t val_len = sizeof(val);
578 socklen_t addrlen = sizeof(u);
582 case _Jv_TCP_NODELAY_ :
583 throw new java::net::SocketException (
584 JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
587 case _Jv_SO_LINGER_ :
588 throw new java::net::SocketException (
589 JvNewStringUTF ("SO_LINGER not valid for UDP"));
591 case _Jv_SO_RCVBUF_ :
592 case _Jv_SO_SNDBUF_ :
593 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
595 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
596 if (::getsockopt (fnum, SOL_SOCKET, opt, (char *) &val, &val_len) != 0)
599 return new java::lang::Integer (val);
601 throw new java::lang::InternalError (
602 JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
605 case _Jv_SO_BINDADDR_:
606 // cache the local address
607 if (localAddress == NULL)
610 if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != 0)
612 if (u.address.sin_family == AF_INET)
614 laddr = JvNewByteArray (4);
615 memcpy (elements (laddr), &u.address.sin_addr, 4);
618 else if (u.address.sin_family == AF_INET6)
620 laddr = JvNewByteArray (16);
621 memcpy (elements (laddr), &u.address6.sin6_addr, 16);
625 throw new java::net::SocketException (JvNewStringUTF ("invalid family"));
626 localAddress = new java::net::InetAddress (laddr, NULL);
630 case _Jv_SO_REUSEADDR_ :
631 #if defined(SO_REUSEADDR)
632 if (::getsockopt (fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
635 return new java::lang::Boolean (val != 0);
637 throw new java::lang::InternalError (
638 JvNewStringUTF ("SO_REUSEADDR not supported"));
641 case _Jv_IP_MULTICAST_IF_ :
642 #ifdef HAVE_INET_NTOA
643 struct in_addr inaddr;
644 socklen_t inaddr_len;
647 inaddr_len = sizeof(inaddr);
648 if (::getsockopt (fnum, IPPROTO_IP, IP_MULTICAST_IF, (char *) &inaddr,
652 bytes = inet_ntoa (inaddr);
654 return java::net::InetAddress::getByName (JvNewStringLatin1 (bytes));
656 throw new java::net::SocketException (
657 JvNewStringUTF ("IP_MULTICAST_IF: not available - no inet_ntoa()"));
660 case _Jv_SO_TIMEOUT_ :
661 return new java::lang::Integer (timeout);
668 char* strerr = strerror (errno);
669 throw new java::net::SocketException (JvNewStringUTF (strerr));
672 #endif /* DISABLE_JAVA_NET */