Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/ikvm-fork.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjfrijters <jfrijters>2011-08-25 09:01:20 +0400
committerjfrijters <jfrijters>2011-08-25 09:01:20 +0400
commit0fe529afda3c3b1c2dc488f5037e63ae3e85e340 (patch)
treebe159a54f772757c9a1cd19a851e9cd8e958aa37 /openjdk/java/net
parentadf4ee1fb7f69255a2bf107152711997af66c494 (diff)
Prepare for forking.
Diffstat (limited to 'openjdk/java/net')
-rw-r--r--openjdk/java/net/DualStackPlainDatagramSocketImpl.java265
-rw-r--r--openjdk/java/net/DualStackPlainDatagramSocketImpl_c.java496
-rw-r--r--openjdk/java/net/DualStackPlainSocketImpl.java276
-rw-r--r--openjdk/java/net/DualStackPlainSocketImpl_c.java478
4 files changed, 1515 insertions, 0 deletions
diff --git a/openjdk/java/net/DualStackPlainDatagramSocketImpl.java b/openjdk/java/net/DualStackPlainDatagramSocketImpl.java
new file mode 100644
index 00000000..7533dea1
--- /dev/null
+++ b/openjdk/java/net/DualStackPlainDatagramSocketImpl.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+import java.io.IOException;
+import java.io.FileDescriptor;
+import sun.misc.SharedSecrets;
+import sun.misc.JavaIOFileDescriptorAccess;
+
+/**
+ * This class defines the plain DatagramSocketImpl that is used on
+ * Windows platforms greater than or equal to Windows Vista. These
+ * platforms have a dual layer TCP/IP stack and can handle both IPv4
+ * and IPV6 through a single file descriptor.
+ * <p>
+ * Note: Multicasting on a dual layer TCP/IP stack is always done with
+ * TwoStacksPlainDatagramSocketImpl. This is to overcome the lack
+ * of behavior defined for multicasting over a dual layer socket by the RFC.
+ *
+ * @author Chris Hegarty
+ */
+
+class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
+{
+ static JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess();
+
+ protected void datagramSocketCreate() throws SocketException {
+ if (fd == null)
+ throw new SocketException("Socket closed");
+
+ int newfd = socketCreate(false /* v6Only */);
+
+ fdAccess.set(fd, newfd);
+ }
+
+ protected synchronized void bind0(int lport, InetAddress laddr)
+ throws SocketException {
+ int nativefd = checkAndReturnNativeFD();
+
+ if (laddr == null)
+ throw new NullPointerException("argument address");
+
+ socketBind(nativefd, laddr, lport);
+ if (lport == 0) {
+ localPort = socketLocalPort(nativefd);
+ } else {
+ localPort = lport;
+ }
+ }
+
+ protected synchronized int peek(InetAddress address) throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+
+ if (address == null)
+ throw new NullPointerException("Null address in peek()");
+
+ // Use peekData()
+ DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1);
+ int peekPort = peekData(peekPacket);
+ address = peekPacket.getAddress();
+ return peekPort;
+ }
+
+ protected synchronized int peekData(DatagramPacket p) throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+
+ if (p == null)
+ throw new NullPointerException("packet");
+ if (p.getData() == null)
+ throw new NullPointerException("packet buffer");
+
+ return socketReceiveOrPeekData(nativefd, p, timeout, connected, true /*peek*/);
+ }
+
+ protected synchronized void receive0(DatagramPacket p) throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+
+ if (p == null)
+ throw new NullPointerException("packet");
+ if (p.getData() == null)
+ throw new NullPointerException("packet buffer");
+
+ socketReceiveOrPeekData(nativefd, p, timeout, connected, false /*receive*/);
+ }
+
+ protected void send(DatagramPacket p) throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+
+ if (p == null)
+ throw new NullPointerException("null packet");
+
+ if (p.getAddress() == null ||p.getData() ==null)
+ throw new NullPointerException("null address || null buffer");
+
+ socketSend(nativefd, p.getData(), p.getOffset(), p.getLength(),
+ p.getAddress(), p.getPort(), connected);
+ }
+
+ protected void connect0(InetAddress address, int port) throws SocketException {
+ int nativefd = checkAndReturnNativeFD();
+
+ if (address == null)
+ throw new NullPointerException("address");
+
+ socketConnect(nativefd, address, port);
+ }
+
+ protected void disconnect0(int family /*unused*/) {
+ if (fd == null || !fd.valid())
+ return; // disconnect doesn't throw any exceptions
+
+ socketDisconnect(fdAccess.get(fd));
+ }
+
+ protected void datagramSocketClose() {
+ if (fd == null || !fd.valid())
+ return; // close doesn't throw any exceptions
+
+ socketClose(fdAccess.get(fd));
+ fdAccess.set(fd, -1);
+ }
+
+ protected void socketSetOption(int opt, Object val) throws SocketException {
+ int nativefd = checkAndReturnNativeFD();
+
+ int optionValue = 0;
+
+ switch(opt) {
+ case IP_TOS :
+ case SO_RCVBUF :
+ case SO_SNDBUF :
+ optionValue = ((Integer)val).intValue();
+ break;
+ case SO_REUSEADDR :
+ case SO_BROADCAST :
+ optionValue = ((Boolean)val).booleanValue() ? 1 : 0;
+ break;
+ default: /* shouldn't get here */
+ throw new SocketException("Option not supported");
+ }
+
+ socketSetIntOption(nativefd, opt, optionValue);
+ }
+
+ protected Object socketGetOption(int opt) throws SocketException {
+ int nativefd = checkAndReturnNativeFD();
+
+ // SO_BINDADDR is not a socket option.
+ if (opt == SO_BINDADDR) {
+ return socketLocalAddress(nativefd);
+ }
+
+ int value = socketGetIntOption(nativefd, opt);
+ Object returnValue = null;
+
+ switch (opt) {
+ case SO_REUSEADDR :
+ case SO_BROADCAST :
+ returnValue = (value == 0) ? Boolean.FALSE : Boolean.TRUE;
+ break;
+ case IP_TOS :
+ case SO_RCVBUF :
+ case SO_SNDBUF :
+ returnValue = new Integer(value);
+ break;
+ default: /* shouldn't get here */
+ throw new SocketException("Option not supported");
+ }
+
+ return returnValue;
+ }
+
+ /* Multicast specific methods.
+ * Multicasting on a dual layer TCP/IP stack is always done with
+ * TwoStacksPlainDatagramSocketImpl. This is to overcome the lack
+ * of behavior defined for multicasting over a dual layer socket by the RFC.
+ */
+ protected void join(InetAddress inetaddr, NetworkInterface netIf)
+ throws IOException {
+ throw new IOException("Method not implemented!");
+ }
+
+ protected void leave(InetAddress inetaddr, NetworkInterface netIf)
+ throws IOException {
+ throw new IOException("Method not implemented!");
+ }
+
+ protected void setTimeToLive(int ttl) throws IOException {
+ throw new IOException("Method not implemented!");
+ }
+
+ protected int getTimeToLive() throws IOException {
+ throw new IOException("Method not implemented!");
+ }
+
+
+ protected void setTTL(byte ttl) throws IOException {
+ throw new IOException("Method not implemented!");
+ }
+
+ protected byte getTTL() throws IOException {
+ throw new IOException("Method not implemented!");
+ }
+ /* END Multicast specific methods */
+
+ private int checkAndReturnNativeFD() throws SocketException {
+ if (fd == null || !fd.valid())
+ throw new SocketException("Socket closed");
+
+ return fdAccess.get(fd);
+ }
+
+ /* Native methods */
+
+ private static native void initIDs();
+
+ private static native int socketCreate(boolean v6Only);
+
+ private static native void socketBind(int fd, InetAddress localAddress, int localport)
+ throws SocketException;
+
+ private static native void socketConnect(int fd, InetAddress address, int port)
+ throws SocketException;
+
+ private static native void socketDisconnect(int fd);
+
+ private static native void socketClose(int fd);
+
+ private static native int socketLocalPort(int fd) throws SocketException;
+
+ private static native Object socketLocalAddress(int fd) throws SocketException;
+
+ private static native int socketReceiveOrPeekData(int fd, DatagramPacket packet,
+ int timeout, boolean connected, boolean peek) throws IOException;
+
+ private static native void socketSend(int fd, byte[] data, int offset, int length,
+ InetAddress address, int port, boolean connected) throws IOException;
+
+ private static native void socketSetIntOption(int fd, int cmd,
+ int optionValue) throws SocketException;
+
+ private static native int socketGetIntOption(int fd, int cmd) throws SocketException;
+}
diff --git a/openjdk/java/net/DualStackPlainDatagramSocketImpl_c.java b/openjdk/java/net/DualStackPlainDatagramSocketImpl_c.java
new file mode 100644
index 00000000..6521e1e5
--- /dev/null
+++ b/openjdk/java/net/DualStackPlainDatagramSocketImpl_c.java
@@ -0,0 +1,496 @@
+/*
+ * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+#include <windows.h>
+#include <winsock2.h>
+#include "jni.h"
+#include "net_util.h"
+#include "java_net_DualStackPlainDatagramSocketImpl.h"
+
+/*
+ * This function "purges" all outstanding ICMP port unreachable packets
+ * outstanding on a socket and returns JNI_TRUE if any ICMP messages
+ * have been purged. The rational for purging is to emulate normal BSD
+ * behaviour whereby receiving a "connection reset" status resets the
+ * socket.
+ */
+static jboolean purgeOutstandingICMP(JNIEnv *env, jint fd)
+{
+ jboolean got_icmp = JNI_FALSE;
+ char buf[1];
+ fd_set tbl;
+ struct timeval t = { 0, 0 };
+ struct sockaddr_in rmtaddr;
+ int addrlen = sizeof(rmtaddr);
+
+ /*
+ * Peek at the queue to see if there is an ICMP port unreachable. If there
+ * is then receive it.
+ */
+ FD_ZERO(&tbl);
+ FD_SET(fd, &tbl);
+ while(1) {
+ if (select(/*ignored*/fd+1, &tbl, 0, 0, &t) <= 0) {
+ break;
+ }
+ if (recvfrom(fd, buf, 1, MSG_PEEK,
+ (struct sockaddr *)&rmtaddr, &addrlen) != JVM_IO_ERR) {
+ break;
+ }
+ if (WSAGetLastError() != WSAECONNRESET) {
+ /* some other error - we don't care here */
+ break;
+ }
+
+ recvfrom(fd, buf, 1, 0, (struct sockaddr *)&rmtaddr, &addrlen);
+ got_icmp = JNI_TRUE;
+ }
+
+ return got_icmp;
+}
+
+/*
+ * Class: java_net_DualStackPlainDatagramSocketImpl
+ * Method: socketCreate
+ * Signature: (Z)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketCreate
+ (JNIEnv *env, jclass clazz, jboolean v6Only /*unused*/) {
+ int fd, rv, opt=0, t=TRUE;
+ DWORD x1, x2; /* ignored result codes */
+
+ fd = (int) socket(AF_INET6, SOCK_DGRAM, 0);
+ if (fd == INVALID_SOCKET) {
+ NET_ThrowNew(env, WSAGetLastError(), "Socket creation failed");
+ return -1;
+ }
+
+ rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt));
+ if (rv == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "Socket creation failed");
+ return -1;
+ }
+
+ SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
+ NET_SetSockOpt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
+
+ /* SIO_UDP_CONNRESET fixes a "bug" introduced in Windows 2000, which
+ * returns connection reset errors on unconnected UDP sockets (as well
+ * as connected sockets). The solution is to only enable this feature
+ * when the socket is connected.
+ */
+ t = FALSE;
+ WSAIoctl(fd ,SIO_UDP_CONNRESET ,&t ,sizeof(t) ,&x1 ,sizeof(x1) ,&x2 ,0 ,0);
+
+ return fd;
+}
+
+/*
+ * Class: java_net_DualStackPlainDatagramSocketImpl
+ * Method: socketBind
+ * Signature: (ILjava/net/InetAddress;I)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketBind
+ (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
+ SOCKETADDRESS sa;
+ int rv;
+ int sa_len = sizeof(sa);
+
+ if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,
+ &sa_len, JNI_TRUE) != 0) {
+ return;
+ }
+
+ rv = bind(fd, (struct sockaddr *)&sa, sa_len);
+
+ if (rv == SOCKET_ERROR) {
+ if (WSAGetLastError() == WSAEACCES) {
+ WSASetLastError(WSAEADDRINUSE);
+ }
+ NET_ThrowNew(env, WSAGetLastError(), "Cannot bind");
+ }
+}
+
+/*
+ * Class: java_net_DualStackPlainDatagramSocketImpl
+ * Method: socketConnect
+ * Signature: (ILjava/net/InetAddress;I)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketConnect
+ (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
+ SOCKETADDRESS sa;
+ int rv;
+ int sa_len = sizeof(sa);
+ DWORD x1, x2; /* ignored result codes */
+ int t = TRUE;
+
+ if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,
+ &sa_len, JNI_TRUE) != 0) {
+ return;
+ }
+
+ rv = connect(fd, (struct sockaddr *)&sa, sa_len);
+ if (rv == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "connect");
+ return;
+ }
+
+ /* see comment in socketCreate */
+ WSAIoctl(fd, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0);
+}
+
+/*
+ * Class: java_net_DualStackPlainDatagramSocketImpl
+ * Method: socketDisconnect
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketDisconnect
+ (JNIEnv *env, jclass clazz, jint fd ) {
+ SOCKETADDRESS sa;
+ int sa_len = sizeof(sa);
+ DWORD x1, x2; /* ignored result codes */
+ int t = FALSE;
+
+ memset(&sa, 0, sa_len);
+ connect(fd, (struct sockaddr *)&sa, sa_len);
+
+ /* see comment in socketCreate */
+ WSAIoctl(fd, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0);
+}
+
+/*
+ * Class: java_net_DualStackPlainDatagramSocketImpl
+ * Method: socketClose
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketClose
+ (JNIEnv *env, jclass clazz , jint fd) {
+ NET_SocketClose(fd);
+}
+
+
+/*
+ * Class: java_net_DualStackPlainDatagramSocketImpl
+ * Method: socketLocalPort
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketLocalPort
+ (JNIEnv *env, jclass clazz, jint fd) {
+ SOCKETADDRESS sa;
+ int len = sizeof(sa);
+
+ if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "JVM_GetSockName");
+ return -1;
+ }
+ return (int) ntohs((u_short)GET_PORT(&sa));
+}
+
+/*
+ * Class: java_net_DualStackPlainDatagramSocketImpl
+ * Method: socketLocalAddress
+ * Signature: (I)Ljava/lang/Object;
+ */
+JNIEXPORT jobject JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketLocalAddress
+ (JNIEnv *env , jclass clazz, jint fd) {
+ SOCKETADDRESS sa;
+ int len = sizeof(sa);
+ jobject iaObj;
+ int port;
+
+ if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
+ return NULL;
+ }
+
+ iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
+ return iaObj;
+}
+
+/*
+ * Class: java_net_DualStackPlainDatagramSocketImpl
+ * Method: socketReceiveOrPeekData
+ * Signature: (ILjava/net/DatagramPacket;IZZ)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketReceiveOrPeekData
+ (JNIEnv *env, jclass clazz, jint fd, jobject dpObj,
+ jint timeout, jboolean connected, jboolean peek) {
+ SOCKETADDRESS sa;
+ int sa_len = sizeof(sa);
+ int port, rv, flags=0;
+ char BUF[MAX_BUFFER_LEN];
+ char *fullPacket;
+ BOOL retry;
+ jlong prevTime = 0;
+
+ jint packetBufferOffset, packetBufferLen;
+ jbyteArray packetBuffer;
+
+ /* if we are only peeking. Called from peekData */
+ if (peek) {
+ flags = MSG_PEEK;
+ }
+
+ packetBuffer = (*env)->GetObjectField(env, dpObj, dp_bufID);
+ packetBufferOffset = (*env)->GetIntField(env, dpObj, dp_offsetID);
+ packetBufferLen = (*env)->GetIntField(env, dpObj, dp_bufLengthID);
+
+ if (packetBufferLen > MAX_BUFFER_LEN) {
+ /* Note: the buffer needn't be greater than 65,536 (0xFFFF)
+ * the max size of an IP packet. Anything bigger is truncated anyway.
+ */
+ if (packetBufferLen > MAX_PACKET_LEN) {
+ packetBufferLen = MAX_PACKET_LEN;
+ }
+ fullPacket = (char *)malloc(packetBufferLen);
+ if (!fullPacket) {
+ JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
+ return -1;
+ }
+ } else {
+ fullPacket = &(BUF[0]);
+ }
+
+ do {
+ retry = FALSE;
+
+ if (timeout) {
+ if (prevTime == 0) {
+ prevTime = JVM_CurrentTimeMillis(env, 0);
+ }
+ rv = NET_Timeout(fd, timeout);
+ if (rv <= 0) {
+ if (rv == 0) {
+ JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException",
+ "Receive timed out");
+ } else if (rv == JVM_IO_ERR) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Socket closed");
+ } else if (rv == JVM_IO_INTR) {
+ JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
+ "operation interrupted");
+ }
+ if (packetBufferLen > MAX_BUFFER_LEN) {
+ free(fullPacket);
+ }
+ return -1;
+ }
+ }
+
+ /* receive the packet */
+ rv = recvfrom(fd, fullPacket, packetBufferLen, flags,
+ (struct sockaddr *)&sa, &sa_len);
+
+ if (rv == SOCKET_ERROR && (WSAGetLastError() == WSAECONNRESET)) {
+ /* An icmp port unreachable - we must receive this as Windows
+ * does not reset the state of the socket until this has been
+ * received.
+ */
+ purgeOutstandingICMP(env, fd);
+
+ if (connected) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
+ "ICMP Port Unreachable");
+ if (packetBufferLen > MAX_BUFFER_LEN)
+ free(fullPacket);
+ return -1;
+ } else if (timeout) {
+ /* Adjust timeout */
+ jlong newTime = JVM_CurrentTimeMillis(env, 0);
+ timeout -= (jint)(newTime - prevTime);
+ if (timeout <= 0) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
+ "Receive timed out");
+ if (packetBufferLen > MAX_BUFFER_LEN)
+ free(fullPacket);
+ return -1;
+ }
+ prevTime = newTime;
+ }
+ retry = TRUE;
+ }
+ } while (retry);
+
+ port = (int) ntohs ((u_short) GET_PORT((SOCKETADDRESS *)&sa));
+
+ /* truncate the data if the packet's length is too small */
+ if (rv > packetBufferLen) {
+ rv = packetBufferLen;
+ }
+ if (rv < 0) {
+ if (WSAGetLastError() == WSAEMSGSIZE) {
+ /* it is because the buffer is too small. It's UDP, it's
+ * unreliable, it's all good. discard the rest of the
+ * data..
+ */
+ rv = packetBufferLen;
+ } else {
+ /* failure */
+ (*env)->SetIntField(env, dpObj, dp_lengthID, 0);
+ }
+ }
+
+ if (rv == -1) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
+ } else if (rv == -2) {
+ JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
+ "operation interrupted");
+ } else if (rv < 0) {
+ NET_ThrowCurrent(env, "Datagram receive failed");
+ } else {
+ jobject packetAddress;
+ /*
+ * Check if there is an InetAddress already associated with this
+ * packet. If so, we check if it is the same source address. We
+ * can't update any existing InetAddress because it is immutable
+ */
+ packetAddress = (*env)->GetObjectField(env, dpObj, dp_addressID);
+ if (packetAddress != NULL) {
+ if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&sa,
+ packetAddress)) {
+ /* force a new InetAddress to be created */
+ packetAddress = NULL;
+ }
+ }
+ if (packetAddress == NULL) {
+ packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa,
+ &port);
+ /* stuff the new Inetaddress into the packet */
+ (*env)->SetObjectField(env, dpObj, dp_addressID, packetAddress);
+ }
+
+ /* populate the packet */
+ (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, rv,
+ (jbyte *)fullPacket);
+ (*env)->SetIntField(env, dpObj, dp_portID, port);
+ (*env)->SetIntField(env, dpObj, dp_lengthID, rv);
+ }
+
+ if (packetBufferLen > MAX_BUFFER_LEN) {
+ free(fullPacket);
+ }
+ return port;
+}
+
+/*
+ * Class: java_net_DualStackPlainDatagramSocketImpl
+ * Method: socketSend
+ * Signature: (I[BIILjava/net/InetAddress;IZ)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketSend
+ (JNIEnv *env, jclass clazz, jint fd, jbyteArray data, jint offset, jint length,
+ jobject iaObj, jint port, jboolean connected) {
+ SOCKETADDRESS sa;
+ int sa_len = sizeof(sa);
+ SOCKETADDRESS *sap = &sa;
+ char BUF[MAX_BUFFER_LEN];
+ char *fullPacket;
+ int rv;
+
+ if (connected) {
+ sap = 0; /* arg to JVM_Sendto () null in this case */
+ sa_len = 0;
+ } else {
+ if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,
+ &sa_len, JNI_TRUE) != 0) {
+ return;
+ }
+ }
+
+ if (length > MAX_BUFFER_LEN) {
+ /* Note: the buffer needn't be greater than 65,536 (0xFFFF)
+ * the max size of an IP packet. Anything bigger is truncated anyway.
+ */
+ if (length > MAX_PACKET_LEN) {
+ length = MAX_PACKET_LEN;
+ }
+ fullPacket = (char *)malloc(length);
+ if (!fullPacket) {
+ JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
+ return;
+ }
+ } else {
+ fullPacket = &(BUF[0]);
+ }
+
+ (*env)->GetByteArrayRegion(env, data, offset, length,
+ (jbyte *)fullPacket);
+ rv = sendto(fd, fullPacket, length, 0, (struct sockaddr *)sap, sa_len);
+ if (rv == SOCKET_ERROR) {
+ if (rv == JVM_IO_ERR) {
+ NET_ThrowNew(env, WSAGetLastError(), "Datagram send failed");
+ } else if (rv == JVM_IO_INTR) {
+ JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
+ "operation interrupted");
+ }
+ }
+
+ if (length > MAX_BUFFER_LEN) {
+ free(fullPacket);
+ }
+}
+
+/*
+ * Class: java_net_DualStackPlainDatagramSocketImpl
+ * Method: socketSetIntOption
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketSetIntOption
+ (JNIEnv *env, jclass clazz, jint fd , jint cmd, jint value) {
+ int level, opt;
+
+ if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
+ JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+ "Invalid option");
+ return;
+ }
+
+ if (NET_SetSockOpt(fd, level, opt, (char *)&value, sizeof(value)) < 0) {
+ NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
+ }
+}
+
+/*
+ * Class: java_net_DualStackPlainDatagramSocketImpl
+ * Method: socketGetIntOption
+ * Signature: (II)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketGetIntOption
+ (JNIEnv *env, jclass clazz, jint fd, jint cmd) {
+ int level, opt, result=0;
+ int result_len = sizeof(result);
+
+ if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
+ JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+ "Invalid option");
+ return -1;
+ }
+
+ if (NET_GetSockOpt(fd, level, opt, (void *)&result, &result_len) < 0) {
+ NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
+ return -1;
+ }
+
+ return result;
+}
diff --git a/openjdk/java/net/DualStackPlainSocketImpl.java b/openjdk/java/net/DualStackPlainSocketImpl.java
new file mode 100644
index 00000000..4073b9d5
--- /dev/null
+++ b/openjdk/java/net/DualStackPlainSocketImpl.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+import java.io.IOException;
+import java.io.FileDescriptor;
+import sun.misc.SharedSecrets;
+import sun.misc.JavaIOFileDescriptorAccess;
+
+/**
+ * This class defines the plain SocketImpl that is used on Windows platforms
+ * greater or equal to Windows Vista. These platforms have a dual
+ * layer TCP/IP stack and can handle both IPv4 and IPV6 through a
+ * single file descriptor.
+ *
+ * @author Chris Hegarty
+ */
+
+class DualStackPlainSocketImpl extends AbstractPlainSocketImpl
+{
+ static JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess();
+
+ public DualStackPlainSocketImpl() {}
+
+ public DualStackPlainSocketImpl(FileDescriptor fd) {
+ this.fd = fd;
+ }
+
+ void socketCreate(boolean stream) throws IOException {
+ if (fd == null)
+ throw new SocketException("Socket closed");
+
+ int newfd = socket0(stream, false /*v6 Only*/);
+
+ fdAccess.set(fd, newfd);
+ }
+
+ void socketConnect(InetAddress address, int port, int timeout)
+ throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+
+ if (address == null)
+ throw new NullPointerException("inet address argument is null.");
+
+ int connectResult;
+ if (timeout <= 0) {
+ connectResult = connect0(nativefd, address, port);
+ } else {
+ configureBlocking(nativefd, false);
+ try {
+ connectResult = connect0(nativefd, address, port);
+ if (connectResult == WOULDBLOCK) {
+ waitForConnect(nativefd, timeout);
+ }
+ } finally {
+ configureBlocking(nativefd, true);
+ }
+ }
+ /*
+ * We need to set the local port field. If bind was called
+ * previous to the connect (by the client) then localport field
+ * will already be set.
+ */
+ if (localport == 0)
+ localport = localPort0(nativefd);
+ }
+
+ void socketBind(InetAddress address, int port) throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+
+ if (address == null)
+ throw new NullPointerException("inet address argument is null.");
+
+ bind0(nativefd, address, port);
+ if (port == 0) {
+ localport = localPort0(nativefd);
+ } else {
+ localport = port;
+ }
+
+ this.address = address;
+ }
+
+ void socketListen(int backlog) throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+
+ listen0(nativefd, backlog);
+ }
+
+ void socketAccept(SocketImpl s) throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+
+ if (s == null)
+ throw new NullPointerException("socket is null");
+
+ int newfd = -1;
+ InetSocketAddress[] isaa = new InetSocketAddress[1];
+ if (timeout <= 0) {
+ newfd = accept0(nativefd, isaa);
+ } else {
+ configureBlocking(nativefd, false);
+ try {
+ waitForNewConnection(nativefd, timeout);
+ newfd = accept0(nativefd, isaa);
+ if (newfd != -1) {
+ configureBlocking(newfd, true);
+ }
+ } finally {
+ configureBlocking(nativefd, true);
+ }
+ }
+ /* Update (SocketImpl)s' fd */
+ fdAccess.set(s.fd, newfd);
+ /* Update socketImpls remote port, address and localport */
+ InetSocketAddress isa = isaa[0];
+ s.port = isa.getPort();
+ s.address = isa.getAddress();
+ s.localport = localport;
+ }
+
+ int socketAvailable() throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+ return available0(nativefd);
+ }
+
+ void socketClose0(boolean useDeferredClose/*unused*/) throws IOException {
+ if (fd == null)
+ throw new SocketException("Socket closed");
+
+ if (!fd.valid())
+ return;
+
+ close0(fdAccess.get(fd));
+ fdAccess.set(fd, -1);
+ }
+
+ void socketShutdown(int howto) throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+ shutdown0(nativefd, howto);
+ }
+
+ void socketSetOption(int opt, boolean on, Object value)
+ throws SocketException {
+ int nativefd = checkAndReturnNativeFD();
+
+ if (opt == SO_TIMEOUT) { // timeout implemented through select.
+ return;
+ }
+
+ int optionValue = 0;
+
+ switch(opt) {
+ case TCP_NODELAY :
+ case SO_OOBINLINE :
+ case SO_KEEPALIVE :
+ case SO_REUSEADDR :
+ optionValue = on ? 1 : 0;
+ break;
+ case SO_SNDBUF :
+ case SO_RCVBUF :
+ case IP_TOS :
+ optionValue = ((Integer)value).intValue();
+ break;
+ case SO_LINGER :
+ if (on) {
+ optionValue = ((Integer)value).intValue();
+ } else {
+ optionValue = -1;
+ }
+ break;
+ default :/* shouldn't get here */
+ throw new SocketException("Option not supported");
+ }
+
+ setIntOption(nativefd, opt, optionValue);
+ }
+
+ int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
+ int nativefd = checkAndReturnNativeFD();
+
+ // SO_BINDADDR is not a socket option.
+ if (opt == SO_BINDADDR) {
+ localAddress(nativefd, (InetAddressContainer)iaContainerObj);
+ return 0; // return value doesn't matter.
+ }
+
+ int value = getIntOption(nativefd, opt);
+
+ switch (opt) {
+ case TCP_NODELAY :
+ case SO_OOBINLINE :
+ case SO_KEEPALIVE :
+ case SO_REUSEADDR :
+ return (value == 0) ? -1 : 1;
+ }
+ return value;
+ }
+
+ void socketSendUrgentData(int data) throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+ sendOOB(nativefd, data);
+ }
+
+ private int checkAndReturnNativeFD() throws SocketException {
+ if (fd == null || !fd.valid())
+ throw new SocketException("Socket closed");
+
+ return fdAccess.get(fd);
+ }
+
+ static final int WOULDBLOCK = -2; // Nothing available (non-blocking)
+
+ static {
+ initIDs();
+ }
+
+ /* Native methods */
+
+ static native void initIDs();
+
+ static native int socket0(boolean stream, boolean v6Only) throws IOException;
+
+ static native void bind0(int fd, InetAddress localAddress, int localport)
+ throws IOException;
+
+ static native int connect0(int fd, InetAddress remote, int remotePort)
+ throws IOException;
+
+ static native void waitForConnect(int fd, int timeout) throws IOException;
+
+ static native int localPort0(int fd) throws IOException;
+
+ static native void localAddress(int fd, InetAddressContainer in) throws SocketException;
+
+ static native void listen0(int fd, int backlog) throws IOException;
+
+ static native int accept0(int fd, InetSocketAddress[] isaa) throws IOException;
+
+ static native void waitForNewConnection(int fd, int timeout) throws IOException;
+
+ static native int available0(int fd) throws IOException;
+
+ static native void close0(int fd) throws IOException;
+
+ static native void shutdown0(int fd, int howto) throws IOException;
+
+ static native void setIntOption(int fd, int cmd, int optionValue) throws SocketException;
+
+ static native int getIntOption(int fd, int cmd) throws SocketException;
+
+ static native void sendOOB(int fd, int data) throws IOException;
+
+ static native void configureBlocking(int fd, boolean blocking) throws IOException;
+}
diff --git a/openjdk/java/net/DualStackPlainSocketImpl_c.java b/openjdk/java/net/DualStackPlainSocketImpl_c.java
new file mode 100644
index 00000000..5f22e887
--- /dev/null
+++ b/openjdk/java/net/DualStackPlainSocketImpl_c.java
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+#include <windows.h>
+#include <winsock2.h>
+#include "jni.h"
+#include "net_util.h"
+#include "java_net_DualStackPlainSocketImpl.h"
+
+#define SET_BLOCKING 0
+#define SET_NONBLOCKING 1
+
+static jclass isa_class; /* java.net.InetSocketAddress */
+static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: initIDs
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_initIDs
+ (JNIEnv *env, jclass clazz) {
+
+ jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
+ isa_class = (*env)->NewGlobalRef(env, cls);
+ isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
+ "(Ljava/net/InetAddress;I)V");
+
+ // implement read timeout with select.
+ isRcvTimeoutSupported = 0;
+}
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: socket0
+ * Signature: (ZZ)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0
+ (JNIEnv *env, jclass clazz, jboolean stream, jboolean v6Only /*unused*/) {
+ int fd, rv, opt=0;
+
+ fd = NET_Socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
+ if (fd == INVALID_SOCKET) {
+ NET_ThrowNew(env, WSAGetLastError(), "create");
+ return -1;
+ }
+
+ rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt));
+ if (rv == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "create");
+ }
+
+ SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
+
+ return fd;
+}
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: bind0
+ * Signature: (ILjava/net/InetAddress;I)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind0
+ (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
+ SOCKETADDRESS sa;
+ int rv;
+ int sa_len = sizeof(sa);
+
+ if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,
+ &sa_len, JNI_TRUE) != 0) {
+ return;
+ }
+
+ rv = NET_Bind(fd, (struct sockaddr *)&sa, sa_len);
+
+ if (rv == SOCKET_ERROR)
+ NET_ThrowNew(env, WSAGetLastError(), "JVM_Bind");
+}
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: connect0
+ * Signature: (ILjava/net/InetAddress;I)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0
+ (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
+ SOCKETADDRESS sa;
+ int rv;
+ int sa_len = sizeof(sa);
+
+ if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,
+ &sa_len, JNI_TRUE) != 0) {
+ return -1;
+ }
+
+ rv = connect(fd, (struct sockaddr *)&sa, sa_len);
+ if (rv == SOCKET_ERROR) {
+ int err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK) {
+ return java_net_DualStackPlainSocketImpl_WOULDBLOCK;
+ } else if (err == WSAEADDRNOTAVAIL) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
+ "connect: Address is invalid on local machine, or port is not valid on remote machine");
+ } else {
+ NET_ThrowNew(env, err, "connect");
+ }
+ return -1; // return value not important.
+ }
+ return rv;
+}
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: waitForConnect
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForConnect
+ (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
+ int rv, retry;
+ int optlen = sizeof(rv);
+ fd_set wr, ex;
+ struct timeval t;
+
+ FD_ZERO(&wr);
+ FD_ZERO(&ex);
+ FD_SET(fd, &wr);
+ FD_SET(fd, &ex);
+ t.tv_sec = timeout / 1000;
+ t.tv_usec = (timeout % 1000) * 1000;
+
+ /*
+ * Wait for timeout, connection established or
+ * connection failed.
+ */
+ rv = select(fd+1, 0, &wr, &ex, &t);
+
+ /*
+ * Timeout before connection is established/failed so
+ * we throw exception and shutdown input/output to prevent
+ * socket from being used.
+ * The socket should be closed immediately by the caller.
+ */
+ if (rv == 0) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
+ "connect timed out");
+ shutdown( fd, SD_BOTH );
+ return;
+ }
+
+ /*
+ * Socket is writable or error occured. On some Windows editions
+ * the socket will appear writable when the connect fails so we
+ * check for error rather than writable.
+ */
+ if (!FD_ISSET(fd, &ex)) {
+ return; /* connection established */
+ }
+
+ /*
+ * Connection failed. The logic here is designed to work around
+ * bug on Windows NT whereby using getsockopt to obtain the
+ * last error (SO_ERROR) indicates there is no error. The workaround
+ * on NT is to allow winsock to be scheduled and this is done by
+ * yielding and retrying. As yielding is problematic in heavy
+ * load conditions we attempt up to 3 times to get the error reason.
+ */
+ for (retry=0; retry<3; retry++) {
+ NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
+ (char*)&rv, &optlen);
+ if (rv) {
+ break;
+ }
+ Sleep(0);
+ }
+
+ if (rv == 0) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Unable to establish connection");
+ } else {
+ NET_ThrowNew(env, rv, "connect");
+ }
+}
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: localPort0
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_localPort0
+ (JNIEnv *env, jclass clazz, jint fd) {
+ SOCKETADDRESS sa;
+ int len = sizeof(sa);
+
+ if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) {
+ if (WSAGetLastError() == WSAENOTSOCK) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Socket closed");
+ } else {
+ NET_ThrowNew(env, WSAGetLastError(), "getsockname failed");
+ }
+ return -1;
+ }
+ return (int) ntohs((u_short)GET_PORT(&sa));
+}
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: localAddress
+ * Signature: (ILjava/net/InetAddressContainer;)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_localAddress
+ (JNIEnv *env, jclass clazz, jint fd, jobject iaContainerObj) {
+ int port;
+ SOCKETADDRESS sa;
+ int len = sizeof(sa);
+ jobject iaObj;
+ jclass iaContainerClass;
+ jfieldID iaFieldID;
+
+ if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
+ return;
+ }
+ iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
+ CHECK_NULL(iaObj);
+
+ iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj);
+ iaFieldID = (*env)->GetFieldID(env, iaContainerClass, "addr", "Ljava/net/InetAddress;");
+ CHECK_NULL(iaFieldID);
+ (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
+}
+
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: listen0
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_listen0
+ (JNIEnv *env, jclass clazz, jint fd, jint backlog) {
+ if (listen(fd, backlog) == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "listen failed");
+ }
+}
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: accept0
+ * Signature: (I[Ljava/net/InetSocketAddress;)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_accept0
+ (JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) {
+ int newfd, port=0;
+ jobject isa;
+ jobject ia;
+ SOCKETADDRESS sa;
+ int len = sizeof(sa);
+
+ memset((char *)&sa, 0, len);
+ newfd = accept(fd, (struct sockaddr *)&sa, &len);
+
+ if (newfd == INVALID_SOCKET) {
+ if (WSAGetLastError() == -2) {
+ JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
+ "operation interrupted");
+ } else {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "socket closed");
+ }
+ return -1;
+ }
+
+ ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
+ isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
+ (*env)->SetObjectArrayElement(env, isaa, 0, isa);
+
+ return newfd;
+}
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: waitForNewConnection
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForNewConnection
+ (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
+ int rv;
+
+ rv = NET_Timeout(fd, timeout);
+ if (rv == 0) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
+ "Accept timed out");
+ } else if (rv == -1) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
+ } else if (rv == -2) {
+ JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
+ "operation interrupted");
+ }
+}
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: available0
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_available0
+ (JNIEnv *env, jclass clazz, jint fd) {
+ jint available = -1;
+
+ if ((ioctlsocket(fd, FIONREAD, &available)) == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "socket available");
+ }
+
+ return available;
+}
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: close0
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_close0
+ (JNIEnv *env, jclass clazz, jint fd) {
+ NET_SocketClose(fd);
+}
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: shutdown0
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_shutdown0
+ (JNIEnv *env, jclass clazz, jint fd, jint howto) {
+ shutdown(fd, howto);
+}
+
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: setIntOption
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_setIntOption
+ (JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value) {
+
+ int level, opt;
+ struct linger linger;
+ char *parg;
+ int arglen;
+
+ if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
+ JNU_ThrowByNameWithLastError(env,
+ JNU_JAVANETPKG "SocketException",
+ "Invalid option");
+ return;
+ }
+
+ if (opt == java_net_SocketOptions_SO_LINGER) {
+ parg = (char *)&linger;
+ arglen = sizeof(linger);
+ if (value >= 0) {
+ linger.l_onoff = 1;
+ linger.l_linger = (unsigned short)value;
+ } else {
+ linger.l_onoff = 0;
+ linger.l_linger = 0;
+ }
+ } else {
+ parg = (char *)&value;
+ arglen = sizeof(value);
+ }
+
+ if (NET_SetSockOpt(fd, level, opt, parg, arglen) < 0) {
+ NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
+ }
+}
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: getIntOption
+ * Signature: (II)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_getIntOption
+ (JNIEnv *env, jclass clazz, jint fd, jint cmd) {
+
+ int level, opt;
+ int result=0;
+ struct linger linger;
+ char *arg;
+ int arglen;
+
+ if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
+ JNU_ThrowByNameWithLastError(env,
+ JNU_JAVANETPKG "SocketException",
+ "Unsupported socket option");
+ return -1;
+ }
+
+ if (opt == java_net_SocketOptions_SO_LINGER) {
+ arg = (char *)&linger;
+ arglen = sizeof(linger);
+ } else {
+ arg = (char *)&result;
+ arglen = sizeof(result);
+ }
+
+ if (NET_GetSockOpt(fd, level, opt, arg, &arglen) < 0) {
+ NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
+ return -1;
+ }
+
+ if (opt == java_net_SocketOptions_SO_LINGER)
+ return linger.l_onoff ? linger.l_linger : -1;
+ else
+ return result;
+}
+
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: sendOOB
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_sendOOB
+ (JNIEnv *env, jclass clazz, jint fd, jint data) {
+ jint n;
+ unsigned char d = (unsigned char) data & 0xff;
+
+ n = send(fd, (char *)&data, 1, MSG_OOB);
+ if (n == JVM_IO_ERR) {
+ NET_ThrowNew(env, WSAGetLastError(), "send");
+ } else if (n == JVM_IO_INTR) {
+ JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
+ }
+}
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: configureBlocking
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_configureBlocking
+ (JNIEnv *env, jclass clazz, jint fd, jboolean blocking) {
+ u_long arg;
+ int result;
+
+ if (blocking == JNI_TRUE) {
+ arg = SET_BLOCKING; // 0
+ } else {
+ arg = SET_NONBLOCKING; // 1
+ }
+
+ result = ioctlsocket(fd, FIONBIO, &arg);
+ if (result == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "configureBlocking");
+ }
+}