Skip to content

Commit 864fe80

Browse files
committed
Make byte buffer size configurable. Add configurable whitelist of proxy targets. Factor out common IO code. Switch to using Vert.x server. Add support for HTTPS. Handle exceptions seen when connection dies between client and server. Refactored domain proxy in general for consistency.
1 parent 5277625 commit 864fe80

File tree

22 files changed

+413
-288
lines changed

22 files changed

+413
-288
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
FROM quay.io/redhat-appstudio/buildah:v1.35.4@sha256:3d3575bb7d0df64abcf1f22f06e82101a945d03317db1f3caac12814f796d01c
2+
RUN dnf install -y iproute
3+
COPY client/target/domain-proxy-client-999-SNAPSHOT-runner /app/domain-proxy-client-runner
4+
COPY server/target/domain-proxy-server-999-SNAPSHOT-runner /app/domain-proxy-server-runner

java-components/domainproxy/client/pom.xml renamed to java-components/domain-proxy/client/pom.xml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
<modelVersion>4.0.0</modelVersion>
55
<parent>
66
<groupId>io.github.redhat-appstudio.jvmbuild</groupId>
7-
<artifactId>domainproxy-parent</artifactId>
7+
<artifactId>domain-proxy-parent</artifactId>
88
<version>999-SNAPSHOT</version>
99
</parent>
10-
<artifactId>domainproxy-client</artifactId>
10+
<artifactId>domain-proxy-client</artifactId>
1111

1212
<dependencies>
1313
<dependency>
@@ -24,6 +24,10 @@
2424
<artifactId>rest-assured</artifactId>
2525
<scope>test</scope>
2626
</dependency>
27+
<dependency>
28+
<groupId>io.github.redhat-appstudio.jvmbuild</groupId>
29+
<artifactId>domain-proxy-common</artifactId>
30+
</dependency>
2731
</dependencies>
2832

