proxy progress

This commit is contained in:
rusefi 2020-07-13 00:44:43 -04:00
parent f26c30de4d
commit deb43f98db
8 changed files with 197 additions and 94 deletions

View File

@ -1 +0,0 @@
rusEFI

View File

@ -1,12 +1,18 @@
package com.rusefi.io.commands;
import com.opensr5.Logger;
import com.rusefi.binaryprotocol.BinaryProtocolCommands;
import com.rusefi.binaryprotocol.IncomingDataBuffer;
import com.rusefi.config.generated.Fields;
import com.rusefi.io.IoStream;
import com.rusefi.io.tcp.BinaryProtocolServer;
import org.jetbrains.annotations.Nullable;
import java.io.EOFException;
import java.io.IOException;
import static com.rusefi.binaryprotocol.IoHelper.checkResponseCode;
public class HelloCommand implements Command {
private final Logger logger;
private final String tsSignature;
@ -20,6 +26,14 @@ public class HelloCommand implements Command {
stream.sendPacket(new byte[]{Fields.TS_HELLO_COMMAND}, logger);
}
@Nullable
public static String getHelloResponse(IncomingDataBuffer incomingData, Logger logger) throws EOFException {
byte[] response = incomingData.getPacket(logger, "[hello]", false);
if (!checkResponseCode(response, BinaryProtocolCommands.RESPONSE_OK))
return null;
return new String(response, 1, response.length - 1);
}
@Override
public byte getCommand() {
return Fields.TS_HELLO_COMMAND;

View File

@ -0,0 +1,53 @@
package com.rusefi;
import com.opensr5.Logger;
import com.rusefi.binaryprotocol.IncomingDataBuffer;
import com.rusefi.config.generated.Fields;
import com.rusefi.io.commands.HelloCommand;
import com.rusefi.io.tcp.BinaryProtocolServer;
import com.rusefi.io.tcp.TcpIoStream;
import com.rusefi.server.SessionDetails;
import java.io.IOException;
import java.net.Socket;
import static com.rusefi.io.tcp.BinaryProtocolServer.getPacketLength;
import static com.rusefi.io.tcp.BinaryProtocolServer.readPromisedBytes;
public class BaseBroadcastingThread {
private final Thread thread;
public BaseBroadcastingThread(Socket socket, SessionDetails sessionDetails, Logger logger) throws IOException {
TcpIoStream stream = new TcpIoStream(logger, socket);
IncomingDataBuffer in = stream.getDataBuffer();
thread = new Thread(() -> {
try {
while (true) {
int length = getPacketLength(in, () -> {
throw new UnsupportedOperationException();
});
BinaryProtocolServer.Packet packet = readPromisedBytes(in, length);
byte[] payload = packet.getPacket();
byte command = payload[0];
if (command == Fields.TS_HELLO_COMMAND) {
new HelloCommand(logger, sessionDetails.toJson()).handle(packet, stream);
} else {
handleCommand();
}
}
} catch (IOException e) {
e.printStackTrace();
}
});
}
protected void handleCommand() {
}
public void start() {
thread.start();
}
}

View File

@ -1,11 +1,6 @@
package com.rusefi;
import com.opensr5.Logger;
import com.rusefi.binaryprotocol.IncomingDataBuffer;
import com.rusefi.config.generated.Fields;
import com.rusefi.io.commands.HelloCommand;
import com.rusefi.io.tcp.BinaryProtocolServer;
import com.rusefi.io.tcp.TcpIoStream;
import com.rusefi.server.ControllerInfo;
import com.rusefi.server.SessionDetails;
@ -13,48 +8,27 @@ import java.io.IOException;
import java.net.Socket;
import static com.rusefi.tools.online.ProxyClient.LOCALHOST;
import static com.rusefi.io.tcp.BinaryProtocolServer.getPacketLength;
import static com.rusefi.io.tcp.BinaryProtocolServer.readPromisedBytes;
public class MockRusEfiDevice {
public static final String TEST_TOKEN_1 = "00000000-1234-1234-1234-123456789012";
private SessionDetails sessionDetails;
private final Logger logger;
public MockRusEfiDevice(String authToken, String signature, Logger logger) {
ControllerInfo ci = new ControllerInfo("vehicle", "make", "code", signature);
sessionDetails = new SessionDetails(ci, authToken, SessionDetails.createOneTimeCode());
sessionDetails = createTestSession(authToken, signature);
this.logger = logger;
}
public void connect(int serverPort) throws IOException {
TcpIoStream stream = new TcpIoStream(logger, new Socket(LOCALHOST, serverPort));
IncomingDataBuffer in = stream.getDataBuffer();
public static SessionDetails createTestSession(String authToken, String signature) {
ControllerInfo ci = new ControllerInfo("vehicle", "make", "code", signature);
new Thread(() -> {
try {
while (true) {
int length = getPacketLength(in, () -> {
throw new UnsupportedOperationException();
});
BinaryProtocolServer.Packet packet = readPromisedBytes(in, length);
byte[] payload = packet.getPacket();
byte command = payload[0];
if (command == Fields.TS_HELLO_COMMAND) {
new HelloCommand(logger, sessionDetails.toJson()).handle(packet, stream);
} else {
handleCommand();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
return new SessionDetails(ci, authToken, SessionDetails.createOneTimeCode());
}
protected void handleCommand() {
public void connect(int serverPort) throws IOException {
BaseBroadcastingThread baseBroadcastingThread = new BaseBroadcastingThread(new Socket(LOCALHOST, serverPort),
sessionDetails,
logger);
baseBroadcastingThread.start();
}
}

View File

@ -1,18 +1,27 @@
package com.rusefi;
import com.opensr5.ConfigurationImage;
import com.opensr5.Logger;
import com.rusefi.config.generated.Fields;
import com.rusefi.io.IoStream;
import com.rusefi.io.commands.HelloCommand;
import com.rusefi.server.Backend;
import com.rusefi.server.ClientConnectionState;
import com.rusefi.server.SessionDetails;
import com.rusefi.server.UserDetails;
import com.rusefi.tools.online.ProxyClient;
import org.junit.Test;
import java.io.IOException;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import static com.rusefi.TestHelper.createIniField;
import static com.rusefi.TestHelper.prepareImage;
import static com.rusefi.tools.online.ProxyClient.LOCALHOST;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@ -26,16 +35,13 @@ public class ServerTest {
@Test
public void testSessionTimeout() throws InterruptedException, IOException {
int serverPort = 7000;
CountDownLatch serverCreated = new CountDownLatch(1);
int httpPort = 8000;
Function<String, UserDetails> userDetailsResolver = authToken -> new UserDetails(authToken.substring(0, 5), authToken.charAt(6));
CountDownLatch serverCreated = new CountDownLatch(1);
CountDownLatch allClientsDisconnected = new CountDownLatch(1);
CountDownLatch onConnected = new CountDownLatch(2);
int httpPort = 8000;
Backend backend = new Backend(userDetailsResolver, httpPort, logger) {
@Override
public void register(ClientConnectionState clientConnectionState) {
@ -52,12 +58,11 @@ public class ServerTest {
};
Backend.runProxy(serverPort, serverCreated, backend);
assertTrue(serverCreated.await(30, TimeUnit.SECONDS));
assertEquals(0, backend.getCount());
new MockRusEfiDevice("00000000-1234-1234-1234-123456789012", "rusEFI 2020.07.06.frankenso_na6.2468827536", logger).connect(serverPort);
new MockRusEfiDevice(MockRusEfiDevice.TEST_TOKEN_1, "rusEFI 2020.07.06.frankenso_na6.2468827536", logger).connect(serverPort);
new MockRusEfiDevice("12345678-1234-1234-1234-123456789012", "rusEFI 2020.07.11.proteus_f4.1986715563", logger).connect(serverPort);
assertTrue(onConnected.await(30, TimeUnit.SECONDS));
@ -72,4 +77,42 @@ public class ServerTest {
}
@Test
public void testRelayWorkflow() throws InterruptedException, IOException {
Function<String, UserDetails> userDetailsResolver = authToken -> new UserDetails(authToken.substring(0, 5), authToken.charAt(6));
int httpPort = 8001;
Backend backend = new Backend(userDetailsResolver, httpPort, logger);
int serverPort = 7001;
CountDownLatch serverCreated = new CountDownLatch(1);
// first start backend server
Backend.runProxy(serverPort, serverCreated, backend);
assertTrue(serverCreated.await(30, TimeUnit.SECONDS));
// create virtual controller
int controllerPort = 7002;
ConfigurationImage controllerImage = prepareImage(240, createIniField(Fields.CYLINDERSCOUNT));
CountDownLatch controllerCreated = new CountDownLatch(1);
TestHelper.createVirtualController(controllerImage, controllerPort, parameter -> controllerCreated.countDown(), logger);
assertTrue(controllerCreated.await(30, TimeUnit.SECONDS));
// start network broadcaster to connect controller with backend since in real life controller has only local serial port it does not have network
IoStream targetEcuSocket = TestHelper.createTestStream(controllerPort, logger);
HelloCommand.send(targetEcuSocket, logger);
String controllerSignature = HelloCommand.getHelloResponse(targetEcuSocket.getDataBuffer(), logger);
SessionDetails sessionDetails = MockRusEfiDevice.createTestSession(MockRusEfiDevice.TEST_TOKEN_1, controllerSignature);
BaseBroadcastingThread baseBroadcastingThread = new BaseBroadcastingThread(new Socket(LOCALHOST, serverPort),
sessionDetails,
logger) {
// todo
};
baseBroadcastingThread.start();
}
}

View File

@ -0,0 +1,58 @@
package com.rusefi;
import com.opensr5.ConfigurationImage;
import com.opensr5.Logger;
import com.opensr5.ini.field.ScalarIniField;
import com.rusefi.binaryprotocol.BinaryProtocolState;
import com.rusefi.config.Field;
import com.rusefi.config.generated.Fields;
import com.rusefi.io.IoStream;
import com.rusefi.io.LinkConnector;
import com.rusefi.io.LinkManager;
import com.rusefi.io.tcp.BinaryProtocolServer;
import com.rusefi.io.tcp.TcpIoStream;
import com.rusefi.tools.online.ProxyClient;
import com.rusefi.tune.xml.Constant;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.net.Socket;
public class TestHelper {
@NotNull
public static ScalarIniField createIniField(Field field) {
return new ScalarIniField(field.getName(), field.getOffset(), "", field.getType(), 1);
}
@NotNull
public static ConfigurationImage prepareImage(int input, ScalarIniField scalarIniField) {
ConfigurationImage ci = new ConfigurationImage(Fields.TOTAL_CONFIG_SIZE);
scalarIniField.setValue(ci, new Constant(scalarIniField.getName(), "", Integer.toString(input)));
return ci;
}
@NotNull
public static BinaryProtocolServer createVirtualController(ConfigurationImage ci, int port, Listener serverSocketCreationCallback, Logger logger) {
BinaryProtocolState state = new BinaryProtocolState();
state.setController(ci);
state.setCurrentOutputs(new byte[1 + Fields.TS_OUTPUT_SIZE]);
LinkManager linkManager = new LinkManager(logger);
linkManager.setConnector(LinkConnector.getDetachedConnector(state));
BinaryProtocolServer server = new BinaryProtocolServer(logger);
server.start(linkManager, port, serverSocketCreationCallback);
return server;
}
@NotNull
public static IoStream createTestStream(int controllerPort, Logger logger) {
IoStream targetEcuSocket;
try {
targetEcuSocket = new TcpIoStream(logger, new Socket(ProxyClient.LOCALHOST, controllerPort));
} catch (IOException e) {
throw new IllegalStateException("Failed to connect to controller " + ProxyClient.LOCALHOST + ":" + controllerPort);
}
return targetEcuSocket;
}
}

View File

@ -3,21 +3,14 @@ package com.rusefi.io;
import com.opensr5.ConfigurationImage;
import com.opensr5.Logger;
import com.opensr5.ini.field.ScalarIniField;
import com.rusefi.Listener;
import com.rusefi.TestHelper;
import com.rusefi.binaryprotocol.BinaryProtocol;
import com.rusefi.binaryprotocol.BinaryProtocolState;
import com.rusefi.config.Field;
import com.rusefi.config.generated.Fields;
import com.rusefi.io.tcp.BinaryProtocolProxy;
import com.rusefi.io.tcp.BinaryProtocolServer;
import com.rusefi.io.tcp.TcpIoStream;
import com.rusefi.tools.online.ProxyClient;
import com.rusefi.tune.xml.Constant;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.io.*;
import java.net.Socket;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -54,13 +47,13 @@ public class TcpCommunicationIntegrationTest {
@Test
public void testConnectAndTransmitImageOverTcpIp() throws InterruptedException {
ScalarIniField iniField = createIniField(Fields.CYLINDERSCOUNT);
ScalarIniField iniField = TestHelper.createIniField(Fields.CYLINDERSCOUNT);
int value = 239;
ConfigurationImage serverImage = prepareImage(value, iniField);
ConfigurationImage serverImage = TestHelper.prepareImage(value, iniField);
int port = 6100;
CountDownLatch serverCreated = new CountDownLatch(1);
BinaryProtocolServer server = createVirtualController(serverImage, port, parameter -> serverCreated.countDown());
BinaryProtocolServer server = TestHelper.createVirtualController(serverImage, port, parameter -> serverCreated.countDown(), LOGGER);
assertTrue(serverCreated.await(30, TimeUnit.SECONDS));
CountDownLatch connectionEstablishedCountDownLatch = new CountDownLatch(1);
@ -94,25 +87,23 @@ public class TcpCommunicationIntegrationTest {
@Test
public void testProxy() throws InterruptedException {
ConfigurationImage serverImage = prepareImage(239, createIniField(Fields.CYLINDERSCOUNT));
ConfigurationImage serverImage = TestHelper.prepareImage(239, TestHelper.createIniField(Fields.CYLINDERSCOUNT));
int controllerPort = 6102;
// create virtual controller
CountDownLatch serverCreated = new CountDownLatch(1);
BinaryProtocolServer server = createVirtualController(serverImage, controllerPort, parameter -> serverCreated.countDown());
BinaryProtocolServer server = TestHelper.createVirtualController(serverImage, controllerPort, parameter -> serverCreated.countDown(), LOGGER);
assertTrue(serverCreated.await(30, TimeUnit.SECONDS));
int proxyPort = 6103;
IoStream targetEcuSocket;
try {
targetEcuSocket = new TcpIoStream(LOGGER, new Socket(ProxyClient.LOCALHOST, controllerPort));
} catch (IOException e) {
throw new IllegalStateException("Failed to connect to controller " + ProxyClient.LOCALHOST + ":" + controllerPort);
}
// connect proxy to virtual controller
IoStream targetEcuSocket = TestHelper.createTestStream(controllerPort, LOGGER);
BinaryProtocolProxy.createProxy(targetEcuSocket, proxyPort);
CountDownLatch connectionEstablishedCountDownLatch = new CountDownLatch(1);
// connect to proxy and read virtual controller through it
LinkManager clientManager = new LinkManager(LOGGER);
clientManager.startAndConnect(ProxyClient.LOCALHOST + ":" + proxyPort, new ConnectionStateListener() {
@Override
@ -130,29 +121,4 @@ public class TcpCommunicationIntegrationTest {
clientManager.stop();
}
@NotNull
private static ScalarIniField createIniField(Field field) {
return new ScalarIniField(field.getName(), field.getOffset(), "", field.getType(), 1);
}
@NotNull
private BinaryProtocolServer createVirtualController(ConfigurationImage ci, int port, Listener serverSocketCreationCallback) {
BinaryProtocolState state = new BinaryProtocolState();
state.setController(ci);
state.setCurrentOutputs(new byte[1 + Fields.TS_OUTPUT_SIZE]);
LinkManager linkManager = new LinkManager(LOGGER);
linkManager.setConnector(LinkConnector.getDetachedConnector(state));
BinaryProtocolServer server = new BinaryProtocolServer(LOGGER);
server.start(linkManager, port, serverSocketCreationCallback);
return server;
}
@NotNull
private ConfigurationImage prepareImage(int input, ScalarIniField scalarIniField) {
ConfigurationImage ci = new ConfigurationImage(Fields.TOTAL_CONFIG_SIZE);
scalarIniField.setValue(ci, new Constant(scalarIniField.getName(), "", Integer.toString(input)));
return ci;
}
}

View File

@ -2,7 +2,6 @@ package com.rusefi.server;
import com.opensr5.Logger;
import com.rusefi.auth.AutoTokenUtil;
import com.rusefi.binaryprotocol.BinaryProtocolCommands;
import com.rusefi.binaryprotocol.IncomingDataBuffer;
import com.rusefi.io.IoStream;
import com.rusefi.io.commands.GetOutputsCommand;
@ -14,8 +13,6 @@ import java.io.IOException;
import java.net.Socket;
import java.util.function.Function;
import static com.rusefi.binaryprotocol.IoHelper.checkResponseCode;
public class ClientConnectionState {
private final Socket clientSocket;
private final Logger logger;
@ -61,10 +58,9 @@ public class ClientConnectionState {
public void requestControllerInfo() throws IOException {
HelloCommand.send(stream, logger);
byte[] response = incomingData.getPacket(logger, "", false);
if (!checkResponseCode(response, BinaryProtocolCommands.RESPONSE_OK))
String jsonString = HelloCommand.getHelloResponse(incomingData, logger);
if (jsonString == null)
return;
String jsonString = new String(response, 1, response.length - 1);
sessionDetails = SessionDetails.valueOf(jsonString);
if (!AutoTokenUtil.isToken(sessionDetails.getAuthToken()))
throw new IOException("Invalid token in " + jsonString);