aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWarren Levy <warrenl@cygnus.com>1999-05-28 19:29:53 +0000
committerWarren Levy <warrenl@gcc.gnu.org>1999-05-28 19:29:53 +0000
commit07515641a55ffacad7a289e32702831f54630d07 (patch)
tree2be352b9baec3fecd8a60eda2e771c4cb2819327
parent930248932e3864264cdfe7d40b00a0544f3d4de9 (diff)
downloadgcc-07515641a55ffacad7a289e32702831f54630d07.zip
gcc-07515641a55ffacad7a289e32702831f54630d07.tar.gz
gcc-07515641a55ffacad7a289e32702831f54630d07.tar.bz2
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
-rw-r--r--libjava/ChangeLog30
-rw-r--r--libjava/java/net/DatagramSocket.java48
-rw-r--r--libjava/java/net/MulticastSocket.java10
-rw-r--r--libjava/java/net/PlainDatagramSocketImpl.java7
-rw-r--r--libjava/java/net/PlainSocketImpl.java4
-rw-r--r--libjava/java/net/ServerSocket.java2
-rw-r--r--libjava/java/net/Socket.java14
-rw-r--r--libjava/java/net/natPlainDatagramSocketImpl.cc205
-rw-r--r--libjava/java/net/natPlainSocketImpl.cc61
9 files changed, 327 insertions, 54 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index 030da4d..d611139 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,33 @@
+1999-05-28 Warren Levy <warrenl@cygnus.com>
+
+ * 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 <bryce@albatross.co.nz>
* java/net/DatagramSocket.java (getSoTimeout): Verify class type.
diff --git a/libjava/java/net/DatagramSocket.java b/libjava/java/net/DatagramSocket.java
index 3bfb032..96d9555 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 03a6e6b..6759e3b 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 2a06371..90e296f 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 b8e10ad..17c8071 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 ae1e113..96690fa 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 e4ef2d7..db46db1 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 42abbe1..74de74f 100644
--- a/libjava/java/net/natPlainDatagramSocketImpl.cc
+++ b/libjava/java/net/natPlainDatagramSocketImpl.cc
@@ -10,6 +10,8 @@ details. */
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/select.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdio.h>
@@ -18,12 +20,16 @@ details. */
#include <cni.h>
#include <java/io/IOException.h>
#include <java/io/FileDescriptor.h>
+#include <java/io/InterruptedIOException.h>
#include <java/net/BindException.h>
#include <java/net/SocketException.h>
#include <java/net/PlainDatagramSocketImpl.h>
#include <java/net/InetAddress.h>
#include <java/net/DatagramPacket.h>
+#include <java/lang/InternalError.h>
+#include <java/lang/Object.h>
#include <java/lang/Boolean.h>
+#include <java/lang/Integer.h>
#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<java::lang::Boolean *> (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<java::lang::Integer *> (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 feaaa77..8ad23cb 100644
--- a/libjava/java/net/natPlainSocketImpl.cc
+++ b/libjava/java/net/natPlainSocketImpl.cc
@@ -10,6 +10,8 @@ details. */
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/select.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <errno.h>
@@ -20,6 +22,7 @@ details. */
#include <javaprims.h>
#include <java/io/IOException.h>
#include <java/io/FileDescriptor.h>
+#include <java/io/InterruptedIOException.h>
#include <java/net/BindException.h>
#include <java/net/ConnectException.h>
#include <java/net/PlainSocketImpl.h>
@@ -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;