From 07515641a55ffacad7a289e32702831f54630d07 Mon Sep 17 00:00:00 2001 From: Warren Levy Date: Fri, 28 May 1999 19:29:53 +0000 Subject: [PATCH] DatagramSocket.java (laddr): Removed. * java/net/DatagramSocket.java (laddr): Removed. (DatagramSocket): Removed attempts to get or set laddr if null. (getLocalAddress): Reimplemented per spec. * java/net/MulticastSocket.java (setTimeToLive): Throw exception when ttl is 0. (joinGroup): Throw NullPointerException if any argument is null. (leaveGroup): ditto. * java/net/PlainDatagramSocketImpl.java: Updated comments. * java/net/PlainSocketImpl.java (timeout): Added. (getInputStream): Added FIXME comment on how to support timeouts for TCP. * java/net/ServerSocket.java (ServerSocket): Added FIXME comment. * java/net/Socket.java: Added FIXME comments to identify conflicting specs between the JCL and JDK 1.2 documents. * java/net/natPlainDatagramSocketImpl.cc (bind): Use INADDR_ANY if host is null. Get localport value resolved by kernel if bind lport is 0. (receive): Implemented support for timeouts in UDP. (setOption): Implemented based on natPlainSocketImpl version. (getOption): ditto. * java/net/natPlainSocketImpl.cc (bind): Get localport value resolved by kernel if bind lport is 0. (connect): Get localport value resolved by kernel if bind wasn't done to set localport. (accept): Implemented support for timeouts for ServerSocket. (setOption): Save value for SO_TIMEOUT. (getOption): Return timeout for SO_TIMEOUT. From-SVN: r27230 --- libjava/ChangeLog | 30 +++ libjava/java/net/DatagramSocket.java | 48 ++-- libjava/java/net/MulticastSocket.java | 10 +- libjava/java/net/PlainDatagramSocketImpl.java | 7 +- libjava/java/net/PlainSocketImpl.java | 4 + libjava/java/net/ServerSocket.java | 2 + libjava/java/net/Socket.java | 14 ++ .../java/net/natPlainDatagramSocketImpl.cc | 205 ++++++++++++++++-- libjava/java/net/natPlainSocketImpl.cc | 61 ++++-- 9 files changed, 327 insertions(+), 54 deletions(-) diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 030da4d11aa..d6111392b68 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,33 @@ +1999-05-28 Warren Levy + + * java/net/DatagramSocket.java (laddr): Removed. + (DatagramSocket): Removed attempts to get or set laddr if null. + (getLocalAddress): Reimplemented per spec. + * java/net/MulticastSocket.java (setTimeToLive): Throw exception + when ttl is 0. + (joinGroup): Throw NullPointerException if any argument is null. + (leaveGroup): ditto. + * java/net/PlainDatagramSocketImpl.java: Updated comments. + * java/net/PlainSocketImpl.java (timeout): Added. + (getInputStream): Added FIXME comment on how to support timeouts + for TCP. + * java/net/ServerSocket.java (ServerSocket): Added FIXME comment. + * java/net/Socket.java: Added FIXME comments to identify + conflicting specs between the JCL and JDK 1.2 documents. + * java/net/natPlainDatagramSocketImpl.cc (bind): Use INADDR_ANY + if host is null. Get localport value resolved by kernel if bind + lport is 0. + (receive): Implemented support for timeouts in UDP. + (setOption): Implemented based on natPlainSocketImpl version. + (getOption): ditto. + * java/net/natPlainSocketImpl.cc (bind): Get localport value + resolved by kernel if bind lport is 0. + (connect): Get localport value resolved by kernel if bind wasn't + done to set localport. + (accept): Implemented support for timeouts for ServerSocket. + (setOption): Save value for SO_TIMEOUT. + (getOption): Return timeout for SO_TIMEOUT. + 1999-05-26 Bryce McKinlay * java/net/DatagramSocket.java (getSoTimeout): Verify class type. diff --git a/libjava/java/net/DatagramSocket.java b/libjava/java/net/DatagramSocket.java index 3bfb0327c49..96d9555590b 100644 --- a/libjava/java/net/DatagramSocket.java +++ b/libjava/java/net/DatagramSocket.java @@ -25,8 +25,6 @@ import java.io.IOException; public class DatagramSocket { DatagramSocketImpl impl; - // FIXME: Shouldn't this be determined by getsockname() instead? - InetAddress laddr; public DatagramSocket() throws SocketException { @@ -53,23 +51,12 @@ public class DatagramSocket impl = (DatagramSocketImpl) Class.forName("java.net." + propVal + "DatagramSocketImpl").newInstance(); impl.create(); - // TBD: if this is right then the same should be done in Socket(). - try - { - if (laddr == null) - laddr = InetAddress.getLocalHost(); - } - catch (UnknownHostException e) - { - throw new BindException(e.getMessage()); - } // For multicasting, set the socket to be reused (Stevens pp. 195-6). if (this instanceof MulticastSocket) impl.setOption(SocketOptions.SO_REUSEADDR, new Boolean(true)); impl.bind(port, laddr); - this.laddr = laddr; } public void close() @@ -79,7 +66,40 @@ public class DatagramSocket public InetAddress getLocalAddress() { - return laddr; + SecurityManager s = System.getSecurityManager(); + // FIXME: JCL p. 510 says this should call checkConnect. But what + // string should be used as the hostname? Maybe this is just a side + // effect of calling InetAddress.getLocalHost. + // + // And is getOption with SO_BINDADDR the right way to get the address? + // Doesn't seem to be since this method doesn't throw a SocketException + // and SO_BINADDR can throw one. + // + // Also see RETURNS section in JCL p. 510 about returning any local + // addr "if the current execution context is not allowed to connect to + // the network interface that is actually bound to this datagram socket." + // How is that done? via InetAddress.getLocalHost? But that throws + // an UnknownHostException and this method doesn't. + // + // if (s != null) + // s.checkConnect("localhost", -1); + try + { + return (InetAddress)impl.getOption(SocketOptions.SO_BINDADDR); + } + catch (SocketException ex) + { + } + + try + { + return InetAddress.getLocalHost(); + } + catch (UnknownHostException ex) + { + // FIXME: This should never happen, so how can we avoid this construct? + return null; + } } public int getLocalPort() diff --git a/libjava/java/net/MulticastSocket.java b/libjava/java/net/MulticastSocket.java index 03a6e6b175c..6759e3bc3ca 100644 --- a/libjava/java/net/MulticastSocket.java +++ b/libjava/java/net/MulticastSocket.java @@ -76,7 +76,7 @@ public class MulticastSocket extends DatagramSocket // JDK1.2 public void setTimeToLive(int ttl) throws IOException { - if (ttl < 0 || ttl > 255) + if (ttl <= 0 || ttl > 255) throw new IllegalArgumentException("Invalid ttl: " + ttl); impl.setTimeToLive(ttl); @@ -84,6 +84,10 @@ public class MulticastSocket extends DatagramSocket public void joinGroup(InetAddress mcastaddr) throws IOException { + // FIXME: We can't currently rely on NullPointerException being + // thrown when we invoke a method on a null object. + if (mcastaddr == null) + throw new NullPointerException("Null address"); if (! mcastaddr.isMulticastAddress()) throw new IOException("Not a Multicast address"); @@ -96,6 +100,10 @@ public class MulticastSocket extends DatagramSocket public void leaveGroup(InetAddress mcastaddr) throws IOException { + // FIXME: We can't currently rely on NullPointerException being + // thrown when we invoke a method on a null object. + if (mcastaddr == null) + throw new NullPointerException("Null address"); if (! mcastaddr.isMulticastAddress()) throw new IOException("Not a Multicast address"); diff --git a/libjava/java/net/PlainDatagramSocketImpl.java b/libjava/java/net/PlainDatagramSocketImpl.java index 2a063717cc5..90e296f1749 100644 --- a/libjava/java/net/PlainDatagramSocketImpl.java +++ b/libjava/java/net/PlainDatagramSocketImpl.java @@ -36,8 +36,11 @@ class PlainDatagramSocketImpl extends DatagramSocketImpl _Jv_SO_RCVBUF_ = SocketOptions.SO_RCVBUF; int fnum = -1; - InetAddress address; // TBD: DatagramSocket.getLocalAddress()? - // FIXME: These values are set/read by setOption/getOption. + + // FIXME: Is this necessary? Could it help w/ DatagramSocket.getLocalAddress? + InetAddress address; + + // These values are set/read by setOption/getOption. int timeout = 0; InetAddress iface = null; int ttl = -1; diff --git a/libjava/java/net/PlainSocketImpl.java b/libjava/java/net/PlainSocketImpl.java index b8e10ad6dc9..17c8071ac39 100644 --- a/libjava/java/net/PlainSocketImpl.java +++ b/libjava/java/net/PlainSocketImpl.java @@ -37,6 +37,9 @@ class PlainSocketImpl extends SocketImpl int fnum = -1; + // This value is set/read by setOption/getOption. + int timeout = 0; + public native void setOption(int optID, Object value) throws SocketException; public native Object getOption(int optID) throws SocketException; @@ -66,6 +69,7 @@ class PlainSocketImpl extends SocketImpl protected InputStream getInputStream() throws IOException { + // FIXME: TODO - Implement class SocketInputStream timeouts in read(); if (in == null) in = new FileInputStream (fd); return in; diff --git a/libjava/java/net/ServerSocket.java b/libjava/java/net/ServerSocket.java index ae1e1135e35..96690faad88 100644 --- a/libjava/java/net/ServerSocket.java +++ b/libjava/java/net/ServerSocket.java @@ -28,6 +28,8 @@ public class ServerSocket public ServerSocket (int port) throws java.io.IOException { + // FIXME: JCL p. 1526 says backlog defaults to 50; is 5 to save space + // or a typo? this(port, 5); } diff --git a/libjava/java/net/Socket.java b/libjava/java/net/Socket.java index e4ef2d7eb88..db46db18e45 100644 --- a/libjava/java/net/Socket.java +++ b/libjava/java/net/Socket.java @@ -42,6 +42,9 @@ public class Socket if (s != null) s.checkConnect(host, port); impl.create(true); + // FIXME: JCL p. 1586 says if localPort is unspecified, bind to any port, + // i.e. '0' and if localAddr is unspecified, use getLocalAddress() as + // that default. JDK 1.2 doc infers not to do a bind. impl.connect(host, port); } @@ -53,6 +56,9 @@ public class Socket if (s != null) s.checkConnect(address.getHostName(), port); impl.create(true); + // FIXME: JCL p. 1586 says if localPort is unspecified, bind to any port, + // i.e. '0' and if localAddr is unspecified, use getLocalAddress() as + // that default. JDK 1.2 doc infers not to do a bind. impl.connect(address, port); } @@ -64,6 +70,7 @@ public class Socket if (s != null) s.checkConnect(host, port); impl.create(true); + // FIXME: JCL p. 1587 says if localAddr is null, use getLocalAddress(). impl.bind(localAddr, localPort); impl.connect(host, port); } @@ -76,6 +83,7 @@ public class Socket if (s != null) s.checkConnect(address.getHostName(), port); impl.create(true); + // FIXME: JCL p. 1587 says if localAddr is null, use getLocalAddress(). impl.bind(localAddr, localPort); impl.connect(address, port); } @@ -91,6 +99,9 @@ public class Socket SecurityManager s = System.getSecurityManager(); if (s != null) s.checkConnect(host, port); + // FIXME: JCL p. 1586 says if localPort is unspecified, bind to any port, + // i.e. '0' and if localAddr is unspecified, use getLocalAddress() as + // that default. JDK 1.2 doc infers not to do a bind. impl.connect(host, port); } @@ -105,6 +116,9 @@ public class Socket SecurityManager s = System.getSecurityManager(); if (s != null) s.checkConnect(host.getHostName(), port); + // FIXME: JCL p. 1586 says if localPort is unspecified, bind to any port, + // i.e. '0' and if localAddr is unspecified, use getLocalAddress() as + // that default. JDK 1.2 doc infers not to do a bind. impl.connect(host, port); } diff --git a/libjava/java/net/natPlainDatagramSocketImpl.cc b/libjava/java/net/natPlainDatagramSocketImpl.cc index 42abbe135db..74de74fd0de 100644 --- a/libjava/java/net/natPlainDatagramSocketImpl.cc +++ b/libjava/java/net/natPlainDatagramSocketImpl.cc @@ -10,6 +10,8 @@ details. */ #include #include +#include +#include #include #include #include @@ -18,12 +20,16 @@ details. */ #include #include #include +#include #include #include #include #include #include +#include +#include #include +#include #ifndef HAVE_SOCKLEN_T typedef int socklen_t; @@ -70,14 +76,25 @@ java::net::PlainDatagramSocketImpl::bind (jint lport, { // FIXME: prob. need to do a setsockopt with SO_BROADCAST to allow multicast. union SockAddr u; - jbyteArray haddress = host->address; - jbyte *bytes = elements (haddress); - int len = haddress->length; struct sockaddr *ptr = (struct sockaddr *) &u.address; + jbyte *bytes = NULL; + // FIXME: Use getaddrinfo() to get actual protocol instead of assuming ipv4. + int len = 4; // Initialize for INADDR_ANY in case host is NULL. + + if (host != NULL) + { + jbyteArray haddress = host->address; + bytes = elements (haddress); + len = haddress->length; + } + if (len == 4) { u.address.sin_family = AF_INET; - memcpy (&u.address.sin_addr, bytes, len); + if (host != NULL) + memcpy (&u.address.sin_addr, bytes, len); + else + u.address.sin_addr.s_addr = htonl (INADDR_ANY); len = sizeof (struct sockaddr_in); u.address.sin_port = htons (lport); } @@ -94,8 +111,15 @@ java::net::PlainDatagramSocketImpl::bind (jint lport, goto error; if (::bind (fnum, ptr, len) == 0) { + // FIXME: Is address really necessary to set? address = host; - localport = lport; + socklen_t addrlen = sizeof(u); + if (lport != 0) + localport = lport; + else if (::getsockname (fnum, (sockaddr*) &u, &addrlen) == 0) + localport = ntohs (u.address.sin_port); + else + goto error; return; } error: @@ -190,7 +214,25 @@ java::net::PlainDatagramSocketImpl::receive (java::net::DatagramPacket *p) union SockAddr u; socklen_t addrlen = sizeof(u); jbyte *dbytes = elements (p->getData()); - ssize_t retlen = + ssize_t retlen = 0; + + // Do timeouts via select since SO_RCVTIMEO is not always available. + if (timeout > 0) + { + fd_set rset; + struct timeval tv; + FD_ZERO(&rset); + FD_SET(fnum, &rset); + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + int retval; + if ((retval = select (fnum + 1, &rset, NULL, NULL, &tv)) < 0) + goto error; + else if (retval == 0) + JvThrow (new java::io::InterruptedIOException ()); + } + + retlen = ::recvfrom (fnum, (char *) dbytes, p->getLength(), 0, (sockaddr*) &u, &addrlen); if (retlen < 0) @@ -288,17 +330,74 @@ void java::net::PlainDatagramSocketImpl::setOption (jint optID, java::lang::Object *value) { - if (optID == _Jv_SO_REUSEADDR_) + int val; + socklen_t val_len = sizeof (val); + + if ( _Jv_IsInstanceOf(value, + java::lang::Class::forName(JvNewStringUTF("java.lang.Boolean")))) { - // FIXME: Is it possible that a Boolean wasn't passed in? - const int on = (((java::lang::Boolean *) value)->booleanValue()) ? 1 : 0; - if (::setsockopt (fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &on, - sizeof (int)) == 0) + java::lang::Boolean *boolobj = + static_cast (value); + val = boolobj->booleanValue() ? 1 : 0; + } + else if ( _Jv_IsInstanceOf(value, + java::lang::Class::forName(JvNewStringUTF("java.lang.Integer")))) + { + java::lang::Integer *intobj = + static_cast (value); + val = (int) intobj->intValue(); + } + // Else assume value to be an InetAddress for use with IP_MULTICAST_IF. + + switch (optID) + { + case _Jv_TCP_NODELAY_ : + JvThrow (new java::net::SocketException ( + JvNewStringUTF ("TCP_NODELAY not valid for UDP"))); + return; + case _Jv_SO_LINGER_ : + JvThrow (new java::net::SocketException ( + JvNewStringUTF ("SO_LINGER not valid for UDP"))); + return; + case _Jv_SO_SNDBUF_ : + case _Jv_SO_RCVBUF_ : +#if defined(SO_SNDBUF) && defined(SO_RCVBUF) + int opt; + optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF; + if (::setsockopt (fnum, SOL_SOCKET, opt, (char *) &val, val_len) != 0) + goto error; +#else + JvThrow (new java::lang::InternalError ( + JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"))); +#endif + return; + case _Jv_SO_REUSEADDR_ : +#if defined(SO_REUSEADDR) + if (::setsockopt (fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &val, + val_len) != 0) + goto error; +#else + JvThrow (new java::lang::InternalError ( + JvNewStringUTF ("SO_REUSEADDR not supported"))); +#endif + return; + case _Jv_SO_BINDADDR_ : + JvThrow (new java::net::SocketException ( + JvNewStringUTF ("SO_BINDADDR: read only option"))); return; + case _Jv_IP_MULTICAST_IF_ : + // FIXME: TODO - Implement IP_MULTICAST_IF. + JvThrow (new java::lang::InternalError ( + JvNewStringUTF ("IP_MULTICAST_IF: option not implemented"))); + return; + case _Jv_SO_TIMEOUT_ : + timeout = val; + return; + default : + errno = ENOPROTOOPT; } - else - errno = ENOPROTOOPT; + error: char msg[100]; char* strerr = strerror (errno); sprintf (msg, "DatagramSocketImpl.setOption: %.*s", 80, strerr); @@ -308,17 +407,81 @@ java::net::PlainDatagramSocketImpl::setOption (jint optID, java::lang::Object * java::net::PlainDatagramSocketImpl::getOption (jint optID) { - if (optID == _Jv_SO_REUSEADDR_) + int val; + socklen_t val_len = sizeof(val); + union SockAddr u; + socklen_t addrlen = sizeof(u); + + switch (optID) { - int on; - socklen_t len; - if (::getsockopt (fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &on, - (socklen_t *) &len) == 0) - return new java::lang::Boolean (on == 1); + case _Jv_TCP_NODELAY_ : + JvThrow (new java::net::SocketException ( + JvNewStringUTF ("TCP_NODELAY not valid for UDP"))); + break; + + case _Jv_SO_LINGER_ : + JvThrow (new java::net::SocketException ( + JvNewStringUTF ("SO_LINGER not valid for UDP"))); + break; + case _Jv_SO_RCVBUF_ : + case _Jv_SO_SNDBUF_ : +#if defined(SO_SNDBUF) && defined(SO_RCVBUF) + int opt; + optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF; + if (::getsockopt (fnum, SOL_SOCKET, opt, (char *) &val, &val_len) != 0) + goto error; + else + return new java::lang::Integer (val); +#else + JvThrow (new java::lang::InternalError ( + JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"))); +#endif + break; + case _Jv_SO_BINDADDR_: + // FIXME: Should cache the laddr as an optimization. + jbyteArray laddr; + if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != 0) + goto error; + if (u.address.sin_family == AF_INET) + { + laddr = JvNewByteArray (4); + memcpy (elements (laddr), &u.address.sin_addr, 4); + } +#ifdef HAVE_INET6 + else if (u.address.sin_family == AF_INET6) + { + laddr = JvNewByteArray (16); + memcpy (elements (laddr), &u.address6.sin6_addr, 16); + } +#endif + else + goto error; + return new java::net::InetAddress (laddr, NULL); + break; + case _Jv_SO_REUSEADDR_ : +#if defined(SO_REUSEADDR) + if (::getsockopt (fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &val, + &val_len) != 0) + goto error; + return new java::lang::Boolean (val != 0); +#else + JvThrow (new java::lang::InternalError ( + JvNewStringUTF ("SO_REUSEADDR not supported"))); +#endif + break; + case _Jv_IP_MULTICAST_IF_ : + // FIXME: TODO - Implement IP_MULTICAST_IF. + JvThrow (new java::lang::InternalError ( + JvNewStringUTF ("IP_MULTICAST_IF: option not implemented"))); + break; + case _Jv_SO_TIMEOUT_ : + return new java::lang::Integer (timeout); + break; + default : + errno = ENOPROTOOPT; } - else - errno = ENOPROTOOPT; + error: char msg[100]; char* strerr = strerror (errno); sprintf (msg, "DatagramSocketImpl.getOption: %.*s", 80, strerr); diff --git a/libjava/java/net/natPlainSocketImpl.cc b/libjava/java/net/natPlainSocketImpl.cc index feaaa779982..8ad23cbab69 100644 --- a/libjava/java/net/natPlainSocketImpl.cc +++ b/libjava/java/net/natPlainSocketImpl.cc @@ -10,6 +10,8 @@ details. */ #include #include +#include +#include #include #include #include @@ -20,6 +22,7 @@ details. */ #include #include #include +#include #include #include #include @@ -87,7 +90,13 @@ java::net::PlainSocketImpl::bind (java::net::InetAddress *host, jint lport) if (::bind (fnum, ptr, len) == 0) { address = host; - localport = lport; + socklen_t addrlen = sizeof(u); + if (lport != 0) + localport = lport; + else if (::getsockname (fnum, (sockaddr*) &u, &addrlen) == 0) + localport = ntohs (u.address.sin_port); + else + goto error; return; } error: @@ -128,9 +137,12 @@ java::net::PlainSocketImpl::connect (java::net::InetAddress *host, jint rport) goto error; address = host; port = rport; - if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != 0) - goto error; - localport = ntohs (u.address.sin_port); + // A bind may not have been done on this socket; if so, set localport now. + if (localport == 0) + if (::getsockname (fnum, (sockaddr*) &u, &addrlen) == 0) + localport = ntohs (u.address.sin_port); + else + goto error; return; error: char msg[100]; @@ -156,7 +168,25 @@ java::net::PlainSocketImpl::accept (java::net::PlainSocketImpl *s) { union SockAddr u; socklen_t addrlen = sizeof(u); - int new_socket = ::accept (fnum, (sockaddr*) &u, &addrlen); + int new_socket = 0; + + // Do timeouts via select since SO_RCVTIMEO is not always available. + if (timeout > 0) + { + fd_set rset; + struct timeval tv; + FD_ZERO(&rset); + FD_SET(fnum, &rset); + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + int retval; + if ((retval = select (fnum + 1, &rset, NULL, NULL, &tv)) < 0) + goto error; + else if (retval == 0) + JvThrow (new java::io::InterruptedIOException ()); + } + + new_socket = ::accept (fnum, (sockaddr*) &u, &addrlen); if (new_socket < 0) goto error; jbyteArray raddr; @@ -260,16 +290,15 @@ java::net::PlainSocketImpl::setOption (jint optID, java::lang::Object *value) JvNewStringUTF ("SO_BINDADDR: read only option"))); return; case _Jv_IP_MULTICAST_IF_ : - JvThrow (new java::lang::InternalError ( + JvThrow (new java::net::SocketException ( JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"))); return; case _Jv_SO_REUSEADDR_ : - JvThrow (new java::lang::InternalError ( - JvNewStringUTF ("SO_REUSEADDR: option not implemented"))); + JvThrow (new java::net::SocketException ( + JvNewStringUTF ("SO_REUSEADDR: not valid for TCP"))); return; case _Jv_SO_TIMEOUT_ : - JvThrow (new java::lang::InternalError ( - JvNewStringUTF ("SO_TIMEOUT: option not implemented"))); + timeout = val; return; default : errno = ENOPROTOOPT; @@ -336,6 +365,7 @@ java::net::PlainSocketImpl::getOption (jint optID) #endif break; case _Jv_SO_BINDADDR_: + // FIXME: Should cache the laddr as an optimization. jbyteArray laddr; if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != 0) goto error; @@ -356,16 +386,15 @@ java::net::PlainSocketImpl::getOption (jint optID) return new java::net::InetAddress (laddr, NULL); break; case _Jv_IP_MULTICAST_IF_ : - JvThrow (new java::lang::InternalError ( - JvNewStringUTF ("IP_MULTICAST_IF: option not implemented"))); + JvThrow (new java::net::SocketException ( + JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"))); break; case _Jv_SO_REUSEADDR_ : - JvThrow (new java::lang::InternalError ( - JvNewStringUTF ("SO_REUSEADDR: option not implemented"))); + JvThrow (new java::net::SocketException ( + JvNewStringUTF ("SO_REUSEADDR: not valid for TCP"))); break; case _Jv_SO_TIMEOUT_ : - JvThrow (new java::lang::InternalError ( - JvNewStringUTF ("SO_TIMEOUT: option not implemented"))); + return new java::lang::Integer (timeout); break; default : errno = ENOPROTOOPT; -- 2.30.2