Fix daemon connection race condition (#1078)

The Server was using a SynchrnousQueue to coordinate the main thread
and the background thread that receives the request from the client.
A SynchronousQueue only allows insertions when a corresponding call
to `get` is in progress. However, since the receiver thread is started
before the call to `get`, there was a short time window, where the call
to `queue.offer` could fail and simply return `false`. This return code
was ignored.

A possible solution would have been to call `put` instead of `offer`,
but I decided to replace the queue with a Future, since we only wait
for a single element.

Co-authored-by: Stefan Oehme <st.oehme@gmail.com>
This commit is contained in:
Guillaume Nodet
2024-07-19 13:42:11 +02:00
committed by GitHub
parent 903aa32dd6
commit 6189475f1b

View File

@@ -37,11 +37,11 @@ import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
@@ -271,13 +271,13 @@ public class Server implements AutoCloseable, Runnable {
try (DaemonConnection connection = new DaemonConnection(socket)) {
LOGGER.info("Waiting for request");
SynchronousQueue<Message> request = new SynchronousQueue<>();
CompletableFuture<Message> request = new CompletableFuture<>();
new DaemonThread(() -> {
Message message = connection.receive();
request.offer(message);
request.complete(message);
})
.start();
Message message = request.poll(1, TimeUnit.MINUTES);
Message message = request.get(1, TimeUnit.MINUTES);
if (message == null) {
LOGGER.info("Could not receive request after one minute, dropping connection");
updateState(DaemonState.Idle);