Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8265367: [macos-aarch64] 3 java/net/httpclient/websocket tests fail with "IOException: No buffer space available" #487

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, 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
@@ -1272,6 +1272,14 @@ int getReceiveBufferSize() {
);
}

// used for testing
int getSendBufferSize() {
return Utils.getIntegerNetProperty(
"jdk.httpclient.sendBufferSize",
0 // only set the size if > 0
);
}

// Optimization for reading SSL encrypted data
// --------------------------------------------

@@ -212,10 +212,23 @@ final FlowTube getConnectionFlow() {
try {
this.chan = SocketChannel.open();
chan.configureBlocking(false);
trySetReceiveBufferSize(client.getReceiveBufferSize());
if (debug.on()) {
int bufsize = getInitialBufferSize();
int bufsize = getSoReceiveBufferSize();
debug.log("Initial receive buffer size is: %d", bufsize);
bufsize = getSoSendBufferSize();
debug.log("Initial send buffer size is: %d", bufsize);
}
if (trySetReceiveBufferSize(client.getReceiveBufferSize())) {
if (debug.on()) {
int bufsize = getSoReceiveBufferSize();
debug.log("Receive buffer size configured: %d", bufsize);
}
}
if (trySetSendBufferSize(client.getSendBufferSize())) {
if (debug.on()) {
int bufsize = getSoSendBufferSize();
debug.log("Send buffer size configured: %d", bufsize);
}
}
chan.setOption(StandardSocketOptions.TCP_NODELAY, true);
// wrap the channel in a Tube for async reading and writing
@@ -225,26 +238,52 @@ final FlowTube getConnectionFlow() {
}
}

private int getInitialBufferSize() {
private int getSoReceiveBufferSize() {
try {
return chan.getOption(StandardSocketOptions.SO_RCVBUF);
} catch(IOException x) {
} catch (IOException x) {
if (debug.on())
debug.log("Failed to get initial receive buffer size on %s", chan);
}
return 0;
}

private int getSoSendBufferSize() {
try {
return chan.getOption(StandardSocketOptions.SO_SNDBUF);
} catch (IOException x) {
if (debug.on())
debug.log("Failed to get initial receive buffer size on %s", chan);
}
return 0;
}

private void trySetReceiveBufferSize(int bufsize) {
private boolean trySetReceiveBufferSize(int bufsize) {
try {
if (bufsize > 0) {
chan.setOption(StandardSocketOptions.SO_RCVBUF, bufsize);
return true;
}
} catch(IOException x) {
} catch (IOException x) {
if (debug.on())
debug.log("Failed to set receive buffer size to %d on %s",
bufsize, chan);
}
return false;
}

private boolean trySetSendBufferSize(int bufsize) {
try {
if (bufsize > 0) {
chan.setOption(StandardSocketOptions.SO_SNDBUF, bufsize);
return true;
}
} catch (IOException x) {
if (debug.on())
debug.log("Failed to set send buffer size to %d on %s",
bufsize, chan);
}
return false;
}

@Override
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@@ -43,7 +43,6 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import static java.net.http.HttpClient.newHttpClient;
import static org.testng.Assert.assertFalse;

public class BlowupOutputQueue extends PendingOperations {
@@ -103,7 +102,7 @@ protected CompletionStage<?> onPing0(WebSocket webSocket,
return null;
}
};
webSocket = newHttpClient().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), listener)
.join();
CharBuffer data = CharBuffer.allocate(65536);
@@ -92,6 +92,7 @@ public class DummyWebSocketServer implements Closeable {
private volatile InetSocketAddress address;
private ByteBuffer read = ByteBuffer.allocate(16384);
private final CountDownLatch readReady = new CountDownLatch(1);
private volatile int receiveBufferSize;

private static class Credentials {
private final String name;
@@ -217,6 +218,11 @@ public ByteBuffer read() throws InterruptedException {
return read.duplicate().asReadOnlyBuffer().flip();
}

public void setReceiveBufferSize(int bufsize) {
assert ssc == null : "Must configure before calling open()";
this.receiveBufferSize = bufsize;
}

public void open() throws IOException {
err.println("Starting");
if (!started.compareAndSet(false, true)) {
@@ -225,6 +231,15 @@ public void open() throws IOException {
ssc = ServerSocketChannel.open();
try {
ssc.configureBlocking(true);
var bufsize = receiveBufferSize;
if (bufsize > 0) {
err.printf("Configuring receive buffer size to %d%n", bufsize);
try {
ssc.setOption(StandardSocketOptions.SO_RCVBUF, bufsize);
} catch (IOException x) {
err.printf("Failed to configure receive buffer size to %d%n", bufsize);
}
}
ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
address = (InetSocketAddress) ssc.getLocalAddress();
thread.start();
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@@ -37,8 +37,6 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpClient.newBuilder;

public class PendingBinaryPingClose extends PendingOperations {

@@ -51,7 +49,7 @@ public void pendingBinaryPingClose(boolean last) throws Exception {
repeatable(() -> {
server = Support.notReadingServer();
server.open();
webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), new WebSocket.Listener() { })
.join();
ByteBuffer data = ByteBuffer.allocate(65536);
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@@ -51,7 +51,7 @@ public void pendingBinaryPongClose(boolean last) throws Exception {
repeatable(() -> {
server = Support.notReadingServer();
server.open();
webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), new WebSocket.Listener() { })
.join();
ByteBuffer data = ByteBuffer.allocate(65536);
@@ -21,15 +21,19 @@
* questions.
*/

import org.testng.annotations.AfterTest;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.DataProvider;

import java.io.IOException;
import java.net.http.HttpClient;
import java.net.http.WebSocket;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionStage;
import java.util.function.BooleanSupplier;

import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpClient.newBuilder;

/* Common infrastructure for tests that check pending operations */
public class PendingOperations {

@@ -44,8 +48,16 @@ public class PendingOperations {
DummyWebSocketServer server;
WebSocket webSocket;

@AfterTest
protected HttpClient httpClient() {
return newBuilder().proxy(NO_PROXY).build();
}

@AfterMethod
public void cleanup() {
// make sure we have a trace both on System.out and System.err
// to help with diagnosis.
System.out.println("cleanup: Closing server");
System.err.println("cleanup: Closing server");
server.close();
webSocket.abort();
}
@@ -72,8 +84,8 @@ static boolean isMacOS() {

private static final int ITERATIONS = 3;

static void repeatable(Callable<Void> callable,
BooleanSupplier repeatCondition)
void repeatable(Callable<Void> callable,
BooleanSupplier repeatCondition)
throws Exception
{
int iterations = 0;
@@ -87,10 +99,16 @@ static void repeatable(Callable<Void> callable,
if (isMacOS() && repeatCondition.getAsBoolean()) {
// ## This is loathsome, but necessary because of observed
// ## automagic socket buffer resizing on recent macOS platforms
try { cleanup(); } catch (Throwable x) {}
continue;
} else {
throw e;
}
} finally {
// gives some time to gc to cleanup any resource that might
// be eligible for garbage collection
System.gc();
Thread.sleep(100);
}
} while (iterations <= ITERATIONS);
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@@ -39,8 +39,6 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpClient.newBuilder;

public class PendingPingBinaryClose extends PendingOperations {

@@ -53,7 +51,7 @@ public void pendingPingBinaryClose(boolean last) throws Exception {
repeatable( () -> {
server = Support.notReadingServer();
server.open();
webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), new WebSocket.Listener() { })
.join();
ByteBuffer data = ByteBuffer.allocate(125);
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@@ -39,8 +39,6 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpClient.newBuilder;

public class PendingPingTextClose extends PendingOperations {

@@ -53,7 +51,7 @@ public void pendingPingTextClose(boolean last) throws Exception {
repeatable( () -> {
server = Support.notReadingServer();
server.open();
webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), new WebSocket.Listener() { })
.join();
ByteBuffer data = ByteBuffer.allocate(125);
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@@ -39,8 +39,6 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpClient.newBuilder;

public class PendingPongBinaryClose extends PendingOperations {

@@ -53,7 +51,7 @@ public void pendingPongBinaryClose(boolean last) throws Exception {
repeatable( () -> {
server = Support.notReadingServer();
server.open();
webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), new WebSocket.Listener() { })
.join();
ByteBuffer data = ByteBuffer.allocate(125);
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@@ -40,10 +40,6 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpClient.newBuilder;
import static java.net.http.HttpClient.newHttpClient;

public class PendingPongTextClose extends PendingOperations {

CompletableFuture<WebSocket> cfText;
@@ -55,7 +51,7 @@ public void pendingPongTextClose(boolean last) throws Exception {
repeatable( () -> {
server = Support.notReadingServer();
server.open();
webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), new WebSocket.Listener() { })
.join();
ByteBuffer data = ByteBuffer.allocate(125);
@@ -79,7 +75,7 @@ public void pendingPongTextClose(boolean last) throws Exception {
assertHangs(cfText);
cfClose = webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
assertHangs(cfClose);
return null;
return null;
}, () -> cfPong.isDone() ? true : false);
webSocket.abort();
assertFails(IOE, cfPong);