summaryrefslogtreecommitdiff
path: root/libjava/gnu/java/net/natPlainSocketImplWin32.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/natPlainSocketImplWin32.cc
downloadcbb-gcc-4.6.4-upstream.tar.bz2
cbb-gcc-4.6.4-upstream.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/natPlainSocketImplWin32.cc')
-rw-r--r--libjava/gnu/java/net/natPlainSocketImplWin32.cc796
1 files changed, 796 insertions, 0 deletions
diff --git a/libjava/gnu/java/net/natPlainSocketImplWin32.cc b/libjava/gnu/java/net/natPlainSocketImplWin32.cc
new file mode 100644
index 000000000..9377998f5
--- /dev/null
+++ b/libjava/gnu/java/net/natPlainSocketImplWin32.cc
@@ -0,0 +1,796 @@
+/* Copyright (C) 2003, 2004, 2005, 2006 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>
+
+#undef STRICT
+#undef MAX_PRIORITY
+#undef MIN_PRIORITY
+
+#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/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>
+
+union SockAddr
+{
+ struct sockaddr_in address;
+#ifdef HAVE_INET6
+ struct sockaddr_in6 address6;
+#endif
+};
+
+void
+gnu::java::net::PlainSocketImpl::create (jboolean stream)
+{
+ SOCKET sock = ::socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
+
+ if (sock == INVALID_SOCKET)
+ {
+ _Jv_ThrowIOException ();
+ }
+
+ // Cast this to a HANDLE so we can make
+ // it non-inheritable via _Jv_platform_close_on_exec.
+ HANDLE hSocket = (HANDLE) sock;
+ _Jv_platform_close_on_exec (hSocket);
+
+ // We use native_fd in place of fd here. From leaving fd null we avoid
+ // the double close problem in FileDescriptor.finalize.
+ native_fd = (jint) hSocket;
+}
+
+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;
+
+ if (len == 4)
+ {
+ u.address.sin_family = AF_INET;
+
+ 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);
+ }
+#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"));
+
+ if (::bind (native_fd, ptr, len) != SOCKET_ERROR)
+ {
+ socklen_t addrlen = sizeof(u);
+
+ if (lport != 0)
+ localport = lport;
+ else if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) != SOCKET_ERROR)
+ localport = ntohs (u.address.sin_port);
+ else
+ goto error;
+
+ return;
+ }
+
+error:
+ DWORD dwErrorCode = WSAGetLastError ();
+ throw new ::java::net::BindException (_Jv_WinStrError (dwErrorCode));
+}
+
+static void
+throwConnectException (DWORD dwErrorCode)
+{
+ throw new ::java::net::ConnectException (_Jv_WinStrError (dwErrorCode));
+}
+
+static void
+throwConnectException ()
+{
+ throwConnectException (WSAGetLastError ());
+}
+
+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();
+ 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)
+ {
+ // FIXME: we're creating a fresh WSAEVENT for each connect().
+ WSAEventWrapper aWSAEventWrapper(native_fd, FD_CONNECT);
+ WSAEVENT hEvent = aWSAEventWrapper.getEventHandle ();
+
+ if (::connect (native_fd, ptr, len) == SOCKET_ERROR)
+ {
+ if (WSAGetLastError () != WSAEWOULDBLOCK)
+ throwConnectException ();
+
+ DWORD dwRet =
+ WSAWaitForMultipleEvents (1, &hEvent, true, timeout, false);
+ // use true, false instead of TRUE, FALSE because the
+ // MS constants got undefined
+
+ // Reset and ignore our thread's interrupted flag.
+ // It's not possible to interrupt these sort of
+ // operations on Win32 anyway.
+ ::java::lang::Thread::interrupted();
+
+ if (dwRet == WSA_WAIT_FAILED)
+ throwConnectException ();
+ else if (dwRet == WSA_WAIT_TIMEOUT)
+ throw new ::java::net::SocketTimeoutException
+ (JvNewStringUTF ("connect timed out"));
+
+ // If we get here, we still need to check whether the actual
+ // connect() succeeded. Use any socket-specific error code
+ // instead of the thread-based one.
+ int nErrCode; int nErrLen=sizeof(nErrCode);
+ if (::getsockopt(native_fd, SOL_SOCKET, SO_ERROR, (char*) &nErrCode,
+ &nErrLen) == SOCKET_ERROR)
+ {
+ throwConnectException ();
+ }
+
+ if (nErrCode != NO_ERROR)
+ {
+ throwConnectException (nErrCode);
+ }
+ }
+ }
+ else
+ {
+ if (::connect (native_fd, ptr, len) == SOCKET_ERROR)
+ throwConnectException();
+ }
+
+ // 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) != SOCKET_ERROR)
+ localport = ntohs (u.address.sin_port);
+ else
+ throwConnectException();
+ }
+}
+
+void
+gnu::java::net::PlainSocketImpl::listen (jint backlog)
+{
+ if (::listen (native_fd, backlog) == SOCKET_ERROR)
+ {
+ _Jv_ThrowIOException ();
+ }
+}
+
+void
+gnu::java::net::PlainSocketImpl::accept (gnu::java::net::PlainSocketImpl *s)
+{
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ HANDLE hSocket = 0;
+ SOCKET new_socket = 0;
+
+ if (timeout > 0)
+ {
+ // FIXME: we're creating a fresh WSAEVENT for each accept().
+ // One possible alternative would be that native_fd really points
+ // to an extended structure consisting of the SOCKET, its
+ // associated WSAEVENT, etc.
+ WSAEventWrapper aWSAEventWrapper(native_fd, FD_ACCEPT);
+ WSAEVENT hEvent = aWSAEventWrapper.getEventHandle ();
+
+ for (;;)
+ {
+ new_socket = ::accept (native_fd, (sockaddr*) &u, &addrlen);
+
+ if (new_socket != INVALID_SOCKET)
+ {
+ // This new child socket is nonblocking because the parent
+ // socket became nonblocking via the WSAEventSelect() call,
+ // so we set its mode back to blocking.
+ WSAEventSelect (new_socket, hEvent, 0);
+ // undo the hEvent <-> FD_ACCEPT association inherited
+ // inherited from our parent socket
+
+ unsigned long lSockOpt = 0L;
+ // blocking mode
+ if (ioctlsocket(new_socket, FIONBIO, &lSockOpt) == SOCKET_ERROR)
+ {
+ goto error;
+ }
+ break;
+ }
+ else if (WSAGetLastError () != WSAEWOULDBLOCK)
+ {
+ goto error;
+ }
+
+ DWORD dwRet =
+ WSAWaitForMultipleEvents (1, &hEvent, true, timeout, false);
+ // use true, false instead of TRUE, FALSE because the
+ // MS constants got undefined
+
+ // Reset and ignore our thread's interrupted flag.
+ ::java::lang::Thread::interrupted();
+
+ if (dwRet == WSA_WAIT_FAILED)
+ goto error;
+ else if (dwRet == WSA_WAIT_TIMEOUT)
+ throw new ::java::net::SocketTimeoutException
+ (JvNewStringUTF ("Accept timed out"));
+ }
+ }
+ else
+ {
+ new_socket = ::accept (native_fd, (sockaddr*) &u, &addrlen);
+ }
+
+ if (new_socket == INVALID_SOCKET)
+ goto error;
+
+ // Cast this to a HANDLE so we can make
+ // it non-inheritable via _Jv_platform_close_on_exec.
+ hSocket = (HANDLE) new_socket;
+ _Jv_platform_close_on_exec (hSocket);
+
+ 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 = (jint) hSocket;
+ s->localport = localport;
+ s->address = ::java::net::InetAddress::getByAddress (raddr);
+ s->port = rport;
+ return;
+
+ error:
+ _Jv_ThrowIOException ();
+}
+
+// Close(shutdown) the socket.
+void
+gnu::java::net::PlainSocketImpl::close()
+{
+ // Avoid races from asynchronous finalization.
+ JvSynchronize sync (this);
+
+ // should we use shutdown here? how would that effect so_linger?
+ int res = ::closesocket (native_fd);
+
+ if (res == -1)
+ {
+ // These three errors are not errors according to tests performed
+ // on the reference implementation.
+ DWORD dwErr = WSAGetLastError();
+ if (dwErr != WSAENOTCONN && dwErr != WSAECONNRESET
+ && dwErr != WSAENOTSOCK)
+ _Jv_ThrowIOException ();
+ }
+ // Safe place to reset the file pointer.
+ native_fd = -1;
+ timeout = 0;
+}
+
+// Write a byte to the socket.
+void
+gnu::java::net::PlainSocketImpl$SocketOutputStream::write(jint b)
+{
+ jbyte d =(jbyte) b;
+ int r = 0;
+
+ while (r != 1)
+ {
+ r = ::send (this$0->native_fd, (char*) &d, 1, 0);
+ if (r == -1)
+ {
+ DWORD dwErr = WSAGetLastError();
+
+ // Reset and ignore our thread's interrupted flag.
+ // It's not possible to interrupt these sort of
+ // operations on Win32 anyway.
+ ::java::lang::Thread::interrupted();
+
+ // Some errors should not cause exceptions.
+ if (dwErr != WSAENOTCONN && dwErr != WSAECONNRESET
+ && dwErr != WSAENOTSOCK)
+ _Jv_ThrowIOException ();
+ break;
+ }
+ }
+}
+
+// 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;
+
+ jbyte *bytes = elements (b) + offset;
+ int written = 0;
+ while (len > 0)
+ {
+ int r = ::send (this$0->native_fd, (char*) bytes, len, 0);
+
+ if (r == -1)
+ {
+ DWORD dwErr = WSAGetLastError();
+
+ // Reset and ignore our thread's interrupted flag.
+ ::java::lang::Thread::interrupted();
+
+ // Some errors should not cause exceptions.
+ if (dwErr != WSAENOTCONN && dwErr != WSAECONNRESET
+ && dwErr != WSAENOTSOCK)
+ _Jv_ThrowIOException ();
+ 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"));
+}
+
+// read() helper
+static jint
+doRead(int native_fd, void* buf, int count, int timeout)
+{
+ int r = 0;
+ DWORD dwErrorCode = 0;
+ // we are forced to declare this here because
+ // a call to Thread::interrupted() blanks out
+ // WSAGetLastError().
+
+ // FIXME: we unconditionally set SO_RCVTIMEO here
+ // because we can't detect whether someone has
+ // gone from a non-zero to zero timeout. What we'd
+ // really need is a member state variable in addition
+ // to timeout
+ int nRet= ::setsockopt(native_fd, SOL_SOCKET, SO_RCVTIMEO,
+ (char*)&timeout, sizeof(timeout));
+ if (nRet != NO_ERROR)
+ {
+ dwErrorCode = WSAGetLastError ();
+ goto error;
+ }
+
+ r = ::recv (native_fd, (char*) buf, count, 0);
+
+ if (r == 0)
+ return -1;
+
+ dwErrorCode = WSAGetLastError ();
+ // save WSAGetLastError() before calling Thread.interrupted()
+
+ // Reset and ignore our thread's interrupted flag.
+ ::java::lang::Thread::interrupted();
+
+ if (r == -1)
+ {
+error:
+ // Some errors cause us to return end of stream...
+ if (dwErrorCode == WSAENOTCONN)
+ return -1;
+
+ // Other errors need to be signalled.
+ if (dwErrorCode == WSAETIMEDOUT)
+ throw new ::java::net::SocketTimeoutException
+ (JvNewStringUTF ("Read timed out") );
+ else
+ _Jv_ThrowIOException (dwErrorCode);
+ }
+
+ return r;
+}
+
+// Read a single byte from the socket.
+jint
+gnu::java::net::PlainSocketImpl$SocketInputStream::read(void)
+{
+ jbyte b;
+ doRead(this$0->native_fd, &b, 1, this$0->timeout);
+ return b & 0xFF;
+}
+
+// Read count bytes into the buffer, starting at offset.
+jint
+gnu::java::net::PlainSocketImpl$SocketInputStream::read(jbyteArray buffer,
+ jint offset, jint count)
+{
+ // If zero bytes were requested, short circuit so that recv
+ // doesn't signal EOF.
+ if (count == 0)
+ return 0;
+
+ if (! buffer)
+ throw new ::java::lang::NullPointerException;
+
+ jsize bsize = JvGetArrayLength (buffer);
+
+ if (offset < 0 || count < 0 || offset + count > bsize)
+ throw new ::java::lang::ArrayIndexOutOfBoundsException;
+
+ jbyte *bytes = elements (buffer) + offset;
+
+ // Read the socket.
+ return doRead(this$0->native_fd, bytes, count, this$0->timeout);
+}
+
+// How many bytes are available?
+jint
+gnu::java::net::PlainSocketImpl::available(void)
+{
+ unsigned long num = 0;
+
+ if (::ioctlsocket (native_fd, FIONREAD, &num) == SOCKET_ERROR)
+ _Jv_ThrowIOException ();
+
+ return (jint) num;
+}
+
+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_ :
+ if (::setsockopt (native_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
+ val_len) == SOCKET_ERROR)
+ goto error;
+ return;
+
+ case _Jv_SO_KEEPALIVE_ :
+ if (::setsockopt (native_fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
+ val_len) == SOCKET_ERROR)
+ goto error;
+ break;
+
+ case _Jv_SO_BROADCAST_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("SO_BROADCAST not valid for TCP"));
+ break;
+
+ case _Jv_SO_OOBINLINE_ :
+ if (::setsockopt (native_fd, SOL_SOCKET, SO_OOBINLINE, (char *) &val,
+ val_len) == SOCKET_ERROR)
+ goto error;
+ break;
+
+ case _Jv_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)) == SOCKET_ERROR)
+ goto error;
+ return;
+
+ case _Jv_SO_SNDBUF_ :
+ case _Jv_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) == SOCKET_ERROR)
+ goto error;
+ 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"));
+ 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 (::setsockopt (native_fd, SOL_SOCKET, IP_TOS, (char *) &val,
+ val_len) == SOCKET_ERROR)
+ goto error;
+ break;
+
+ case _Jv_SO_REUSEADDR_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_REUSEADDR: not valid for TCP"));
+ return;
+
+ case _Jv_SO_TIMEOUT_ :
+ timeout = val;
+ return;
+
+ default :
+ WSASetLastError (WSAENOPROTOOPT);
+ }
+
+error:
+ _Jv_ThrowSocketException ();
+}
+
+::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)
+ {
+ case _Jv_TCP_NODELAY_ :
+ if (::getsockopt (native_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
+ &val_len) == SOCKET_ERROR)
+ goto error;
+ else
+ return new ::java::lang::Boolean (val != 0);
+ break;
+
+ case _Jv_SO_LINGER_ :
+ if (::getsockopt (native_fd, SOL_SOCKET, SO_LINGER, (char *) &l_val,
+ &l_val_len) == SOCKET_ERROR)
+ goto error;
+
+ if (l_val.l_onoff)
+ return new ::java::lang::Integer (l_val.l_linger);
+ else
+ return new ::java::lang::Boolean ((jboolean)false);
+ break;
+
+ case _Jv_SO_KEEPALIVE_ :
+ if (::getsockopt (native_fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
+ &val_len) == SOCKET_ERROR)
+ 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) == SOCKET_ERROR)
+ 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) == SOCKET_ERROR)
+ goto error;
+ return new ::java::lang::Boolean ((jboolean)val);
+
+ case _Jv_SO_RCVBUF_ :
+ case _Jv_SO_SNDBUF_ :
+ int opt;
+ optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
+ if (::getsockopt (native_fd, SOL_SOCKET, opt, (char *) &val,
+ &val_len) == SOCKET_ERROR)
+ goto error;
+ else
+ return new ::java::lang::Integer (val);
+ break;
+ case _Jv_SO_BINDADDR_:
+ // cache the local address
+ if (localAddress == NULL)
+ {
+ jbyteArray laddr;
+
+ if (::getsockname (native_fd, (sockaddr*) &u,
+ &addrlen) == SOCKET_ERROR)
+ 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) == SOCKET_ERROR)
+ goto error;
+ return new ::java::lang::Integer (val);
+ break;
+
+ case _Jv_SO_REUSEADDR_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("SO_REUSEADDR: not valid for TCP"));
+ break;
+
+ case _Jv_SO_TIMEOUT_ :
+ return new ::java::lang::Integer (timeout);
+ break;
+
+ default :
+ WSASetLastError (WSAENOPROTOOPT);
+ }
+
+error:
+ _Jv_ThrowSocketException ();
+ return 0;
+ // we should never get here
+}
+
+void
+gnu::java::net::PlainSocketImpl::shutdownInput (void)
+{
+ if (::shutdown (native_fd, 0))
+ _Jv_ThrowSocketException ();
+}
+
+void
+gnu::java::net::PlainSocketImpl::shutdownOutput (void)
+{
+ if (::shutdown (native_fd, 1))
+ _Jv_ThrowSocketException ();
+}