@@ -0,0 +1,2704 @@
+/*%0A * Copyright (c) 2021, PostgreSQL Global Development Group%0A * See the LICENSE file in the project root for more information.%0A */%0A%0Apackage org.postgresql.test.util;%0A%0Aimport org.postgresql.test.TestUtil;%0A%0Aimport java.io.Closeable;%0Aimport java.io.IOException;%0Aimport java.io.InputStream;%0Aimport java.io.OutputStream;%0Aimport java.net.ServerSocket;%0Aimport java.net.Socket;%0Aimport java.net.SocketTimeoutException;%0A%0A/**%0A * Proxy server that allows for pretending that traffic did not arrive at the%0A * destination. Client connections created prior to a call to%0A * stopForwardingOlderClients() will not have any subsequent traffic forwarded.%0A * Bytes are transferred one-by-one. If either side of the connection reaches%0A * EOF then both sides are immediately closed.%0A */%0Apublic class StrangeProxyServer implements Closeable %7B%0A  private final ServerSocket serverSock;%0A  private volatile boolean keepRunning = true;%0A  private volatile long minAcceptedAt = 0;%0A%0A  public StrangeProxyServer(String destHost, int destPort) throws IOException %7B%0A    this.serverSock = new ServerSocket(0);%0A    this.serverSock.setSoTimeout(100);%0A    doAsync(() -%3E %7B%0A      while (keepRunning) %7B%0A        try %7B%0A          Socket sourceSock = serverSock.accept();%0A          final long acceptedAt = System.currentTimeMillis();%0A          Socket destSock = new Socket(destHost, destPort);%0A          doAsync(() -%3E transferOneByOne(acceptedAt, sourceSock, destSock));%0A          doAsync(() -%3E transferOneByOne(acceptedAt, destSock, sourceSock));%0A        %7D catch (SocketTimeoutException ignore) %7B%0A        %7D catch (IOException e) %7B%0A          throw new RuntimeException(e);%0A        %7D%0A      %7D%0A      TestUtil.closeQuietly(serverSock);%0A    %7D);%0A  %7D%0A%0A  public int getServerPort() %7B%0A    return this.serverSock.getLocalPort();%0A  %7D%0A%0A  @Override%0A  public void close() %7B%0A    this.keepRunning = false;%0A  %7D%0A%0A  public void stopForwardingOlderClients() %7B%0A    this.minAcceptedAt = System.currentTimeMillis();%0A  %7D%0A%0A  private void doAsync(Runnable task) %7B%0A    Thread thread = new Thread(task);%0A    thread.setDaemon(true);%0A    thread.start();%0A  %7D%0A%0A  private void transferOneByOne(long acceptedAt, Socket source, Socket dest) %7B%0A    try %7B%0A      InputStream in = source.getInputStream();%0A      OutputStream out = dest.getOutputStream();%0A      int b;%0A      // As long as we're running try to read%0A      while (keepRunning && (b = in.read()) %3E= 0) %7B%0A        // But only write it if the client is newer than the last call to stopForwardingOlderClients()%0A        if (acceptedAt %3E= minAcceptedAt) %7B%0A          out.write(b);%0A        %7D%0A      %7D%0A    %7D catch (IOException ignore) %7B%0A    %7D finally %7B%0A      TestUtil.closeQuietly(source);%0A      TestUtil.closeQuietly(dest);%0A    %7D%0A  %7D%0A%7D%0A

Add StrangeProxyServer