/* * 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"); closesocket(fd); 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; }
JNIEXPORT jint JNICALL Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, jboolean stream, jboolean reuse) { SOCKET s; int domain = (preferIPv6) ? AF_INET6 : AF_INET; s = socket(domain, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); if (s != INVALID_SOCKET) { SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0); /* IPV6_V6ONLY is true by default */ if (domain == AF_INET6) { int opt = 0; setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&opt, sizeof(opt)); } /* Disable WSAECONNRESET errors for initially unconnected UDP sockets */ if (!stream) { setConnectionReset(s, FALSE); } } else { NET_ThrowNew(env, WSAGetLastError(), "socket"); } return (jint)s; }
/* * 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; }
JNIEXPORT jint JNICALL Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, jobject fdo, jobject iao, jint port) { SOCKETADDRESS sa; int rv; int sa_len; SOCKET s = (SOCKET)fdval(env, fdo); if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { return IOS_THROWN; } rv = connect(s, (struct sockaddr *)&sa, sa_len); if (rv != 0) { int err = WSAGetLastError(); if (err == WSAEINPROGRESS || err == WSAEWOULDBLOCK) { return IOS_UNAVAILABLE; } NET_ThrowNew(env, err, "connect"); return IOS_THROWN; } else { /* Enable WSAECONNRESET errors when a UDP socket is connected */ int type = 0, optlen = sizeof(type); rv = getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&type, &optlen); if (rv == 0 && type == SOCK_DGRAM) { setConnectionReset(s, TRUE); } } return 1; }
JNIEXPORT void JNICALL Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) { if (listen(fdval(env,fdo), backlog) == SOCKET_ERROR) { NET_ThrowNew(env, WSAGetLastError(), "listen"); } }
/* * 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: 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: 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: 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_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_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_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, "Native 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); } }
JNIEXPORT jobject JNICALL Java_sun_nio_ch_Net_remoteInetAddress(JNIEnv *env, jclass clazz, jobject fdo) { SOCKETADDRESS sa; int sa_len = sizeof(sa); int port; if (getpeername(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { NET_ThrowNew(env, WSAGetLastError(), "getsockname"); return NULL; } return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); }
/* * 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 = 0, opt = 0; 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: 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_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: 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)); }
JNIEXPORT void JNICALL Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6, jboolean isExclBind, jobject iao, jint port) { SOCKETADDRESS sa; int rv; int sa_len; if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { return; } rv = NET_WinBind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len, isExclBind); if (rv == SOCKET_ERROR) NET_ThrowNew(env, WSAGetLastError(), "bind"); }
JNIEXPORT jint JNICALL Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo) { SOCKETADDRESS sa; int sa_len = sizeof(sa); if (getpeername(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { int error = WSAGetLastError(); if (error == WSAEINVAL) { return 0; } NET_ThrowNew(env, error, "getsockname"); return IOS_THROWN; } return NET_GetPortFromSockaddr((struct sockaddr *)&sa); }
/* * 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"); } }
/* * 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 = 0, opt = 0, 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; }
/* * 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, jboolean exclBind) { 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_WinBind(fd, (struct sockaddr *)&sa, sa_len, exclBind); if (rv == SOCKET_ERROR) { if (WSAGetLastError() == WSAEACCES) { WSASetLastError(WSAEADDRINUSE); } NET_ThrowNew(env, WSAGetLastError(), "Cannot bind"); } }
/* * 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_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); }
jint handleSocketError(JNIEnv *env, int errorValue) { NET_ThrowNew(env, errorValue, NULL); return IOS_THROWN; }
void NET_ThrowCurrent(JNIEnv *env, char *msg) { NET_ThrowNew(env, WSAGetLastError(), msg); }
/* * 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: 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"); } }