2933
<build>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.redhat.hacbs.domainproxy.client;
2+
3+
import java.io.IOException;
4+
import java.net.ServerSocket;
5+
import java.net.Socket;
6+
import java.net.UnixDomainSocketAddress;
7+
import java.nio.channels.SocketChannel;
8+
9+
import jakarta.annotation.PostConstruct;
10+
import jakarta.inject.Inject;
11+
import jakarta.inject.Singleton;
12+
13+
import org.eclipse.microprofile.config.inject.ConfigProperty;
14+
15+
import com.redhat.hacbs.domainproxy.common.CommonIOUtil;
16+
17+
import io.quarkus.logging.Log;
18+
import io.quarkus.runtime.Quarkus;
19+
import io.quarkus.runtime.Startup;
20+
21+
@Startup
22+
@Singleton
23+
public class DomainProxyClient {
24+
25+
@Inject
26+
@ConfigProperty(name = "client-domain-socket")
27+
String domainSocket;
28+
29+
@Inject
30+
@ConfigProperty(name = "client-http-port")
31+
int clientHttpPort;
32+
33+
@Inject
34+
@ConfigProperty(name = "byte-buffer-size")
35+
int byteBufferSize;
36+
37+
@PostConstruct
38+
public void start() {
39+
Log.info("Starting domain proxy client...");
40+
new Thread(() -> {
41+
try (final ServerSocket serverSocket = new ServerSocket(clientHttpPort)) {
42+
while (true) {
43+
final Socket socket = serverSocket.accept();
44+
final UnixDomainSocketAddress address = UnixDomainSocketAddress.of(domainSocket);
45+
final SocketChannel channel = SocketChannel.open(address);
46+
// write from socket to channel
47+
CommonIOUtil.createSocketToChannelWriter(byteBufferSize, socket, channel).start();
48+
// write from channel to socket
49+
CommonIOUtil.createChannelToSocketWriter(byteBufferSize, channel, socket).start();
50+
}
51+
} catch (final IOException e) {
52+
Log.errorf(e, "Error initialising domain proxy client");
53+
}
54+
Quarkus.asyncExit();
55+
}).start();
56+
}
57+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
client-domain-socket=${DOMAIN_SOCKET:/tmp/domainserver}
2+
client-http-port=8080
3+
byte-buffer-size=${BYTE_BUFFER_SIZE:1024}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>io.github.redhat-appstudio.jvmbuild</groupId>
7+
<artifactId>domain-proxy-parent</artifactId>
8+
<version>999-SNAPSHOT</version>
9+
</parent>
10+
<artifactId>domain-proxy-common</artifactId>
11+
12+
<dependencies>
13+
<dependency>
14+
<groupId>org.jboss.logging</groupId>
15+
<artifactId>jboss-logging</artifactId>
16+
</dependency>
17+
</dependencies>
18+
</project>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package com.redhat.hacbs.domainproxy.common;
2+
3+
import java.io.IOException;
4+
import java.net.Socket;
5+
import java.net.SocketException;
6+
import java.nio.ByteBuffer;
7+
import java.nio.channels.AsynchronousCloseException;
8+
import java.nio.channels.SocketChannel;
9+
10+
import org.jboss.logging.Logger;
11+
12+
public final class CommonIOUtil {
13+
14+
private static final Logger LOG = Logger.getLogger(CommonIOUtil.class);
15+
16+
public static Thread createSocketToChannelWriter(final int byteBufferSize, final Socket socket,
17+
final SocketChannel channel) {
18+
// write from socket to channel
19+
return new Thread(() -> {
20+
int r;
21+
final byte[] buf = new byte[byteBufferSize];
22+
int bytesWritten = 0;
23+
LOG.info("Writing from socket to channel");
24+
try {
25+
while ((r = socket.getInputStream().read(buf)) > 0) {
26+
channel.write(ByteBuffer.wrap(buf, 0, r));
27+
bytesWritten += r;
28+
}
29+
} catch (final SocketException ignore) {
30+
LOG.info("Socket closed");
31+
} catch (final IOException e) {
32+
LOG.errorf(e, "Error writing from socket to channel");
33+
} finally {
34+
try {
35+
channel.close();
36+
} catch (final Exception e) {
37+
LOG.errorf(e, "Error closing channel");
38+
}
39+
try {
40+
socket.close();
41+
} catch (final IOException e) {
42+
LOG.errorf(e, "Error closing socket");
43+
}
44+
}
45+
LOG.infof("Wrote %d bytes from socket to channel", bytesWritten);
46+
});
47+
}
48+
49+
public static Thread createChannelToSocketWriter(final int byteBufferSize, final SocketChannel channel,
50+
final Socket socket) {
51+
// write from channel to socket
52+
return new Thread(() -> {
53+
int r;
54+
final ByteBuffer buf = ByteBuffer.allocate(byteBufferSize);
55+
buf.clear();
56+
int bytesWritten = 0;
57+
LOG.info("Writing from channel to socket");
58+
try {
59+
while ((r = channel.read(buf)) > 0) {
60+
buf.flip();
61+
socket.getOutputStream().write(buf.array(), buf.arrayOffset(), buf.remaining());
62+
buf.clear();
63+
bytesWritten += r;
64+
}
65+
} catch (final AsynchronousCloseException ignore) {
66+
LOG.info("Channel closed");
67+
} catch (final Exception e) {
68+
LOG.errorf(e, "Error writing from channel to socket");
69+
} finally {
70+
try {
71+
channel.close();
72+
} catch (final IOException e) {
73+
LOG.errorf(e, "Error closing channel");
74+
}
75+
try {
76+
socket.close();
77+
} catch (final IOException e) {
78+
LOG.errorf(e, "Error closing socket");
79+
}
80+
}
81+
LOG.infof("Wrote %d bytes from channel to socket", bytesWritten);
82+
});
83+
}
84+
}

java-components/domainproxy/pom.xml renamed to java-components/domain-proxy/pom.xml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<artifactId>jvm-build-service-parent</artifactId>
88
<version>999-SNAPSHOT</version>
99
</parent>
10-
<artifactId>domainproxy-parent</artifactId>
10+
<artifactId>domain-proxy-parent</artifactId>
1111
<packaging>pom</packaging>
1212
<properties>
1313
<skipITs>true</skipITs>
@@ -16,8 +16,19 @@
1616
<modules>
1717
<module>server</module>
1818
<module>client</module>
19+
<module>common</module>
1920
</modules>
2021

22+
<dependencyManagement>
23+
<dependencies>
24+
<dependency>
25+
<groupId>io.github.redhat-appstudio.jvmbuild</groupId>
26+
<artifactId>domain-proxy-common</artifactId>
27+
<version>${project.version}</version>
28+
</dependency>
29+
</dependencies>
30+
</dependencyManagement>
31+
2132
<profiles>
2233
<profile>
2334
<id>native</id>

java-components/domainproxy/server/pom.xml renamed to java-components/domain-proxy/server/pom.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
<modelVersion>4.0.0</modelVersion>
55
<parent>
66
<groupId>io.github.redhat-appstudio.jvmbuild</groupId>
7-
<artifactId>domainproxy-parent</artifactId>
7+
<artifactId>domain-proxy-parent</artifactId>
88
<version>999-SNAPSHOT</version>
99
</parent>
10-
<artifactId>domainproxy-server</artifactId>
10+
<artifactId>domain-proxy-server</artifactId>
1111

1212
<dependencies>
1313
<dependency>
1414
<groupId>io.quarkus</groupId>
15-
<artifactId>quarkus-rest</artifactId>
15+
<artifactId>quarkus-vertx</artifactId>
1616
</dependency>
1717
<dependency>
1818
<groupId>io.quarkus</groupId>
@@ -30,7 +30,7 @@
3030
</dependency>
3131
<dependency>
3232
<groupId>io.github.redhat-appstudio.jvmbuild</groupId>
33-
<artifactId>common-maven</artifactId>
33+
<artifactId>domain-proxy-common</artifactId>
3434
</dependency>
3535
</dependencies>
3636

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.redhat.hacbs.domainproxy;
2+
3+
import java.io.IOException;
4+
import java.net.Socket;
5+
import java.net.StandardProtocolFamily;
6+
import java.net.UnixDomainSocketAddress;
7+
import java.nio.channels.ServerSocketChannel;
8+
import java.nio.channels.SocketChannel;
9+
import java.nio.file.Files;
10+
import java.nio.file.Path;
11+
12+
import jakarta.annotation.PostConstruct;
13+
import jakarta.inject.Inject;
14+
import jakarta.inject.Singleton;
15+
16+
import org.eclipse.microprofile.config.inject.ConfigProperty;
17+
18+
import com.redhat.hacbs.domainproxy.common.CommonIOUtil;
19+
20+
import io.quarkus.logging.Log;
21+
import io.quarkus.runtime.Quarkus;
22+
import io.quarkus.runtime.Startup;
23+
24+
@Startup
25+
@Singleton
26+
public class DomainProxyServer {
27+
28+
static final String HOST = "localhost";
29+
30+
@Inject
31+
@ConfigProperty(name = "server-domain-socket")
32+
String domainSocket;
33+
34+
@Inject
35+
@ConfigProperty(name = "server-http-port")
36+
int serverHttpPort;
37+
38+
@Inject
39+
@ConfigProperty(name = "byte-buffer-size")
40+
int byteBufferSize;
41+
42+
@PostConstruct
43+
public void start() {
44+
Log.info("Starting domain proxy server...");
45+
new Thread(() -> {
46+
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
47+
try {
48+
Files.delete(Path.of(domainSocket));
49+
} catch (final IOException e) {
50+
Log.errorf(e, "Error deleting domain socket");
51+
}
52+
}));
53+
try (final ServerSocketChannel serverChannel = ServerSocketChannel.open(StandardProtocolFamily.UNIX)) {
54+
final UnixDomainSocketAddress address = UnixDomainSocketAddress.of(domainSocket);
55+
serverChannel.bind(address);
56+
while (true) {
57+
final SocketChannel channel = serverChannel.accept();
58+
final Socket socket = new Socket(HOST, serverHttpPort);
59+
// write from socket to channel
60+
CommonIOUtil.createSocketToChannelWriter(byteBufferSize, socket, channel).start();
61+
// write from channel to socket
62+
CommonIOUtil.createChannelToSocketWriter(byteBufferSize, channel, socket).start();
63+
}
64+
} catch (final IOException e) {
65+
Log.errorf(e, "Error initialising domain proxy server");
66+
}
67+
Quarkus.asyncExit();
68+
}).start();
69+
}
70+
}

0 commit comments

Comments
 (0)