summaryrefslogtreecommitdiff
path: root/libjava/gnu/java/net/natPlainSocketImplPosix.cc
diff options
context:
space:
mode:
authorupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
committerupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
commit554fd8c5195424bdbcabf5de30fdc183aba391bd (patch)
tree976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/gnu/java/net/natPlainSocketImplPosix.cc
downloadcbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2
cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository.
Diffstat (limited to 'libjava/gnu/java/net/natPlainSocketImplPosix.cc')
-rw-r--r--libjava/gnu/java/net/natPlainSocketImplPosix.cc868
1 files changed, 868 insertions, 0 deletions
diff --git a/libjava/gnu/java/net/natPlainSocketImplPosix.cc b/libjava/gnu/java/net/natPlainSocketImplPosix.cc
new file mode 100644
index 000000000..e21013bf7
--- /dev/null
+++ b/libjava/gnu/java/net/natPlainSocketImplPosix.cc
@@ -0,0 +1,868 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+#include <config.h>
+#include <platform.h>
+
+#ifdef HAVE_SYS_IOCTL_H
+#define BSD_COMP /* Get FIONREAD on Solaris2. */
+#include <sys/ioctl.h>
+#endif
+
+// Pick up FIONREAD on Solaris 2.5.
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <errno.h>
+#include <string.h>
+
+#if HAVE_BSTRING_H
+// Needed for bzero, implicitly used by FD_ZERO on IRIX 5.2
+#include <bstring.h>
+#endif
+
+#include <gcj/cni.h>
+#include <gcj/javaprims.h>
+#include <gnu/java/net/PlainSocketImpl.h>
+#include <gnu/java/net/PlainSocketImpl$SocketInputStream.h>
+#include <gnu/java/net/PlainSocketImpl$SocketOutputStream.h>
+#include <java/io/IOException.h>
+#include <java/io/InterruptedIOException.h>
+#include <java/net/BindException.h>
+#include <java/net/ConnectException.h>
+#include <java/net/InetAddress.h>
+#include <java/net/InetSocketAddress.h>
+#include <java/net/SocketException.h>
+#include <java/net/SocketTimeoutException.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>
+#include <java/lang/Thread.h>
+#include <java/lang/NullPointerException.h>
+#include <java/lang/ArrayIndexOutOfBoundsException.h>
+#include <java/lang/IllegalArgumentException.h>
+#include <java/net/UnknownHostException.h>
+
+union SockAddr
+{
+ struct sockaddr_in address;
+#ifdef HAVE_INET6
+ struct sockaddr_in6 address6;
+#endif
+};
+
+void
+gnu::java::net::PlainSocketImpl::create (jboolean stream)
+{
+ // We might already have been create()d in the nio case.
+ if (native_fd != -1)
+ return;
+
+ int sock = _Jv_socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
+
+ if (sock < 0)
+ {
+ char* strerr = strerror (errno);
+ throw new ::java::io::IOException (JvNewStringUTF (strerr));
+ }
+
+ // We use native_fd in place of fd here. From leaving fd null we avoid
+ // the double close problem in FileDescriptor.finalize.
+ native_fd = sock;
+}
+
+void
+gnu::java::net::PlainSocketImpl::bind (::java::net::InetAddress *host, jint lport)
+{
+ union SockAddr u;
+ struct sockaddr *ptr = (struct sockaddr *) &u.address;
+ jbyteArray haddress = host->addr;
+ jbyte *bytes = elements (haddress);
+ int len = haddress->length;
+ int i = 1;
+
+ // The following is needed for OS X/PPC, otherwise bind() fails with an
+ // error. I found the issue and following fix on some mailing list, but
+ // no explanation was given as to why this solved the problem.
+ memset (&u, 0, sizeof (u));
+
+ if (len == 4)
+ {
+ u.address.sin_family = AF_INET;
+ memcpy (&u.address.sin_addr, bytes, len);
+ len = sizeof (struct sockaddr_in);
+ u.address.sin_port = htons (lport);
+ }
+#ifdef HAVE_INET6
+ else if (len == 16)
+ {
+ u.address6.sin6_family = AF_INET6;
+ memcpy (&u.address6.sin6_addr, bytes, len);
+ len = sizeof (struct sockaddr_in6);
+ u.address6.sin6_port = htons (lport);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
+
+ // Enable SO_REUSEADDR, so that servers can reuse ports left in TIME_WAIT.
+ ::setsockopt(native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof(i));
+
+ if (_Jv_bind (native_fd, ptr, len) == 0)
+ {
+ socklen_t addrlen = sizeof(u);
+
+ if (lport != 0)
+ localport = lport;
+ else if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) == 0)
+ localport = ntohs (u.address.sin_port);
+ else
+ goto error;
+
+ return;
+ }
+
+ error:
+ char* strerr = strerror (errno);
+ throw new ::java::net::BindException (JvNewStringUTF (strerr));
+}
+
+void
+gnu::java::net::PlainSocketImpl::connect (::java::net::SocketAddress *addr,
+ jint timeout)
+{
+ ::java::net::InetSocketAddress *tmp = (::java::net::InetSocketAddress*) addr;
+ ::java::net::InetAddress *host = tmp->getAddress();
+ if (! host)
+ throw new ::java::net::UnknownHostException(tmp->toString());
+
+ jint rport = tmp->getPort();
+
+ // Set the SocketImpl's address and port fields before we try to
+ // connect. Note that the fact that these are set doesn't imply
+ // that we're actually connected to anything. We need to record
+ // this data before we attempt the connect, since non-blocking
+ // SocketChannels will use this and almost certainly throw timeout
+ // exceptions.
+ address = host;
+ port = rport;
+
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ jbyteArray haddress = host->addr;
+ jbyte *bytes = elements (haddress);
+ int len = haddress->length;
+ struct sockaddr *ptr = (struct sockaddr *) &u.address;
+ if (len == 4)
+ {
+ u.address.sin_family = AF_INET;
+ memcpy (&u.address.sin_addr, bytes, len);
+ len = sizeof (struct sockaddr_in);
+ u.address.sin_port = htons (rport);
+ }
+#ifdef HAVE_INET6
+ else if (len == 16)
+ {
+ u.address6.sin6_family = AF_INET6;
+ memcpy (&u.address6.sin6_addr, bytes, len);
+ len = sizeof (struct sockaddr_in6);
+ u.address6.sin6_port = htons (rport);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
+
+ if (timeout > 0)
+ {
+ int flags = ::fcntl (native_fd, F_GETFL);
+ ::fcntl (native_fd, F_SETFL, flags | O_NONBLOCK);
+
+ if ((_Jv_connect (native_fd, ptr, len) != 0) && (errno != EINPROGRESS))
+ goto error;
+
+ fd_set fset;
+ struct timeval tv;
+ FD_ZERO(&fset);
+ FD_SET(native_fd, &fset);
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ int retval;
+
+ if ((retval = _Jv_select (native_fd + 1, &fset, &fset, NULL, &tv)) < 0)
+ goto error;
+ else if (retval == 0)
+ throw new ::java::net::SocketTimeoutException
+ (JvNewStringUTF ("Connect timed out"));
+ // Set the socket back into a blocking state.
+ ::fcntl (native_fd, F_SETFL, flags);
+ }
+ else
+ {
+ if (_Jv_connect (native_fd, ptr, len) != 0)
+ goto error;
+ }
+
+ // A bind may not have been done on this socket; if so, set localport now.
+ if (localport == 0)
+ {
+ if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) == 0)
+ localport = ntohs (u.address.sin_port);
+ else
+ goto error;
+ }
+
+ return;
+
+ error:
+ char* strerr = strerror (errno);
+ throw new ::java::net::ConnectException (JvNewStringUTF (strerr));
+}
+
+void
+gnu::java::net::PlainSocketImpl::listen (jint backlog)
+{
+ if (::listen (native_fd, backlog) != 0)
+ {
+ char* strerr = strerror (errno);
+ throw new ::java::io::IOException (JvNewStringUTF (strerr));
+ }
+}
+
+static void
+throw_on_sock_closed (gnu::java::net::PlainSocketImpl *soc_impl)
+{
+ // Avoid races from asynchronous close().
+ JvSynchronize sync (soc_impl);
+ if (soc_impl->native_fd == -1)
+ {
+ using namespace java::net;
+ // Socket was closed.
+ SocketException *se =
+ new SocketException (JvNewStringUTF ("Socket Closed"));
+ throw se;
+ }
+}
+
+void
+gnu::java::net::PlainSocketImpl::accept (gnu::java::net::PlainSocketImpl *s)
+{
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ int new_socket = 0;
+
+ // Do timeouts via select since SO_RCVTIMEO is not always available.
+ if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE)
+ {
+ fd_set fset;
+ struct timeval tv;
+ FD_ZERO(&fset);
+ FD_SET(native_fd, &fset);
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ int retval;
+ if ((retval = _Jv_select (native_fd + 1, &fset, &fset, NULL, &tv)) < 0)
+ goto error;
+ else if (retval == 0)
+ throw new ::java::net::SocketTimeoutException (
+ JvNewStringUTF("Accept timed out"));
+ }
+
+ new_socket = _Jv_accept (native_fd, (sockaddr*) &u, &addrlen);
+
+ if (new_socket < 0)
+ goto error;
+
+ 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
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
+
+ s->native_fd = new_socket;
+ s->localport = localport;
+ s->address = ::java::net::InetAddress::getByAddress (raddr);
+ s->port = rport;
+ return;
+
+ error:
+ char* strerr = strerror (errno);
+ throw_on_sock_closed (this);
+ throw new ::java::io::IOException (JvNewStringUTF (strerr));
+}
+
+// Close(shutdown) the socket.
+void
+gnu::java::net::PlainSocketImpl::close()
+{
+ // Avoid races from asynchronous finalization.
+ JvSynchronize sync (this);
+
+ // Should we use shutdown here? Yes.
+ // How would that effect so_linger? Uncertain.
+ ::shutdown (native_fd, 2);
+ // Ignore errors in shutdown as we are closing and all the same
+ // errors are handled in the close.
+ int res = _Jv_close (native_fd);
+
+ if (res == -1)
+ {
+ // These three errors are not errors according to tests performed
+ // on the reference implementation.
+ if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF)
+ throw new ::java::io::IOException (JvNewStringUTF (strerror (errno)));
+ }
+ // Safe place to reset the file pointer.
+ native_fd = -1;
+ timeout = 0;
+}
+
+static void
+write_helper (jint native_fd, jbyte *bytes, jint len);
+
+// Write a byte to the socket.
+void
+gnu::java::net::PlainSocketImpl$SocketOutputStream::write(jint b)
+{
+ jbyte data = (jbyte) b;
+ write_helper (this$0->native_fd, &data, 1);
+}
+
+// Write some bytes to the socket.
+void
+gnu::java::net::PlainSocketImpl$SocketOutputStream::write(jbyteArray b, jint offset, jint len)
+{
+ if (! b)
+ throw new ::java::lang::NullPointerException;
+ if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
+ throw new ::java::lang::ArrayIndexOutOfBoundsException;
+
+ write_helper (this$0->native_fd, elements (b) + offset, len);
+}
+
+static void
+write_helper(jint native_fd, jbyte *bytes, jint len)
+{
+ int written = 0;
+
+ while (len > 0)
+ {
+ int r = _Jv_write (native_fd, bytes, len);
+
+ if (r == -1)
+ {
+ if (::java::lang::Thread::interrupted())
+ {
+ ::java::io::InterruptedIOException *iioe
+ = new ::java::io::InterruptedIOException
+ (JvNewStringLatin1 (strerror (errno)));
+ iioe->bytesTransferred = written;
+ throw iioe;
+ }
+ // Some errors should not cause exceptions.
+ if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF)
+ throw new ::java::io::IOException (JvNewStringUTF (strerror (errno)));
+ break;
+ }
+
+ written += r;
+ len -= r;
+ bytes += r;
+ }
+}
+
+void
+gnu::java::net::PlainSocketImpl::sendUrgentData (jint)
+{
+ throw new ::java::net::SocketException (JvNewStringLatin1 (
+ "PlainSocketImpl: sending of urgent data not supported by this socket"));
+}
+
+static jint
+read_helper (gnu::java::net::PlainSocketImpl *soc_impl,
+ jbyte *bytes, jint count);
+
+// Read a single byte from the socket.
+jint
+gnu::java::net::PlainSocketImpl$SocketInputStream::read(void)
+{
+ jbyte data;
+
+ if (read_helper (this$0, &data, 1) == 1)
+ return data & 0xFF;
+
+ return -1;
+}
+
+// Read count bytes into the buffer, starting at offset.
+jint
+gnu::java::net::PlainSocketImpl$SocketInputStream::read(jbyteArray buffer,
+ jint offset,
+ jint count)
+{
+ if (! buffer)
+ throw new ::java::lang::NullPointerException;
+
+ jsize bsize = JvGetArrayLength (buffer);
+
+ if (offset < 0 || count < 0 || offset + count > bsize)
+ throw new ::java::lang::ArrayIndexOutOfBoundsException;
+
+ return read_helper (this$0, elements (buffer) + offset, count);
+}
+
+static jint
+read_helper (gnu::java::net::PlainSocketImpl *soc_impl,
+ jbyte *bytes, jint count)
+{
+ // If zero bytes were requested, short circuit so that recv
+ // doesn't signal EOF.
+ if (count == 0)
+ return 0;
+
+ // Do timeouts via select.
+ if (soc_impl->timeout > 0
+ && soc_impl->native_fd >= 0
+ && soc_impl->native_fd < FD_SETSIZE)
+ {
+ // Create the file descriptor set.
+ fd_set read_fds;
+ FD_ZERO (&read_fds);
+ FD_SET (soc_impl->native_fd, &read_fds);
+ // Create the timeout struct based on our internal timeout value.
+ struct timeval timeout_value;
+ timeout_value.tv_sec = soc_impl->timeout / 1000;
+ timeout_value.tv_usec =(soc_impl->timeout % 1000) * 1000;
+ // Select on the fds.
+ int sel_retval =
+ _Jv_select (soc_impl->native_fd + 1,
+ &read_fds, NULL, NULL, &timeout_value);
+ // We're only interested in the 0 return.
+ // error returns still require us to try to read
+ // the socket to see what happened.
+ if (sel_retval == 0)
+ {
+ ::java::net::SocketTimeoutException *timeoutException =
+ new ::java::net::SocketTimeoutException
+ (JvNewStringUTF ("Read timed out"));
+ throw timeoutException;
+ }
+ }
+
+ // Read the socket.
+ int r = ::recv (soc_impl->native_fd, (char *) bytes, count, 0);
+
+ if (r == 0)
+ {
+ throw_on_sock_closed (soc_impl);
+ return -1;
+ }
+
+ if (::java::lang::Thread::interrupted())
+ {
+ ::java::io::InterruptedIOException *iioe =
+ new ::java::io::InterruptedIOException
+ (JvNewStringUTF ("Read interrupted"));
+ iioe->bytesTransferred = r == -1 ? 0 : r;
+ throw iioe;
+ }
+ else if (r == -1)
+ {
+ throw_on_sock_closed (soc_impl);
+ // Some errors cause us to return end of stream...
+ if (errno == ENOTCONN)
+ return -1;
+
+ // Other errors need to be signalled.
+ throw new ::java::io::IOException (JvNewStringUTF (strerror (errno)));
+ }
+
+ return r;
+}
+
+// How many bytes are available?
+jint
+gnu::java::net::PlainSocketImpl::available(void)
+{
+#if defined(FIONREAD) || defined(HAVE_SELECT)
+ int num = 0;
+ int r = 0;
+ bool num_set = false;
+
+#if defined(FIONREAD)
+ r = ::ioctl (native_fd, FIONREAD, &num);
+
+ if (r == -1 && errno == ENOTTY)
+ {
+ // If the ioctl doesn't work, we don't care.
+ r = 0;
+ num = 0;
+ }
+ else
+ num_set = true;
+#elif defined(HAVE_SELECT)
+ if (native_fd < 0)
+ {
+ errno = EBADF;
+ r = -1;
+ }
+#endif
+
+ if (r == -1)
+ {
+ posix_error:
+ throw new ::java::io::IOException(JvNewStringUTF(strerror(errno)));
+ }
+
+ // If we didn't get anything we can use select.
+
+#if defined(HAVE_SELECT)
+ if (! num_set)
+ if (! num_set && native_fd >= 0 && native_fd < FD_SETSIZE)
+ {
+ fd_set rd;
+ FD_ZERO (&rd);
+ FD_SET (native_fd, &rd);
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ r = _Jv_select (native_fd + 1, &rd, NULL, NULL, &tv);
+ if(r == -1)
+ goto posix_error;
+ num = r == 0 ? 0 : 1;
+ }
+#endif /* HAVE_SELECT */
+
+ return (jint) num;
+#else
+ throw new ::java::io::IOException (JvNewStringUTF ("unimplemented"));
+#endif
+}
+
+void
+gnu::java::net::PlainSocketImpl::setOption (jint optID, ::java::lang::Object *value)
+{
+ int val;
+ socklen_t val_len = sizeof (val);
+
+ if (native_fd < 0)
+ throw new ::java::net::SocketException (JvNewStringUTF ("Socket closed"));
+
+ if (_Jv_IsInstanceOf (value, &::java::lang::Boolean::class$))
+ {
+ ::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 if (_Jv_IsInstanceOf (value, &::java::lang::Integer::class$))
+ {
+ ::java::lang::Integer *intobj =
+ static_cast< ::java::lang::Integer *> (value);
+ val = (int) intobj->intValue();
+ }
+ else
+ {
+ throw new ::java::lang::IllegalArgumentException (
+ JvNewStringLatin1 ("`value' must be Boolean or Integer"));
+ }
+
+ switch (optID)
+ {
+ case _Jv_TCP_NODELAY_ :
+#ifdef TCP_NODELAY
+ if (::setsockopt (native_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
+ val_len) != 0)
+ goto error;
+#else
+ throw new ::java::lang::InternalError
+ (JvNewStringUTF ("TCP_NODELAY not supported"));
+#endif /* TCP_NODELAY */
+ return;
+
+ case _Jv_SO_KEEPALIVE_ :
+ if (::setsockopt (native_fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
+ val_len) != 0)
+ goto error;
+ return;
+
+ case _Jv_SO_BROADCAST_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("SO_BROADCAST not valid for TCP"));
+ return;
+
+ case _Jv_SO_OOBINLINE_ :
+ if (::setsockopt (native_fd, SOL_SOCKET, SO_OOBINLINE, (char *) &val,
+ val_len) != 0)
+ goto error;
+ 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 (native_fd, SOL_SOCKET, SO_LINGER, (char *) &l_val,
+ sizeof(l_val)) != 0)
+ goto error;
+#else
+ throw 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 (native_fd, SOL_SOCKET, opt, (char *) &val, val_len) != 0)
+ goto error;
+#else
+ throw new ::java::lang::InternalError (
+ JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
+#endif
+ return;
+
+ case _Jv_SO_BINDADDR_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_BINDADDR: read only option"));
+ return;
+
+ case _Jv_IP_MULTICAST_IF_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
+ return;
+
+ case _Jv_IP_MULTICAST_IF2_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
+ return;
+
+ case _Jv_IP_MULTICAST_LOOP_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
+ return;
+
+ case _Jv_IP_TOS_ :
+ if (::setsockopt (native_fd, SOL_SOCKET, IP_TOS, (char *) &val,
+ val_len) != 0)
+ goto error;
+ return;
+
+ case _Jv_SO_REUSEADDR_ :
+#if defined(SO_REUSEADDR)
+ if (::setsockopt (native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
+ val_len) != 0)
+ goto error;
+ return;
+#else
+ throw new ::java::lang::InternalError (
+ JvNewStringUTF ("SO_REUSEADDR not supported"));
+#endif
+
+ case _Jv_SO_TIMEOUT_ :
+ timeout = val;
+ return;
+
+ default :
+ errno = ENOPROTOOPT;
+ }
+
+ error:
+ char* strerr = strerror (errno);
+ throw new ::java::net::SocketException (JvNewStringUTF (strerr));
+}
+
+::java::lang::Object *
+gnu::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 (native_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ else
+ return new ::java::lang::Boolean (val != 0);
+#else
+ throw new ::java::lang::InternalError
+ (JvNewStringUTF ("TCP_NODELAY not supported"));
+#endif
+ break;
+
+ case _Jv_SO_LINGER_ :
+#ifdef SO_LINGER
+ if (::getsockopt (native_fd, 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 ((jboolean)false);
+#else
+ throw new ::java::lang::InternalError
+ (JvNewStringUTF ("SO_LINGER not supported"));
+#endif
+ break;
+
+ case _Jv_SO_KEEPALIVE_ :
+ if (::getsockopt (native_fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ else
+ return new ::java::lang::Boolean (val != 0);
+
+ case _Jv_SO_BROADCAST_ :
+ if (::getsockopt (native_fd, SOL_SOCKET, SO_BROADCAST, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ return new ::java::lang::Boolean ((jboolean)val);
+
+ case _Jv_SO_OOBINLINE_ :
+ if (::getsockopt (native_fd, SOL_SOCKET, SO_OOBINLINE, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ return new ::java::lang::Boolean ((jboolean)val);
+
+ 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 (native_fd, SOL_SOCKET, opt, (char *) &val, &val_len) != 0)
+ goto error;
+ else
+ return new ::java::lang::Integer (val);
+#else
+ throw new ::java::lang::InternalError
+ (JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
+#endif
+ break;
+ case _Jv_SO_BINDADDR_:
+ // cache the local address
+ if (localAddress == NULL)
+ {
+ jbyteArray laddr;
+
+ if (::getsockname (native_fd, (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
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("invalid family"));
+ localAddress = ::java::net::InetAddress::getByAddress (laddr);
+ }
+
+ return localAddress;
+ break;
+ case _Jv_IP_MULTICAST_IF_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
+ break;
+
+ case _Jv_IP_MULTICAST_IF2_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
+ break;
+
+ case _Jv_IP_MULTICAST_LOOP_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
+ break;
+
+ case _Jv_IP_TOS_ :
+ if (::getsockopt (native_fd, SOL_SOCKET, IP_TOS, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ return new ::java::lang::Integer (val);
+ break;
+
+ case _Jv_SO_REUSEADDR_ :
+#if defined(SO_REUSEADDR)
+ if (::getsockopt (native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
+ &val_len) != 0)
+ goto error;
+#else
+ throw new ::java::lang::InternalError (
+ JvNewStringUTF ("SO_REUSEADDR not supported"));
+#endif
+ break;
+
+ case _Jv_SO_TIMEOUT_ :
+ return new ::java::lang::Integer (timeout);
+ break;
+
+ default :
+ errno = ENOPROTOOPT;
+ }
+
+ error:
+ char* strerr = strerror (errno);
+ throw new ::java::net::SocketException (JvNewStringUTF (strerr));
+}
+
+void
+gnu::java::net::PlainSocketImpl::shutdownInput (void)
+{
+ if (::shutdown (native_fd, 0))
+ throw new ::java::net::SocketException (JvNewStringUTF (strerror (errno)));
+}
+
+void
+gnu::java::net::PlainSocketImpl::shutdownOutput (void)
+{
+ if (::shutdown (native_fd, 1))
+ throw new ::java::net::SocketException (JvNewStringUTF (strerror (errno)));
+}