+ * Used as a form of validation for packets, prevents other Apps that connect + * with the server from sending unexpected data and inexplicably causing huge byte array allocations. + *
+ * Since the server only accepts {@link NetworkExtensionInfo.INCOMING_MESSAGES_IDS#EXTENSIONINFO} packets, + * this value is calculated based on that packet. + */ + private static final int MAX_PACKET_BODY_SIZE = (MAX_STRING_SIZE * 6) + (BOOLEAN_SIZE * 4); + + /** + * The port at which the {@link #serverSocket} is listening for incoming connections. + */ public static int extensionPort = -1; - private ServerSocket serverSocket; @Override public void startProducing(ExtensionProducerObserver observer) { -// serverSocket = new ServerSocket(0); - int port = 9092; - boolean serverSetup = false; - while (!serverSetup) { - serverSetup = createServer(port); - port++; - } + /* + Initialise the serverSocket at the argued port. + */ + int port = PORT_ONSET; + while (!createServer(port)) + ++port; + /* + Start connection listener thread. + */ new Thread(() -> { + try { + while (!serverSocket.isClosed()) { - Socket extensionSocket = serverSocket.accept(); + + // accept a new connection + final Socket extensionSocket = serverSocket.accept(); extensionSocket.setTcpNoDelay(true); + /* + Start client session handler thread. + */ new Thread(() -> { + try { + + // write INFOREQUEST packet to client synchronized (extensionSocket) { extensionSocket.getOutputStream().write((new HPacket(NetworkExtensionInfo.OUTGOING_MESSAGES_IDS.INFOREQUEST)).toBytes()); } - InputStream inputStream = extensionSocket.getInputStream(); - DataInputStream dIn = new DataInputStream(inputStream); + final DataInputStream dIn = new DataInputStream(extensionSocket.getInputStream()); + // listen to incoming data from client while (!extensionSocket.isClosed()) { - int length = dIn.readInt(); - byte[] headerandbody = new byte[length + 4]; + final int bodyLength = dIn.readInt() - Short.BYTES; + final short headerId = dIn.readShort(); - int amountRead = 0; - while (amountRead < length) { - amountRead += dIn.read(headerandbody, 4 + amountRead, Math.min(dIn.available(), length - amountRead)); - } + if (headerId == NetworkExtensionInfo.INCOMING_MESSAGES_IDS.EXTENSIONINFO) { - HPacket packet = new HPacket(headerandbody); - packet.fixLength(); + if (bodyLength > MAX_PACKET_BODY_SIZE) { + System.err.printf("Incoming packet(h=%d, l=%d) exceeds max packet body size %d.\n", headerId, bodyLength, MAX_PACKET_BODY_SIZE); + break; + } - if (packet.headerId() == NetworkExtensionInfo.INCOMING_MESSAGES_IDS.EXTENSIONINFO) { - NetworkExtension gEarthExtension = new NetworkExtension( - packet, - extensionSocket - ); + final HPacket packet = readPacket(dIn, bodyLength, headerId); - if (Authenticator.evaluate(gEarthExtension)) { + final NetworkExtension gEarthExtension = new NetworkExtension(packet, extensionSocket); + + if (Authenticator.evaluate(gEarthExtension)) observer.onExtensionProduced(gEarthExtension); - } - else { + else gEarthExtension.close(); - } break; } } - - } catch (IOException ignored) {} + } catch (IOException ignored) { + } }).start(); } - } catch (IOException e) {e.printStackTrace();} + } catch (IOException e) { + e.printStackTrace(); + } }).start(); } @@ -94,7 +142,26 @@ public class NetworkExtensionsProducer implements ExtensionProducer { } } + private HPacket readPacket(DataInputStream dIn, int amountToRead, short id) throws IOException { + final byte[] headerAndBody = new byte[amountToRead + PACKET_HEADER_SIZE]; + + int amountRead = 0; + while (amountRead < amountToRead) + amountRead += dIn.read(headerAndBody, amountRead + PACKET_HEADER_SIZE, Math.min(dIn.available(), amountToRead - amountRead)); + + final HPacket packet = new HPacket(headerAndBody); + packet.fixLength(); + packet.replaceShort(4, id); // add header id + + return packet; + } + + /** + * Retrieves the {@link ServerSocket#getLocalPort()} of {@link #serverSocket}. + * + * @return the port number to which {@link #serverSocket} is listening or -1 if the socket is not bound yet. + */ public int getPort() { return serverSocket.getLocalPort(); } -} +} \ No newline at end of file diff --git a/G-Earth/src/main/java/gearth/ui/titlebar/TitleBarController.java b/G-Earth/src/main/java/gearth/ui/titlebar/TitleBarController.java index ed9c87f..b2a7c16 100644 --- a/G-Earth/src/main/java/gearth/ui/titlebar/TitleBarController.java +++ b/G-Earth/src/main/java/gearth/ui/titlebar/TitleBarController.java @@ -49,6 +49,7 @@ public class TitleBarController { } public static TitleBarController create(Alert alert) throws IOException { + GEarth.setAlertOwner(alert); FXMLLoader loader = new FXMLLoader(TitleBarController.class.getResource("Titlebar.fxml")); Parent titleBar = loader.load();