+1999-05-26 Bryce McKinlay <bryce@albatross.co.nz>
+
+ * java/net/DatagramSocket.java (getSoTimeout): Verify class type.
+ * java/net/DatagramSocketImpl.java (getOption): Made abstract.
+ (setOption): Made abstract.
+ * java/net/PlainDatagramSocketImpl.java: Mirror SocketOptions fields
+ to avoid cpp conflicts in native code.
+ * java/net/PlainSocketImpl.java: Mirror SocketOptions fields to avoid
+ cpp conflicts in native code.
+ * java/net/ServerSocket.java (toString): Prepended "ServerSocket".
+ * java/net/Socket.java (getLocalAddress): Implemented.
+ (setTcpNoDelay): Implemented.
+ (getTcpNoDelay): Implemented.
+ (setSoLinger): Implemented.
+ (getSoLinger): Implemented.
+ (getSoTimeout): Verify class type.
+ (setSendBufferSize): Implemented.
+ (getSendBufferSize): Implemented.
+ (setReceiveBufferSize): Implemented.
+ (getReceiveBufferSize): Implemented.
+ (toString): Prepended "Socket".
+ * java/net/SocketImpl.java (toString): Rewritten.
+ (getOption): Made abstract.
+ (setOption): Made abstract.
+ * java/net/natPlainSocketImpl.cc (connect): Set localport properly.
+ (setOption): Implemented.
+ (getOption): Implemented.
+
+1999-05-26 Warren Levy <warrenl@cygnus.com>
+
+ * java/net/DatagramSocket.java (DatagramSocket): Get local host
+ address when null. Set SO_REUSEADDR for multicasts.
+ (getSoTimeout): Implemented.
+ (setSoTimeout): Implemented.
+ * java/net/DatagramSocketImpl.java: Implement SocketOptions interface.
+ * java/net/MulticastSocket.java (getInterface): Implemented.
+ (setInterface): Implemented.
+ (setTimeToLive): Check for invalid ttl.
+ (joinGroup): Verify multicast address and security.
+ (leaveGroup): Verify multicast address and security.
+ (send): Implemented.
+ * java/net/PlainDatagramSocketImpl.java (timeout): Added.
+ (iface): Added.
+ (ttl): Added.
+ (setOption): Added.
+ (getOption): Added.
+ (mcastGrp): Added.
+ (getTTL): Implemented as non-native.
+ (setTTL): ditto.
+ (join): ditto.
+ (leave): ditto.
+ * java/net/ServerSocket.java (setSoTimeout): Implemented.
+ (getSoTimeout): Implemented.
+ (setSocketFactory): Made synchronized.
+ * java/net/Socket.java (setSoTimeout): Implemented.
+ (getSoTimeout): Implemented.
+ (close): Made synchronized.
+ (setSocketImplFactory): Made synchronized.
+ * java/net/SocketImpl.java: Implement SocketOptions interface.
+ * java/net/natInetAddress.cc: Corrected module name at top of file.
+ * java/net/natPlainDatagramSocketImpl.cc (McastReq): Added union.
+ (bind): Added FIXME.
+ (peek): Implemented.
+ (setTTL): Removed.
+ (getTTL): Removed.
+ (join): Removed.
+ (leave): Removed.
+ (mcastGrp): Added.
+ (setOption): Implemented for SO_REUSEADDR.
+ (getOption): Implemented for SO_REUSEADDR.
+
1999-05-24 Tom Tromey <tromey@cygnus.com>
* java/util/ResourceBundle.java (getBundle): Throw
// TBD: if this is right then the same should be done in Socket().
try
{
- impl.bind(port, laddr == null ? InetAddress.getLocalHost() : laddr);
+ 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 synchronized int getSoTimeout() throws SocketException
{
- // FIXME: TODO - DatagramSocket.getSoTimeout
- throw new SocketException("DatagramSocket.getSoTimeout - not yet implemented");
+ Object timeout = impl.getOption(SocketOptions.SO_TIMEOUT);
+ if (timeout instanceof Integer)
+ return ((Integer)timeout).intValue();
+ else
+ return 0;
}
public synchronized void receive(DatagramPacket p) throws IOException
public synchronized void setSoTimeout(int timeout) throws SocketException
{
- // FIXME: TODO - DatagramSocket.setSoTimeout
- throw new SocketException("DatagramSocket.setSoTimeout - not yet implemented");
+ if (timeout < 0)
+ throw new IllegalArgumentException("Invalid timeout: " + timeout);
+
+ impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
}
// JDK1.2
* Status: Believed complete and correct.
*/
-// JDK1.2: needs to implement SocketOptions.
-// JDK1.2: public abstract class DatagramSocketImpl implements SocketOptions
-public abstract class DatagramSocketImpl
+public abstract class DatagramSocketImpl implements SocketOptions
{
protected int localport;
protected FileDescriptor fd;
protected abstract void join(InetAddress inetaddr) throws IOException;
protected abstract void leave(InetAddress inetaddr) throws IOException;
+ public abstract Object getOption(int optID) throws SocketException;
+ public abstract void setOption(int optID, Object value)
+ throws SocketException;
+
protected FileDescriptor getFileDescriptor()
{
return fd;
public class MulticastSocket extends DatagramSocket
{
// FIXME: the local addr bound to the multicast socket can be reused;
- // unlike unicast sockets. see p.1159 JCL book.
+ // unlike unicast sockets. It binds to any available network interface.
+ // See p.1159 JCL book.
public MulticastSocket() throws IOException
{
public InetAddress getInterface() throws SocketException
{
- // FIXME: TODO - MulticastSocket.getInterface
- throw new SocketException("MulticastSocket.getInterface - not yet implemented");
+ // FIXME: Is it possible that an InetAddress wasn't returned from getOption?
+ return (InetAddress) impl.getOption(SocketOptions.IP_MULTICAST_IF);
}
// Deprecated in JDK1.2
public byte getTTL() throws IOException
{
+ // Use getTTL here rather than getTimeToLive in case we're using an impl
+ // other than the default PlainDatagramSocketImpl and it doesn't have
+ // getTimeToLive yet.
return impl.getTTL();
}
public void setInterface(InetAddress inf) throws SocketException
{
- // FIXME: TODO - MulticastSocket.setInterface
- throw new SocketException("MulticastSocket.setInterface - not yet implemented");
+ impl.setOption(SocketOptions.IP_MULTICAST_IF, inf);
}
// Deprecated in JDK1.2
public void setTTL(byte ttl) throws IOException
{
+ // Use setTTL here rather than setTimeToLive in case we're using an impl
+ // other than the default PlainDatagramSocketImpl and it doesn't have
+ // setTimeToLive yet.
impl.setTTL(ttl);
}
// JDK1.2
public void setTimeToLive(int ttl) throws IOException
{
+ if (ttl < 0 || ttl > 255)
+ throw new IllegalArgumentException("Invalid ttl: " + ttl);
+
impl.setTimeToLive(ttl);
}
public void joinGroup(InetAddress mcastaddr) throws IOException
{
+ if (! mcastaddr.isMulticastAddress())
+ throw new IOException("Not a Multicast address");
+
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkMulticast(mcastaddr);
+
impl.join(mcastaddr);
}
public void leaveGroup(InetAddress mcastaddr) throws IOException
{
+ if (! mcastaddr.isMulticastAddress())
+ throw new IOException("Not a Multicast address");
+
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkMulticast(mcastaddr);
+
impl.leave(mcastaddr);
}
- public void send(DatagramPacket p, byte ttl) throws IOException
+ public synchronized void send(DatagramPacket p, byte ttl) throws IOException
{
- // FIXME: use ttl instead of getTTL() for time to live.
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ {
+ InetAddress addr = p.getAddress();
+ if (addr.isMulticastAddress())
+ s.checkMulticast(addr, ttl);
+ else
+ s.checkConnect(addr.getHostAddress(), p.getPort());
+ }
+
+ int oldttl = impl.getTimeToLive();
+ impl.setTimeToLive(((int) ttl) & 0xFF);
impl.send(p);
+ impl.setTimeToLive(oldttl);
}
}
class PlainDatagramSocketImpl extends DatagramSocketImpl
{
+ // These fields are mirrored for use in native code to avoid cpp conflicts
+ // when the #defines in system header files are the same as the public fields.
+ static final int _Jv_TCP_NODELAY_ = SocketOptions.TCP_NODELAY,
+ _Jv_SO_BINDADDR_ = SocketOptions.SO_BINDADDR,
+ _Jv_SO_REUSEADDR_ = SocketOptions.SO_REUSEADDR,
+ _Jv_IP_MULTICAST_IF_ = SocketOptions.IP_MULTICAST_IF,
+ _Jv_SO_LINGER_ = SocketOptions.SO_LINGER,
+ _Jv_SO_TIMEOUT_ = SocketOptions.SO_TIMEOUT,
+ _Jv_SO_SNDBUF_ = SocketOptions.SO_SNDBUF,
+ _Jv_SO_RCVBUF_ = SocketOptions.SO_RCVBUF;
+
int fnum = -1;
InetAddress address; // TBD: DatagramSocket.getLocalAddress()?
+ // FIXME: These values are set/read by setOption/getOption.
+ int timeout = 0;
+ InetAddress iface = null;
+ int ttl = -1;
// FIXME: Probably should have bind (and create?) calls from DatagramSocket
// constuctor. If so, then same change should be made to the corresponding
// Socket (non-datagram) classes. This allows the implementation more
- // compleete control over how the socket is set up and used (e.g. connect,
+ // complete control over how the socket is set up and used (e.g. connect,
// setting options, etc.).
public PlainDatagramSocketImpl()
{
throws SocketException;
protected native void create() throws SocketException;
protected native int peek(InetAddress i) throws IOException;
- protected native void setTTL(byte ttl) throws IOException;
- protected native byte getTTL() throws IOException;
protected native void setTimeToLive(int ttl) throws IOException;
protected native int getTimeToLive() throws IOException;
- protected native void join(InetAddress inetaddr) throws IOException;
- protected native void leave(InetAddress inetaddr) throws IOException;
protected native void send(DatagramPacket p) throws IOException;
protected native void receive(DatagramPacket p) throws IOException;
+ public native void setOption(int optID, Object value) throws SocketException;
+ public native Object getOption(int optID) throws SocketException;
+ private native void mcastGrp(InetAddress inetaddr, boolean join)
+ throws IOException;
protected void close() throws IOException
{
fd.close();
}
+
+ // Deprecated in JDK 1.2.
+ protected byte getTTL() throws IOException
+ {
+ return (byte) getTimeToLive();
+ }
+
+ // Deprecated in JDK 1.2.
+ protected void setTTL(byte ttl) throws IOException
+ {
+ setTimeToLive(((int) ttl) & 0xFF);
+ }
+
+ protected void join(InetAddress inetaddr) throws IOException
+ {
+ mcastGrp(inetaddr, true);
+ }
+
+ protected void leave(InetAddress inetaddr) throws IOException
+ {
+ mcastGrp(inetaddr, false);
+ }
}
class PlainSocketImpl extends SocketImpl
{
+ // These fields are mirrored for use in native code to avoid cpp conflicts
+ // when the #defines in system header files are the same as the public fields.
+ static final int _Jv_TCP_NODELAY_ = SocketOptions.TCP_NODELAY,
+ _Jv_SO_BINDADDR_ = SocketOptions.SO_BINDADDR,
+ _Jv_SO_REUSEADDR_ = SocketOptions.SO_REUSEADDR,
+ _Jv_IP_MULTICAST_IF_ = SocketOptions.IP_MULTICAST_IF,
+ _Jv_SO_LINGER_ = SocketOptions.SO_LINGER,
+ _Jv_SO_TIMEOUT_ = SocketOptions.SO_TIMEOUT,
+ _Jv_SO_SNDBUF_ = SocketOptions.SO_SNDBUF,
+ _Jv_SO_RCVBUF_ = SocketOptions.SO_RCVBUF;
+
int fnum = -1;
+ public native void setOption(int optID, Object value) throws SocketException;
+
+ public native Object getOption(int optID) throws SocketException;
+
protected native void create (boolean stream) throws IOException;
protected void connect (String host, int port) throws IOException
-// Socket.java
+// ServerSocket.java
/* Copyright (C) 1999 Cygnus Solutions
*/
/** Written using on-line Java Platform 1.2 API Specification.
- * Status: I believe all methods are implemented, but many
- * of them just throw an exception.
+ * Status: I believe all methods are implemented.
*/
package java.net;
impl.close();
}
- public void setSoTimeout (int timeout) throws SocketException
+ public synchronized void setSoTimeout (int timeout) throws SocketException
{
- throw new InternalError("ServerSocket.setSoTimeout not implemented");
+ if (timeout < 0)
+ throw new IllegalArgumentException("Invalid timeout: " + timeout);
+
+ impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
}
- public int getSoTimeout () throws SocketException
+ public synchronized int getSoTimeout () throws SocketException
{
- throw new InternalError("ServerSocket.getSoTimeout not implemented");
+ Object timeout = impl.getOption(SocketOptions.SO_TIMEOUT);
+ if (timeout instanceof Integer)
+ return ((Integer)timeout).intValue();
+ else
+ return 0;
}
public String toString ()
{
- return impl.toString();
+ return "ServerSocket" + impl.toString();
}
- public static void setSocketFactory (SocketImplFactory fac)
+ public static synchronized void setSocketFactory (SocketImplFactory fac)
throws IOException
{
factory = fac;
}
-
}
*/
/** Written using on-line Java Platform 1.2 API Specification.
- * Status: I believe all methods are implemented, but many
- * of them just throw an exception.
+ * Status: I believe all methods are implemented.
*/
package java.net;
public InetAddress getLocalAddress ()
{
- // There doesn't seem to be any way to implement this
- // using a (generic) SocketImpl ... What am I missing?
- throw new InternalError("Socket.getLocalAddres not implemented");
+ InetAddress localAddress;
+ try
+ {
+ localAddress = (InetAddress)impl.getOption(SocketOptions.SO_BINDADDR);
+ }
+ catch (SocketException x)
+ {
+ // (hopefully) shouldn't happen
+ System.err.println(x);
+ throw new java.lang.InternalError("Error in PlainSocketImpl.getOption");
+ }
+ return localAddress;
}
public int getPort ()
public void setTcpNoDelay (boolean on) throws SocketException
{
- throw new InternalError("Socket.setTcpNoDelay not implemented");
+ impl.setOption( SocketOptions.TCP_NODELAY, new Boolean(on) );
}
public boolean getTcpNoDelay() throws SocketException
{
- throw new InternalError("Socket.getTcpNoDelay not implemented");
+ Boolean bool = (Boolean)impl.getOption( SocketOptions.TCP_NODELAY );
+ return bool.booleanValue();
}
public void setSoLinger(boolean on, int linger) throws SocketException
{
- throw new InternalError("Socket.setSoLinger not implemented");
+ if ( on && (linger >= 0) )
+ {
+ if (linger > 65535)
+ linger = 65535;
+ impl.setOption( SocketOptions.SO_LINGER, new Integer(linger) );
+ }
+ else if ( on && (linger < 0) )
+ throw new IllegalArgumentException("SO_LINGER must be >= 0");
+ else
+ impl.setOption( SocketOptions.SO_LINGER, new Boolean(false) );
}
public int getSoLinger() throws SocketException
{
- throw new InternalError("Socket.getSoLinger not implemented");
+ Object linger = impl.getOption(SocketOptions.SO_LINGER);
+ if (linger instanceof Integer)
+ return ((Integer)linger).intValue();
+ else
+ return -1;
}
- public void setSoTimeout (int timeout) throws SocketException
+ public synchronized void setSoTimeout (int timeout) throws SocketException
{
- throw new InternalError("Socket.setSoTimeout not implemented");
+ if (timeout < 0)
+ throw new IllegalArgumentException("Invalid timeout: " + timeout);
+
+ impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
}
- public int getSoTimeout () throws SocketException
+ public synchronized int getSoTimeout () throws SocketException
{
- throw new InternalError("Socket.getSoTimeout not implemented");
+ Object timeout = impl.getOption(SocketOptions.SO_TIMEOUT);
+ if (timeout instanceof Integer)
+ return ((Integer)timeout).intValue();
+ else
+ return 0;
}
+ // JDK1.2
public void setSendBufferSize (int size) throws SocketException
{
- throw new InternalError("Socket.setSendBufferSize not implemented");
+ if (size <= 0)
+ throw new IllegalArgumentException("Invalid buffer size: " + size);
+
+ impl.setOption(SocketOptions.SO_SNDBUF, new Integer(size));
}
+ // JDK1.2
public int getSendBufferSize () throws SocketException
{
- throw new InternalError("Socket.getSendBufferSize not implemented");
+ Integer buf = (Integer)impl.getOption(SocketOptions.SO_SNDBUF);
+ return buf.intValue();
}
+ // JDK1.2
public void setReceiveBufferSize (int size) throws SocketException
{
- throw new InternalError("Socket.setReceiveBufferSize not implemented");
+ if (size <= 0)
+ throw new IllegalArgumentException("Invalid buffer size: " + size);
+
+ impl.setOption(SocketOptions.SO_RCVBUF, new Integer(size));
}
+ // JDK1.2
public int getReceiveBufferSize () throws SocketException
{
- throw new InternalError("Socket.getReceiveBufferSize not implemented");
+ Integer buf = (Integer)impl.getOption(SocketOptions.SO_RCVBUF);
+ return buf.intValue();
}
- public void close () throws IOException
+ public synchronized void close () throws IOException
{
impl.close();
}
public String toString ()
{
- return impl.toString();
+ return "Socket" + impl.toString();
}
- public static void setSocketImplFactory (SocketImplFactory fac)
+ public static synchronized void setSocketImplFactory (SocketImplFactory fac)
throws IOException
{
factory = fac;
*/
/** Written using on-line Java Platform 1.2 API Specification.
- * Believed complete and correct, except for implementation of toString.
+ * Believed complete and correct.
*/
-// JDK1.2: needs to implement SocketOptions.
-// JDK1.2: public abstract class SocketImpl implements SocketOptions
-public abstract class SocketImpl
+public abstract class SocketImpl implements SocketOptions
{
protected InetAddress address;
protected int getLocalPort () { return localport; }
+ public abstract Object getOption(int optID) throws SocketException;
+
+ public abstract void setOption(int optID, Object value)
+ throws SocketException;
+
public String toString ()
{
- return super.toString(); // FIXME
+ return "[addr=" + address.toString() + ",port=" + Integer.toString(port) +
+ ",localport=" + Integer.toString(localport) + "]";
}
}
public static final int SO_LINGER = 0x80;
public static final int SO_TIMEOUT = 0x1006;
-// JDK1.2
+ // JDK1.2
public static final int SO_SNDBUF = 0x1001;
-// JDK1.2
+ // JDK1.2
public static final int SO_RCVBUF = 0x1002;
public void setOption(int optID, Object value) throws SocketException;
-// natClass.cc - Implementation of java.lang.Class native methods.
+// natInetAddress.cc
/* Copyright (C) 1998, 1999 Cygnus Solutions
#include <java/net/PlainDatagramSocketImpl.h>
#include <java/net/InetAddress.h>
#include <java/net/DatagramPacket.h>
+#include <java/lang/Boolean.h>
#ifndef HAVE_SOCKLEN_T
typedef int socklen_t;
#endif
};
+union McastReq
+{
+ struct ip_mreq mreq;
+#ifdef HAVE_INET6
+ struct ipv6_mreq mreq6;
+#endif
+};
+
+
// FIXME: routines here and/or in natPlainSocketImpl.cc could throw
// NoRouteToHostException; also consider UnknownHostException, ConnectException.
java::net::PlainDatagramSocketImpl::bind (jint lport,
java::net::InetAddress *host)
{
+ // FIXME: prob. need to do a setsockopt with SO_BROADCAST to allow multicast.
union SockAddr u;
jbyteArray haddress = host->address;
jbyte *bytes = elements (haddress);
jint
java::net::PlainDatagramSocketImpl::peek (java::net::InetAddress *i)
{
- // FIXME: TODO - PlainDatagramSocketImpl::peek
- // throws IOException;
- return 0;
+ // FIXME: Deal with Multicast and if the socket is connected.
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ ssize_t retlen =
+ ::recvfrom (fnum, (char *) NULL, 0, MSG_PEEK, (sockaddr*) &u,
+ &addrlen);
+ if (retlen < 0)
+ goto error;
+ // FIXME: Deal with Multicast addressing and if the socket is connected.
+ jbyteArray raddr;
+ jint rport;
+ if (u.address.sin_family == AF_INET)
+ {
+ raddr = JvNewByteArray (4);
+ memcpy (elements (raddr), &u.address.sin_addr, 4);
+ rport = ntohs (u.address.sin_port);
+ }
+#ifdef HAVE_INET6
+ else if (u.address.sin_family == AF_INET6)
+ {
+ raddr = JvNewByteArray (16);
+ memcpy (elements (raddr), &u.address6.sin6_addr, 16);
+ rport = ntohs (u.address6.sin6_port);
+ }
+#endif
+ else
+ goto error;
+ // FIXME: Multicast: s->address = new InetAddress (raddr, NULL);
+ i->address = raddr;
+ return rport;
+ error:
+ char msg[100];
+ char* strerr = strerror (errno);
+ sprintf (msg, "DatagramSocketImpl.peek: %.*s", 80, strerr);
+ JvThrow (new java::io::IOException (JvNewStringUTF (msg)));
}
void
}
void
-java::net::PlainDatagramSocketImpl::setTTL (jbyte ttl)
-{
- // FIXME: TODO - :PlainDatagramSocketImpl::setTTL
- // throws IOException;
-}
-
-jbyte
-java::net::PlainDatagramSocketImpl::getTTL ()
-{
- // FIXME: TODO - PlainDatagramSocketImpl::getTTL
- // throws IOException;
- return 0;
-}
-
-void
java::net::PlainDatagramSocketImpl::setTimeToLive (jint ttl)
{
// throws IOException;
}
void
-java::net::PlainDatagramSocketImpl::join (java::net::InetAddress *inetaddr)
+java::net::PlainDatagramSocketImpl::mcastGrp (java::net::InetAddress *inetaddr,
+ jboolean join)
{
- // throws IOException;
- // FIXME: TODO - PlainDatagramSocketImpl::join
+ union McastReq u;
+ jbyteArray haddress = inetaddr->address;
+ jbyte *bytes = elements (haddress);
+ int len = haddress->length;
+ int level, opname;
+ const char *ptr;
+ if (len == 4)
+ {
+ level = IPPROTO_IP;
+ opname = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
+ memcpy (&u.mreq.imr_multiaddr, bytes, len);
+ // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
+ u.mreq.imr_interface.s_addr = htonl (INADDR_ANY);
+ len = sizeof (struct ip_mreq);
+ ptr = (const char *) &u.mreq;
+ }
+#ifdef HAVE_INET6
+ else if (len == 16)
+ {
+ level = IPPROTO_IPV6;
+ opname = join ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
+ memcpy (&u.mreq6.ipv6mr_multiaddr, bytes, len);
+ // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
+ u.mreq6.ipv6mr_interface = 0;
+ len = sizeof (struct ipv6_mreq);
+ ptr = (const char *) &u.mreq6;
+ }
+#endif
+ else
+ goto error;
+ if (::setsockopt (fnum, level, opname, ptr, len) == 0)
+ return;
+ error:
+ char msg[100];
+ char* strerr = strerror (errno);
+ sprintf (msg, "DatagramSocketImpl.%s: %.*s", join ? "join" : "leave", 80,
+ strerr);
+ JvThrow (new java::io::IOException (JvNewStringUTF (msg)));
}
void
-java::net::PlainDatagramSocketImpl::leave (java::net::InetAddress *inetaddr)
+java::net::PlainDatagramSocketImpl::setOption (jint optID,
+ java::lang::Object *value)
{
- // throws IOException;
- // FIXME: TODO - PlainDatagramSocketImpl::leave
+ 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;
+
+ char msg[100];
+ char* strerr = strerror (errno);
+ sprintf (msg, "DatagramSocketImpl.setOption: %.*s", 80, strerr);
+ JvThrow (new java::net::SocketException (JvNewStringUTF (msg)));
+}
+
+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;
+
+ char msg[100];
+ char* strerr = strerror (errno);
+ sprintf (msg, "DatagramSocketImpl.getOption: %.*s", 80, strerr);
+ JvThrow (new java::net::SocketException (JvNewStringUTF (msg)));
}
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <cni.h>
+#include <javaprims.h>
#include <java/io/IOException.h>
#include <java/io/FileDescriptor.h>
#include <java/net/BindException.h>
#include <java/net/ConnectException.h>
#include <java/net/PlainSocketImpl.h>
#include <java/net/InetAddress.h>
+#include <java/net/SocketException.h>
+#include <java/lang/InternalError.h>
+#include <java/lang/Object.h>
+#include <java/lang/Boolean.h>
+#include <java/lang/Class.h>
+#include <java/lang/Integer.h>
#ifndef HAVE_SOCKLEN_T
typedef int socklen_t;
java::net::PlainSocketImpl::connect (java::net::InetAddress *host, jint rport)
{
union SockAddr u;
+ socklen_t addrlen = sizeof(u);
jbyteArray haddress = host->address;
jbyte *bytes = elements (haddress);
int len = haddress->length;
#endif
else
goto error;
- if (::connect (fnum, ptr, len) == 0)
- {
- address = host;
- port = rport;
- return;
- }
+ if (::connect (fnum, ptr, len) != 0)
+ goto error;
+ address = host;
+ port = rport;
+ if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != 0)
+ goto error;
+ localport = ntohs (u.address.sin_port);
+ return;
error:
char msg[100];
char* strerr = strerror (errno);
sprintf (msg, "SocketImpl.accept: %.*s", 80, strerr);
JvThrow (new java::io::IOException (JvNewStringUTF (msg)));
}
+
+void
+java::net::PlainSocketImpl::setOption (jint optID, java::lang::Object *value)
+{
+ 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);
+ if (boolobj->booleanValue())
+ val = 1;
+ else
+ {
+ if (optID == _Jv_SO_LINGER_)
+ val = -1;
+ else
+ val = 0;
+ }
+ }
+ else // assume value is an Integer
+ {
+ java::lang::Integer *intobj =
+ static_cast<java::lang::Integer *> (value);
+ val = (int) intobj->intValue();
+ }
+
+ switch (optID)
+ {
+ case _Jv_TCP_NODELAY_ :
+#ifdef TCP_NODELAY
+ if (::setsockopt (fnum, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
+ val_len) != 0)
+ goto error;
+#else
+ JvThrow (new java::lang::InternalError (
+ JvNewStringUTF ("TCP_NODELAY not supported")));
+#endif /* TCP_NODELAY */
+ return;
+ case _Jv_SO_LINGER_ :
+#ifdef SO_LINGER
+ struct linger l_val;
+ l_val.l_onoff = (val != -1);
+ l_val.l_linger = val;
+ if (::setsockopt (fnum, SOL_SOCKET, SO_LINGER, (char *) &l_val,
+ sizeof(l_val)) != 0)
+ goto error;
+#else
+ JvThrow (new java::lang::InternalError (
+ JvNewStringUTF ("SO_LINGER not supported")));
+#endif /* SO_LINGER */
+ 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_BINDADDR_ :
+ JvThrow (new java::net::SocketException (
+ JvNewStringUTF ("SO_BINDADDR: read only option")));
+ return;
+ case _Jv_IP_MULTICAST_IF_ :
+ JvThrow (new java::lang::InternalError (
+ JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP")));
+ return;
+ case _Jv_SO_REUSEADDR_ :
+ JvThrow (new java::lang::InternalError (
+ JvNewStringUTF ("SO_REUSEADDR: option not implemented")));
+ return;
+ case _Jv_SO_TIMEOUT_ :
+ JvThrow (new java::lang::InternalError (
+ JvNewStringUTF ("SO_TIMEOUT: option not implemented")));
+ return;
+ default :
+ errno = ENOPROTOOPT;
+ }
+
+ error:
+ char msg[100];
+ char* strerr = strerror (errno);
+ sprintf (msg, "SocketImpl.setOption: %.*s", 80, strerr);
+ JvThrow (new java::net::SocketException (JvNewStringUTF (msg)));
+}
+
+java::lang::Object *
+java::net::PlainSocketImpl::getOption (jint optID)
+{
+ int val;
+ socklen_t val_len = sizeof(val);
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ struct linger l_val;
+ socklen_t l_val_len = sizeof(l_val);
+
+ switch (optID)
+ {
+#ifdef TCP_NODELAY
+ case _Jv_TCP_NODELAY_ :
+ if (::getsockopt (fnum, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ else
+ return new java::lang::Boolean (val != 0);
+#else
+ JvThrow (new java::lang::InternalError (
+ JvNewStringUTF ("TCP_NODELAY not supported")));
+#endif
+ break;
+
+ case _Jv_SO_LINGER_ :
+#ifdef SO_LINGER
+ if (::getsockopt (fnum, SOL_SOCKET, SO_LINGER, (char *) &l_val,
+ &l_val_len) != 0)
+ goto error;
+ if (l_val.l_onoff)
+ return new java::lang::Integer (l_val.l_linger);
+ else
+ return new java::lang::Boolean (false);
+#else
+ JvThrow (new java::lang::InternalError (
+ JvNewStringUTF ("SO_LINGER not supported")));
+#endif
+ 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_:
+ 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_IP_MULTICAST_IF_ :
+ JvThrow (new java::lang::InternalError (
+ JvNewStringUTF ("IP_MULTICAST_IF: option not implemented")));
+ break;
+ case _Jv_SO_REUSEADDR_ :
+ JvThrow (new java::lang::InternalError (
+ JvNewStringUTF ("SO_REUSEADDR: option not implemented")));
+ break;
+ case _Jv_SO_TIMEOUT_ :
+ JvThrow (new java::lang::InternalError (
+ JvNewStringUTF ("SO_TIMEOUT: option not implemented")));
+ break;
+ default :
+ errno = ENOPROTOOPT;
+ }
+
+ error:
+ char msg[100];
+ char* strerr = strerror (errno);
+ sprintf (msg, "SocketImpl.getOption: %.*s", 80, strerr);
+ JvThrow (new java::net::SocketException (JvNewStringUTF (msg)));
+}