switchboardPortListener;
@Autowired
- private SharingManager sharingManager; // TODO the tunnel will run through it.
+ private SharingManager sharingManager; // the tunnel will run through it.
// @Autowired
// private TunnelRegistry tunnelRegistry;
@@ -94,14 +94,14 @@ private void handleNewChannel(AsynchronousSocketChannel channel) {
UUID uuid = new UUID(headerBuffer.getLong(), headerBuffer.getLong());
long targetId = headerBuffer.getLong();
- Object context = sharingManager.httpClientEndConnected(uuid, targetId);
+ Object context = sharingManager.switchboardConnected(uuid, targetId);
if (context != null) {
try {
IOTools.asyncWriteWholeBuffer(channel, ByteBuffer.wrap(new byte[] {0})) // send 0 = OK
.thenAccept(x -> {
try {
log.info("Switchboard proxy is ready: {}.{}", uuid, targetId);
- sharingManager.httpClientEndConnectionReady(context, channel);
+ sharingManager.switchboardConnectionReady(context, channel);
} catch (Exception e1) {
reportErrorThenClose(channel, 2, e1.toString());
}
diff --git a/src/main/java/org/aalku/joatse/cloud/tools/io/SwitchboardExternalClient.java b/src/main/java/org/aalku/joatse/cloud/tools/io/SwitchboardExternalClient.java
new file mode 100644
index 0000000..558ed16
--- /dev/null
+++ b/src/main/java/org/aalku/joatse/cloud/tools/io/SwitchboardExternalClient.java
@@ -0,0 +1,140 @@
+package org.aalku.joatse.cloud.tools.io;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * This main class allows us to use the Switchboard system from the command
+ * line.
+ *
+ * The process will connect to the specified (switchboard) port and it will tell
+ * it to connect to certain tunnel and target, and then it will redirect stdin
+ * to the socket and the socket to stdout.
+ *
+ * You could use it like this to pass an SSH connection through a tunnel:
+ *
+ *
+ * ssh -o 'ProxyCommand java -jar file.jar ' @ ...
+ *
+ *
+ * The is needed in the command line but it's not really used, just to associate the pub key to that name.
+ *
+ */
+public class SwitchboardExternalClient {
+
+ private static final int BUFFER_SIZE = 1024*128;
+
+ public static void main(String[] args) {
+ try {
+ String host = args[0];
+ int port = Integer.parseInt(args[1], 10);
+ UUID uuid = UUID.fromString(args[2]);
+ long targetId = Long.parseLong(args[3], 10);
+
+ // Connect
+ SocketChannel client = SocketChannel.open();
+ client.configureBlocking(true);
+ client.connect(new InetSocketAddress(host, port));
+ // Say hello
+ ByteBuffer hello = ByteBuffer.allocate(16 + 8);
+ hello.putLong(uuid.getMostSignificantBits());
+ hello.putLong(uuid.getLeastSignificantBits());
+ hello.putLong(targetId);
+ hello.flip();
+ while (hello.hasRemaining()) {
+ client.write(hello);
+ }
+ hello.flip();
+ hello = ByteBuffer.allocate(1);
+ int x;
+ if ((x = client.read(hello)) != 1) {
+ throw new IOException("Couldn't read switchboard response: " + x);
+ }
+ hello.flip();
+ if (hello.get() != 0) {
+ hello = ByteBuffer.allocate(BUFFER_SIZE);
+ while (client.read(hello) >= 0);
+ hello.flip();
+ hello.limit(hello.limit() - 1); // \0 at the end
+ throw new IOException("Negative response from switchboard: " + hello.asCharBuffer().toString());
+ }
+ hello = null;
+
+ // Two way comm until exception or both ends closed
+ CompletableFuture resOut = copyThread(Channels.newChannel(System.in), client, "thOut");
+ CompletableFuture resIn = copyThread(client, Channels.newChannel(System.out), "thIn");
+ CompletableFuture.allOf(resIn, resOut).exceptionally(e->{
+ resIn.cancel(true);
+ resOut.cancel(true);
+ return null;
+ }).get();
+
+ try {
+ client.close();
+ } catch (Exception e) {
+ }
+ } catch (Exception e) {
+ e.printStackTrace(System.err);
+ System.exit(1);
+ }
+
+ }
+
+ private static CompletableFuture copyThread(ReadableByteChannel in, WritableByteChannel out, String name) {
+ CompletableFuture res = new CompletableFuture();
+ new Thread(name) {
+ volatile boolean closed = false;
+
+ {
+ this.setDaemon(true);
+ this.start();
+ res.exceptionally(e->{
+ try {
+ in.close();
+ } catch (Exception e1) {
+ }
+ try {
+ out.close();
+ } catch (Exception e1) {
+ }
+ closed = true;
+ this.interrupt();
+ return null;
+ });
+ }
+ public void run() {
+ ByteBuffer buff = ByteBuffer.allocate(BUFFER_SIZE);
+ while (true) {
+ try {
+ int c = (!closed && buff.capacity() > 0) ? in.read(buff) : 0;
+ int p = buff.position();
+ if (c < 0) {
+ closed = true;
+ if (p == 0) {
+ res.complete(null);
+ return;
+ }
+ }
+ if (p > 0) {
+ buff.flip();
+ out.write(buff);
+ buff.compact();
+ }
+ } catch (IOException e) {
+ res.completeExceptionally(e);
+ return;
+ }
+ }
+ };
+ };
+ return res;
+ }
+
+}
diff --git a/src/main/java/org/aalku/joatse/cloud/web/ConfirmController.java b/src/main/java/org/aalku/joatse/cloud/web/ConfirmController.java
index 05c4e29..e060d2a 100644
--- a/src/main/java/org/aalku/joatse/cloud/web/ConfirmController.java
+++ b/src/main/java/org/aalku/joatse/cloud/web/ConfirmController.java
@@ -36,6 +36,7 @@ public class ConfirmController {
public final static String CONFIRM_SESSION_KEY_HASH = "CONFIRM_SESSION_KEY_HASH";
+ @SuppressWarnings("unused")
private Logger log = LoggerFactory.getLogger(ConfirmController.class);
@Autowired
diff --git a/src/main/java/org/aalku/joatse/cloud/web/HeaderController.java b/src/main/java/org/aalku/joatse/cloud/web/HeaderController.java
index c3e3ff5..859c335 100644
--- a/src/main/java/org/aalku/joatse/cloud/web/HeaderController.java
+++ b/src/main/java/org/aalku/joatse/cloud/web/HeaderController.java
@@ -15,6 +15,7 @@
@Controller
public class HeaderController {
+ @SuppressWarnings("unused")
private Logger log = LoggerFactory.getLogger(HeaderController.class);
@Autowired