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
This commit is contained in:
Warren Levy 1999-05-28 19:29:53 +00:00 committed by Warren Levy
parent 930248932e
commit 07515641a5
9 changed files with 332 additions and 59 deletions

View File

@ -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.

View File

@ -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()

View File

@ -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");

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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_)
{
// 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)
return;
}
else
errno = ENOPROTOOPT;
int val;
socklen_t val_len = sizeof (val);
if ( _Jv_IsInstanceOf(value,
java::lang::Class::forName(JvNewStringUTF("java.lang.Boolean"))))
{
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;
}
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 on;
socklen_t len;
if (::getsockopt (fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
(socklen_t *) &len) == 0)
return new java::lang::Boolean (on == 1);
}
else
errno = ENOPROTOOPT;
int val;
socklen_t val_len = sizeof(val);
union SockAddr u;
socklen_t addrlen = sizeof(u);
switch (optID)
{
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;
}
error:
char msg[100];
char* strerr = strerror (errno);
sprintf (msg, "DatagramSocketImpl.getOption: %.*s", 80, strerr);

View File

@ -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;