| /* Copyright (C) 2003, 2004, 2005 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 = new ::java::net::InetAddress (raddr, NULL); | |
| 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 = new ::java::net::InetAddress (laddr, NULL); | |
| } | |
| 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 (); | |
| } |