From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; 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. --- libjava/gnu/java/net/natPlainSocketImplPosix.cc | 868 ++++++++++++++++++++++++ 1 file changed, 868 insertions(+) create mode 100644 libjava/gnu/java/net/natPlainSocketImplPosix.cc (limited to 'libjava/gnu/java/net/natPlainSocketImplPosix.cc') 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 +#include + +#ifdef HAVE_SYS_IOCTL_H +#define BSD_COMP /* Get FIONREAD on Solaris2. */ +#include +#endif + +// Pick up FIONREAD on Solaris 2.5. +#ifdef HAVE_SYS_FILIO_H +#include +#endif + +#include +#include +#include +#include + +#if HAVE_BSTRING_H +// Needed for bzero, implicitly used by FD_ZERO on IRIX 5.2 +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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))); +} -- cgit v1.2.3