JNIEXPORT jlong JNICALL Java_sun_nio_ch_DatagramDispatcher_readv0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len) { /* set up */ int i = 0; DWORD read = 0; DWORD flags = 0; jint fd = fdval(env, fdo); struct iovec *iovp = (struct iovec *)address; WSABUF *bufs = malloc(len * sizeof(WSABUF)); /* copy iovec into WSABUF */ for(i=0; i<len; i++) { bufs[i].buf = (char *)iovp[i].iov_base; bufs[i].len = (u_long)iovp[i].iov_len; } /* read into the buffers */ i = WSARecv((SOCKET)fd, /* Socket */ bufs, /* pointers to the buffers */ (DWORD)len, /* number of buffers to process */ &read, /* receives number of bytes read */ &flags, /* no flags */ 0, /* no overlapped sockets */ 0); /* no completion routine */ /* clean up */ free(bufs); if (i != 0) { int theErr = (jint)WSAGetLastError(); if (theErr == WSAEWOULDBLOCK) { return IOS_UNAVAILABLE; } if (theErr == WSAECONNRESET) { purgeOutstandingICMP(env, clazz, fd); JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 0); return IOS_THROWN; } JNU_ThrowIOExceptionWithLastError(env, "Write failed"); return IOS_THROWN; } return convertLongReturnVal(env, (jlong)read, JNI_TRUE); }
JNIEXPORT jint JNICALL Java_sun_nio_ch_DatagramDispatcher_read0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len) { /* set up */ int i = 0; DWORD read = 0; DWORD flags = 0; jint fd = fdval(env, fdo); WSABUF buf; /* destination buffer and size */ buf.buf = (char *)address; buf.len = (u_long)len; /* read into the buffers */ i = WSARecv((SOCKET)fd, /* Socket */ &buf, /* pointers to the buffers */ (DWORD)1, /* number of buffers to process */ &read, /* receives number of bytes read */ &flags, /* no flags */ 0, /* no overlapped sockets */ 0); /* no completion routine */ if (i == SOCKET_ERROR) { int theErr = (jint)WSAGetLastError(); if (theErr == WSAEWOULDBLOCK) { return IOS_UNAVAILABLE; } if (theErr == WSAECONNRESET) { purgeOutstandingICMP(env, clazz, fd); JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 0); return IOS_THROWN; } JNU_ThrowIOExceptionWithLastError(env, "Write failed"); return IOS_THROWN; } return convertReturnVal(env, (jint)read, JNI_TRUE); }
/* * 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); /* 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; } if (packetBufferLen > MAX_BUFFER_LEN) { fullPacket = (char *)malloc(packetBufferLen); if (!fullPacket) { JNU_ThrowOutOfMemoryError(env, "Native 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); if (packetAddress != NULL) { /* stuff the new Inetaddress into the packet */ (*env)->SetObjectField(env, dpObj, dp_addressID, packetAddress); } } if (!(*env)->ExceptionCheck(env)) { /* 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; }