mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-10 10:28:37 +00:00
8053479: (dc) DatagramChannel.read() throws exception instead of discarding data when buffer too small
Reviewed-by: redestad, dfuchs
This commit is contained in:
parent
c6da6681d4
commit
6ef474a4f4
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2020, 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
|
||||
@ -23,32 +23,30 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
#include "sun_nio_ch_DatagramDispatcher.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nio.h"
|
||||
#include "nio_util.h"
|
||||
#include <limits.h>
|
||||
#include "sun_nio_ch_DatagramDispatcher.h"
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_DatagramDispatcher_read0(JNIEnv *env, jclass clazz,
|
||||
jobject fdo, jlong address, jint len)
|
||||
jobject fdo, jlong address, jint len)
|
||||
{
|
||||
jint fd = fdval(env, fdo);
|
||||
void *buf = (void *)jlong_to_ptr(address);
|
||||
int result = recv(fd, buf, len, 0);
|
||||
if (result < 0 && errno == ECONNREFUSED) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 0);
|
||||
return -2;
|
||||
return IOS_THROWN;
|
||||
}
|
||||
return convertReturnVal(env, result, JNI_TRUE);
|
||||
}
|
||||
@ -56,7 +54,7 @@ Java_sun_nio_ch_DatagramDispatcher_read0(JNIEnv *env, jclass clazz,
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_nio_ch_DatagramDispatcher_readv0(JNIEnv *env, jclass clazz,
|
||||
jobject fdo, jlong address, jint len)
|
||||
jobject fdo, jlong address, jint len)
|
||||
{
|
||||
jint fd = fdval(env, fdo);
|
||||
ssize_t result = 0;
|
||||
@ -74,28 +72,28 @@ Java_sun_nio_ch_DatagramDispatcher_readv0(JNIEnv *env, jclass clazz,
|
||||
result = recvmsg(fd, &m, 0);
|
||||
if (result < 0 && errno == ECONNREFUSED) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 0);
|
||||
return -2;
|
||||
return IOS_THROWN;
|
||||
}
|
||||
return convertLongReturnVal(env, (jlong)result, JNI_TRUE);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_DatagramDispatcher_write0(JNIEnv *env, jclass clazz,
|
||||
jobject fdo, jlong address, jint len)
|
||||
jobject fdo, jlong address, jint len)
|
||||
{
|
||||
jint fd = fdval(env, fdo);
|
||||
void *buf = (void *)jlong_to_ptr(address);
|
||||
int result = send(fd, buf, len, 0);
|
||||
if (result < 0 && errno == ECONNREFUSED) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 0);
|
||||
return -2;
|
||||
return IOS_THROWN;
|
||||
}
|
||||
return convertReturnVal(env, result, JNI_FALSE);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_nio_ch_DatagramDispatcher_writev0(JNIEnv *env, jclass clazz,
|
||||
jobject fdo, jlong address, jint len)
|
||||
jobject fdo, jlong address, jint len)
|
||||
{
|
||||
jint fd = fdval(env, fdo);
|
||||
struct iovec *iov = (struct iovec *)jlong_to_ptr(address);
|
||||
@ -113,7 +111,7 @@ Java_sun_nio_ch_DatagramDispatcher_writev0(JNIEnv *env, jclass clazz,
|
||||
result = sendmsg(fd, &m, 0);
|
||||
if (result < 0 && errno == ECONNREFUSED) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 0);
|
||||
return -2;
|
||||
return IOS_THROWN;
|
||||
}
|
||||
return convertLongReturnVal(env, (jlong)result, JNI_FALSE);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2020, 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
|
||||
@ -23,21 +23,19 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
#include "sun_nio_ch_DatagramDispatcher.h"
|
||||
|
||||
#include "nio.h"
|
||||
#include "nio_util.h"
|
||||
|
||||
#include "sun_nio_ch_DatagramDispatcher.h"
|
||||
|
||||
|
||||
/**************************************************************
|
||||
* DatagramDispatcher.c
|
||||
@ -45,7 +43,7 @@
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_DatagramDispatcher_read0(JNIEnv *env, jclass clazz, jobject fdo,
|
||||
jlong address, jint len)
|
||||
jlong address, jint len)
|
||||
{
|
||||
/* set up */
|
||||
int i = 0;
|
||||
@ -69,16 +67,18 @@ Java_sun_nio_ch_DatagramDispatcher_read0(JNIEnv *env, jclass clazz, jobject fdo,
|
||||
|
||||
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);
|
||||
if (theErr != WSAEMSGSIZE) {
|
||||
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, "WSARecv failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
JNU_ThrowIOExceptionWithLastError(env, "Write failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
|
||||
return convertReturnVal(env, (jint)read, JNI_TRUE);
|
||||
@ -104,7 +104,7 @@ Java_sun_nio_ch_DatagramDispatcher_readv0(JNIEnv *env, jclass clazz,
|
||||
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 */
|
||||
@ -120,16 +120,18 @@ Java_sun_nio_ch_DatagramDispatcher_readv0(JNIEnv *env, jclass clazz,
|
||||
|
||||
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);
|
||||
if (theErr != WSAEMSGSIZE) {
|
||||
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, "WSARecv failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
JNU_ThrowIOExceptionWithLastError(env, "Write failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
|
||||
return convertLongReturnVal(env, (jlong)read, JNI_TRUE);
|
||||
@ -169,7 +171,7 @@ Java_sun_nio_ch_DatagramDispatcher_write0(JNIEnv *env, jclass clazz,
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 0);
|
||||
return IOS_THROWN;
|
||||
}
|
||||
JNU_ThrowIOExceptionWithLastError(env, "Write failed");
|
||||
JNU_ThrowIOExceptionWithLastError(env, "WSASend failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
|
||||
@ -178,7 +180,7 @@ Java_sun_nio_ch_DatagramDispatcher_write0(JNIEnv *env, jclass clazz,
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_nio_ch_DatagramDispatcher_writev0(JNIEnv *env, jclass clazz,
|
||||
jobject fdo, jlong address, jint len)
|
||||
jobject fdo, jlong address, jint len)
|
||||
{
|
||||
/* set up */
|
||||
int i = 0;
|
||||
@ -219,7 +221,7 @@ Java_sun_nio_ch_DatagramDispatcher_writev0(JNIEnv *env, jclass clazz,
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 0);
|
||||
return IOS_THROWN;
|
||||
}
|
||||
JNU_ThrowIOExceptionWithLastError(env, "Write failed");
|
||||
JNU_ThrowIOExceptionWithLastError(env, "WSASend failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
|
||||
|
||||
140
test/jdk/java/nio/channels/DatagramChannel/Truncate.java
Normal file
140
test/jdk/java/nio/channels/DatagramChannel/Truncate.java
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8053479
|
||||
* @run main Truncate
|
||||
* @summary Test DatagramChannel receive/read where there are fewer bytes remaining
|
||||
* in the buffer than are required to hold the datagram. The remainder of the
|
||||
* datagram should be silently discarded.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Truncate {
|
||||
static final int LARGE_SIZE = 1000;
|
||||
static final int SMALL_SIZE = 100;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
try (DatagramChannel dc = DatagramChannel.open()) {
|
||||
dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
|
||||
|
||||
// not connected
|
||||
testReceiveDiscards(dc);
|
||||
|
||||
// connected
|
||||
dc.connect(dc.getLocalAddress());
|
||||
testReceiveDiscards(dc);
|
||||
testReadDiscards(dc);
|
||||
testScatteringReadDiscards(dc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive a datagram with a buffer that has fewer bytes remaining than are
|
||||
* required to hold the datagram.
|
||||
*/
|
||||
static void testReceiveDiscards(DatagramChannel dc) throws IOException {
|
||||
ByteBuffer largeBuffer = send(dc, LARGE_SIZE, dc.getLocalAddress());
|
||||
|
||||
ByteBuffer smallBuffer = ByteBuffer.allocate(SMALL_SIZE);
|
||||
SocketAddress sender = dc.receive(smallBuffer);
|
||||
assertTrue(sender.equals(dc.getLocalAddress()));
|
||||
|
||||
// check buffer/contents
|
||||
smallBuffer.flip();
|
||||
assertTrue(smallBuffer.remaining() == SMALL_SIZE);
|
||||
assertTrue(Arrays.equals(smallBuffer.array(), 0, SMALL_SIZE,
|
||||
largeBuffer.array(), 0, SMALL_SIZE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a datagram with a buffer that has fewer bytes remaining than are
|
||||
* required to hold the datagram.
|
||||
*/
|
||||
static void testReadDiscards(DatagramChannel dc) throws IOException {
|
||||
ByteBuffer largeBuffer = send(dc, LARGE_SIZE, dc.getRemoteAddress());
|
||||
|
||||
ByteBuffer smallBuffer = ByteBuffer.allocate(SMALL_SIZE);
|
||||
int n = dc.read(smallBuffer);
|
||||
assertTrue(n == SMALL_SIZE);
|
||||
|
||||
// check buffer/contents
|
||||
smallBuffer.flip();
|
||||
assertTrue(smallBuffer.remaining() == SMALL_SIZE);
|
||||
assertTrue(Arrays.equals(smallBuffer.array(), 0, SMALL_SIZE,
|
||||
largeBuffer.array(), 0, SMALL_SIZE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a datagram with an array of buffers that have fewer bytes remaining
|
||||
* than are required to hold the datagram.
|
||||
*/
|
||||
static void testScatteringReadDiscards(DatagramChannel dc) throws IOException {
|
||||
ByteBuffer largeBuffer = send(dc, LARGE_SIZE, dc.getRemoteAddress());
|
||||
|
||||
ByteBuffer smallBuffer1 = ByteBuffer.allocate(SMALL_SIZE);
|
||||
ByteBuffer smallBuffer2 = ByteBuffer.allocate(SMALL_SIZE);
|
||||
ByteBuffer[] bufs = new ByteBuffer[] { smallBuffer1, smallBuffer2 };
|
||||
long n = dc.read(bufs);
|
||||
assertTrue(n == (SMALL_SIZE * bufs.length));
|
||||
|
||||
// check buffer/contents
|
||||
smallBuffer1.flip();
|
||||
assertTrue(smallBuffer1.remaining() == SMALL_SIZE);
|
||||
assertTrue(Arrays.equals(smallBuffer1.array(), 0, SMALL_SIZE,
|
||||
largeBuffer.array(), 0, SMALL_SIZE));
|
||||
smallBuffer2.flip();
|
||||
assertTrue(smallBuffer2.remaining() == SMALL_SIZE);
|
||||
assertTrue(Arrays.equals(smallBuffer2.array(), 0, SMALL_SIZE,
|
||||
largeBuffer.array(), SMALL_SIZE, SMALL_SIZE << 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a datagram of the given size to the given target address.
|
||||
* @return the buffer with the datagram sent to the target address
|
||||
*/
|
||||
static ByteBuffer send(DatagramChannel dc, int size, SocketAddress target)
|
||||
throws IOException
|
||||
{
|
||||
ByteBuffer buffer = ByteBuffer.allocate(size);
|
||||
IntStream.range(0, size).forEach(i -> buffer.put((byte)i));
|
||||
buffer.flip();
|
||||
|
||||
int n = dc.send(buffer, target);
|
||||
assertTrue(n == size);
|
||||
buffer.flip();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void assertTrue(boolean e) {
|
||||
if (!e) throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user