From ab3840e4a44df0dd57680f735f7398878632625c Mon Sep 17 00:00:00 2001 From: GustavoHMDS Date: Fri, 9 Oct 2026 13:51:06 -0300 Subject: [PATCH] =?UTF-8?q?corre=C3=A7=C3=A3o=20de=20bugs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pitiupi/control/ConnectionManager.java | 10 +- .../src/pitiupi/models/ConnectionData.java | 59 ++++++++- pitiupi/src/pitiupi/net/tcp/TcpClient.java | 9 +- pitiupi/src/pitiupi/net/tcp/TcpFactory.java | 27 ++-- pitiupi/src/pitiupi/net/tcp/TcpManager.java | 123 +++++++++++++----- pitiupi/src/pitiupi/net/tcp/TcpPitiupi.java | 54 ++++++-- pitiupi/src/pitiupi/net/tcp/TcpServer.java | 14 +- pitiupi/src/pitiupi/plugin/Pitiupi.java | 8 +- 8 files changed, 236 insertions(+), 68 deletions(-) diff --git a/pitiupi/src/pitiupi/control/ConnectionManager.java b/pitiupi/src/pitiupi/control/ConnectionManager.java index 4edbc42..e037dbd 100644 --- a/pitiupi/src/pitiupi/control/ConnectionManager.java +++ b/pitiupi/src/pitiupi/control/ConnectionManager.java @@ -24,7 +24,7 @@ public class ConnectionManager { private TcpManager tcpManager; private SocketUDP socketUDP; private String username; - private InetAddress address; + private final InetAddress address; private int port; public ConnectionManager(String username, PluginManager pluginManager, int port) throws UnknownHostException { @@ -44,8 +44,12 @@ public class ConnectionManager { return tcpManager.getClient(serverData, pluginId, username); } - public TcpServer getTcpServer(String pluginId) { - return tcpManager.getServer(pluginId, username, address, port); + public TcpServer getTcpServer(String serverName, String pluginId) { + return tcpManager.getServer(serverName, pluginId, username, address, port); + } + + public void closeTcpServer(TcpServer tcpServer) { + tcpManager.closeServer(tcpServer); } public boolean sendTcp(Message message, InetAddress destinationAddress) { diff --git a/pitiupi/src/pitiupi/models/ConnectionData.java b/pitiupi/src/pitiupi/models/ConnectionData.java index 5348b22..c7268bc 100644 --- a/pitiupi/src/pitiupi/models/ConnectionData.java +++ b/pitiupi/src/pitiupi/models/ConnectionData.java @@ -2,26 +2,33 @@ package pitiupi.models; import java.io.Serializable; import java.net.InetAddress; +import java.util.Objects; import java.util.UUID; -public class ConnectionData implements Serializable { +public final class ConnectionData implements Serializable { private final UUID uuid; private final int port; + + private final String connectionName; + private final String ownerName; private final InetAddress ownerAddress; - private final String plugin; + private final String pluginId; private final boolean isServer; - public ConnectionData(String ownerName, InetAddress ownerAddress, String plugin, int port, boolean isServer) { + public ConnectionData(String connectionName, String ownerName, InetAddress ownerAddress, String pluginId, int port, boolean isServer) { uuid = UUID.randomUUID(); this.port = port; + this.connectionName = connectionName; this.ownerName = ownerName; this.ownerAddress = ownerAddress; - this.plugin = plugin; + this.pluginId = pluginId; this.isServer = isServer; } + + public UUID getUuid() { return uuid; } @@ -29,16 +36,56 @@ public class ConnectionData implements Serializable { public int getPort() { return port; } + + public String getConnectionName() { + return connectionName; + } + public String getOwnerName() { return ownerName; } public InetAddress getOwnerAddress() { return ownerAddress; } - public String getPlugin() { - return plugin; + public String getPluginId() { + return pluginId; } public boolean isServer() { return isServer; } + + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConnectionData that = (ConnectionData) o; + + if (port != that.port) return false; + if (!uuid.equals(that.uuid)) return false; + if (!connectionName.equals(that.connectionName)) return false; + if (!Objects.equals(ownerName, that.ownerName)) return false; + if (!Objects.equals(ownerAddress, that.ownerAddress)) return false; + if (!Objects.equals(pluginId, that.pluginId)) return false; + return isServer == that.isServer; + } + + @Override + public int hashCode() { + return Objects.hash( + uuid, + port, + connectionName, + ownerName, + ownerAddress, + pluginId, + isServer + ); + } + + @Override + public String toString() { + return connectionName + ": " + pluginId; + } } diff --git a/pitiupi/src/pitiupi/net/tcp/TcpClient.java b/pitiupi/src/pitiupi/net/tcp/TcpClient.java index 5fb070e..38c0d7f 100644 --- a/pitiupi/src/pitiupi/net/tcp/TcpClient.java +++ b/pitiupi/src/pitiupi/net/tcp/TcpClient.java @@ -15,11 +15,14 @@ public final class TcpClient extends TcpPitiupi { ConnectionData serverData, Socket socket, DataInputStream input, - DataOutputStream output) - { + DataOutputStream output + ) throws IllegalArgumentException { super(socket, input, output); + if (clientData == null) throw new IllegalArgumentException("clientData is null"); + if (serverData == null) throw new IllegalArgumentException("ServerData is null"); + this.clientData = clientData; this.serverData = serverData; } @@ -31,4 +34,4 @@ public final class TcpClient extends TcpPitiupi { public ConnectionData getClientData() { return clientData; } -} +} \ No newline at end of file diff --git a/pitiupi/src/pitiupi/net/tcp/TcpFactory.java b/pitiupi/src/pitiupi/net/tcp/TcpFactory.java index fe5d488..18488b2 100644 --- a/pitiupi/src/pitiupi/net/tcp/TcpFactory.java +++ b/pitiupi/src/pitiupi/net/tcp/TcpFactory.java @@ -4,24 +4,26 @@ import pitiupi.models.ConnectionData; import java.io.*; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.Socket; import java.util.logging.Level; import java.util.logging.Logger; final class TcpFactory { - private static final int HANDSHAKE_TIMEOUT = 1000; + private static final int HANDSHAKE_TIMEOUT = 3000; private static final int DISABLE_TIMEOUT = 0; - TcpManager manager; + private final TcpManager manager; TcpFactory(TcpManager manager) { this.manager = manager; } TcpPitiupi createPitiupiConnection(InetAddress receiverAddress, int port) { - Socket socket = null; + Socket socket = new Socket(); try { socket = new Socket(receiverAddress, port); + socket.connect(new InetSocketAddress(receiverAddress, port), HANDSHAKE_TIMEOUT); DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream()); DataInputStream dataInputStream = new DataInputStream(socket.getInputStream()); @@ -36,7 +38,7 @@ final class TcpFactory { Logger.getLogger(TcpFactory.class.getName()).log(Level.SEVERE, null, e); } - if (socket != null) tryClose(socket); + tryClose(socket); return null; } @@ -44,10 +46,12 @@ final class TcpFactory { Socket socket = null; try { socket = new Socket(receiverAddress, port); + socket.connect(new InetSocketAddress(receiverAddress, port), HANDSHAKE_TIMEOUT); DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream()); DataInputStream dataInputStream = new DataInputStream(socket.getInputStream()); ConnectionData clientData = new ConnectionData( + "Connection to " + serverData.getConnectionName() + " (" + serverData.getOwnerAddress() + ")", username, receiverAddress, pluginIdentifier, @@ -69,8 +73,9 @@ final class TcpFactory { return null; } - TcpServer createServer(String pluginIdentifier, String username, InetAddress receiverAddress, int port) { + TcpServer createServer(String serverName, String pluginIdentifier, String username, InetAddress receiverAddress, int port) { ConnectionData data = new ConnectionData( + serverName, username, receiverAddress, pluginIdentifier, @@ -112,11 +117,15 @@ final class TcpFactory { } catch (IOException | ClassNotFoundException e) { Logger.getLogger(TcpFactory.class.getName()).log(Level.SEVERE, null, e); + try { + sendHandshakeResponse(false, dataOutputStream); + } + catch (IOException e1) { + Logger.getLogger(TcpFactory.class.getName()).log(Level.INFO, null, e1); + } + tryClose(socket); + return null; } - - sendHandshakeResponse(false, dataOutputStream); - tryClose(socket); - return null; } private void sendHandshake(DataOutputStream output, ConnectionData serverData, ConnectionData clientData) throws IOException { diff --git a/pitiupi/src/pitiupi/net/tcp/TcpManager.java b/pitiupi/src/pitiupi/net/tcp/TcpManager.java index 7427e10..00dd4c4 100644 --- a/pitiupi/src/pitiupi/net/tcp/TcpManager.java +++ b/pitiupi/src/pitiupi/net/tcp/TcpManager.java @@ -5,6 +5,8 @@ import pitiupi.models.Messages.Message; import java.io.*; import java.net.*; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; @@ -17,17 +19,23 @@ public final class TcpManager extends Thread{ private final TcpFactory tcpFactory; private final Map servers; + + // TODO: Atualizar a identificação das conexões públicas quando + // a identificação de usuário/processo for revisada. + // Atualmente, o mapa permite apenas uma conexão pública por endereço IP. private final Map connections; + private final List clients; private final ExecutorService connectionExecutor; private final ServerSocket serverSocket; private final Consumer handleMessage; - private boolean isRunning; + private volatile boolean isRunning; public TcpManager(int port, Consumer handleMessage) throws IOException { servers = new ConcurrentHashMap<>(); connections = new ConcurrentHashMap<>(); + clients = new ArrayList<>(); tcpFactory = new TcpFactory(this); @@ -37,20 +45,27 @@ public final class TcpManager extends Thread{ this.handleMessage = handleMessage; } - public TcpServer getServer(String pluginIdentifier, String username, InetAddress userAddress, int port) { - TcpServer tcpServer = tcpFactory.createServer(pluginIdentifier, username, userAddress, port); + public TcpServer getServer(String serverName, String pluginIdentifier, String username, InetAddress userAddress, int port) { + TcpServer tcpServer = tcpFactory.createServer(serverName, pluginIdentifier, username, userAddress, port); servers.put(tcpServer.getConnectionData(), tcpServer); return tcpServer; } public TcpClient getClient(ConnectionData serverData, String pluginIdentifier, String username) { - return tcpFactory.createClient(serverData, pluginIdentifier, username, serverData.getOwnerAddress(), serverData.getPort()); + TcpClient tcpClient = tcpFactory.createClient(serverData, pluginIdentifier, username, serverData.getOwnerAddress(), serverData.getPort()); + + if (tcpClient == null) return null; + + clients.add(tcpClient); + return tcpClient; } private TcpPitiupi createConnection(InetAddress receiverAddress, int port) { TcpPitiupi tcpPitiupi = tcpFactory.createPitiupiConnection(receiverAddress, port); + if (tcpPitiupi == null) return null; + manageConnectionList(tcpPitiupi, receiverAddress); startConnectionReceiver(tcpPitiupi); @@ -58,17 +73,23 @@ public final class TcpManager extends Thread{ } public boolean send(Message message, InetAddress receiverAddress, int port) { - TcpPitiupi tcpPitiupi = findConnection(receiverAddress); - if (tcpPitiupi == null || tcpPitiupi.isClosed()) tcpPitiupi = createConnection(receiverAddress, port); - try { - tcpPitiupi.send(message.toByteArray()); - return true; - } - catch (IOException ex) { - Logger.getLogger(TcpManager.class.getName()).log(Level.WARNING, null, ex); - return false; + synchronized (connections) { + TcpPitiupi tcpPitiupi = findConnection(receiverAddress); + + if (tcpPitiupi == null || tcpPitiupi.isClosed()) tcpPitiupi = createConnection(receiverAddress, port); + if (tcpPitiupi == null) return false; + + try { + tcpPitiupi.send(message.toByteArray()); + return true; + } + catch (IOException ex) { + Logger.getLogger(TcpManager.class.getName()).log(Level.WARNING, null, ex); + return false; + } } } + private void receive() { while (isRunning) { Socket socket = null; @@ -89,24 +110,29 @@ public final class TcpManager extends Thread{ } private void processConnection(Socket socket) { - try { - TcpPitiupi tcpPitiupi = tcpFactory.createFromReceiver(socket); + connectionExecutor.submit(() -> { + try { + TcpPitiupi tcpPitiupi = tcpFactory.createFromReceiver(socket); - if (tcpPitiupi == null) return; + if (tcpPitiupi == null) return; - if (tcpPitiupi instanceof TcpClient client) { - ConnectionData serverData = client.getServerData(); - TcpServer tcpServer = servers.get(serverData); + if (tcpPitiupi instanceof TcpClient client) { + ConnectionData serverData = client.getServerData(); - tcpServer.addClient(client); + TcpServer tcpServer; + + tcpServer = servers.get(serverData); + + clients.add(client); + tcpServer.addClient(client); + } else { + manageConnectionList(tcpPitiupi, socket.getInetAddress()); + startConnectionReceiver(tcpPitiupi); + } + } catch (IOException e) { + Logger.getLogger(TcpClient.class.getName()).log(Level.SEVERE, null, e); } - else { - manageConnectionList(tcpPitiupi, socket.getInetAddress()); - startConnectionReceiver(tcpPitiupi); - } - } catch (IOException e) { - Logger.getLogger(TcpClient.class.getName()).log(Level.SEVERE, null, e); - } + }); } public void closeManager() { @@ -118,8 +144,29 @@ public final class TcpManager extends Thread{ Logger.getLogger(TcpManager.class.getName()).log(Level.WARNING, null, e); } + for (TcpClient tcpClient : clients) { + try { + tcpClient.close(); + } + catch (IOException e) { + Logger.getLogger(TcpManager.class.getName()).log(Level.WARNING, null, e); + } + } + + for (TcpPitiupi tcpPitiupi : connections.values()) { + try { + tcpPitiupi.close(); + } + catch (IOException e) { + Logger.getLogger(TcpManager.class.getName()).log(Level.WARNING, null, e); + } + } + servers.clear(); + clients.clear(); connections.clear(); + + connectionExecutor.shutdown(); } public void closeServer(TcpServer tcpServer) { @@ -132,25 +179,39 @@ public final class TcpManager extends Thread{ private TcpPitiupi findConnection(InetAddress receiverAddress) { return connections.get(receiverAddress); } + public TcpServer findServer(ConnectionData serverData) { return servers.get(serverData); } private void manageConnectionList(TcpPitiupi tcpPitiupi, InetAddress receiverAddress) { - TcpPitiupi oldPitiupiConnection = connections.put(receiverAddress, tcpPitiupi); - if (oldPitiupiConnection != null) { - tcpFactory.tryClose(oldPitiupiConnection.getSocket()); + synchronized (connections) { + TcpPitiupi oldPitiupiConnection = connections.put(receiverAddress, tcpPitiupi); + if (oldPitiupiConnection != null) { + tcpFactory.tryClose(oldPitiupiConnection.getSocket()); + } } } + private void startConnectionReceiver(TcpPitiupi tcpPitiupi) { connectionExecutor.submit(() -> { while (!tcpPitiupi.isClosed()) { try { handleMessage.accept(tcpPitiupi.receive()); - } catch (IOException e) { + } + catch (IOException e) { Logger.getLogger(TcpManager.class.getName()).log(Level.SEVERE, null, e); break; } + finally { + connections.remove(tcpPitiupi.getSocket().getInetAddress()); + + try { + tcpPitiupi.close(); + } catch (IOException ex) { + Logger.getLogger(TcpManager.class.getName()).log(Level.INFO, null, ex); + } + } } }); } diff --git a/pitiupi/src/pitiupi/net/tcp/TcpPitiupi.java b/pitiupi/src/pitiupi/net/tcp/TcpPitiupi.java index e9bb3a1..ac7f5d2 100644 --- a/pitiupi/src/pitiupi/net/tcp/TcpPitiupi.java +++ b/pitiupi/src/pitiupi/net/tcp/TcpPitiupi.java @@ -2,19 +2,28 @@ package pitiupi.net.tcp; import java.io.DataInputStream; import java.io.DataOutputStream; +import java.io.EOFException; import java.io.IOException; import java.net.Socket; +import java.util.logging.Level; +import java.util.logging.Logger; class TcpPitiupi { + private static final int MAX_MESSAGE_SIZE = 1_048_576; + protected final Socket socket; protected final DataInputStream input; protected final DataOutputStream output; + protected boolean isClosed; + public TcpPitiupi(Socket socket, DataInputStream input, DataOutputStream output) { this.socket = socket; this.input = input; this.output = output; + + this.isClosed = socket.isClosed(); } /** @@ -27,15 +36,23 @@ class TcpPitiupi { * @throws IOException se ocorrer um erro durante o envio */ public void send(byte[] message) throws IOException { - output.writeInt(message.length); - output.write(message); - output.flush(); + if (message.length > MAX_MESSAGE_SIZE) throw new IOException("Oversized message"); + + try { + output.writeInt(message.length); + output.write(message); + output.flush(); + } catch (EOFException e) { + Logger.getLogger(TcpPitiupi.class.getName()).log(Level.INFO, null, e); + isClosed = true; + throw new IOException("Socket closed"); + } } /** * Recebe uma mensagem da conexão. * - *

Primeiro lê o tamanho da mensagem e, em seguida, lê aquantidade + *

Primeiro lê o tamanho da mensagem e, em seguida, lê a quantidade * correspondente de bytes.

* * @return mensagem recebida @@ -43,21 +60,34 @@ class TcpPitiupi { * for encerrada antes que a mensagem seja completamente recebida */ public byte[] receive() throws IOException { - int length = input.readInt(); + try { + int length = input.readInt(); - if (length < 0) throw new IOException("Invalid message length."); + if (length < 0 || length > MAX_MESSAGE_SIZE) throw new IOException("Invalid message length."); - byte[] message = input.readNBytes(length); + byte[] message = input.readNBytes(length); - if (message.length != length) { - throw new IOException("Connection closed before receiving the complete message."); + if (message.length != length) { + Logger.getLogger(TcpPitiupi.class.getName()).log(Level.INFO, null, "Socket closed"); + isClosed = true; + throw new IOException("Socket closed"); + } + + return message; + } + catch (EOFException e) { + Logger.getLogger(TcpPitiupi.class.getName()).log(Level.INFO, null, e); + isClosed = true; + throw new IOException("Socket closed"); } - - return message; } public boolean isClosed() { - return socket.isClosed(); + if (socket.isClosed()) isClosed = true; + if (socket.isInputShutdown()) isClosed = true; + if (socket.isOutputShutdown()) isClosed = true; + + return isClosed; } Socket getSocket() { diff --git a/pitiupi/src/pitiupi/net/tcp/TcpServer.java b/pitiupi/src/pitiupi/net/tcp/TcpServer.java index 5b21623..6d8e374 100644 --- a/pitiupi/src/pitiupi/net/tcp/TcpServer.java +++ b/pitiupi/src/pitiupi/net/tcp/TcpServer.java @@ -29,13 +29,13 @@ public final class TcpServer { clients.put(tcpClient.getClientData(), tcpClient); } - public TcpClient receive() { + public TcpClient receive() throws IOException { try { return buffer.take(); } catch (InterruptedException e) { Logger.getLogger(TcpServer.class.getName()).log(Level.SEVERE, null, e); - return null; + throw new IOException(e); } } @@ -43,6 +43,16 @@ public final class TcpServer { return clients.keySet().stream().toList(); } + public void removeClient(ConnectionData clientData) { + TcpClient client = clients.remove(clientData); + try { + client.close(); + } + catch (IOException e) { + Logger.getLogger(TcpServer.class.getName()).log(Level.INFO, null, e); + } + } + public ConnectionData getConnectionData() { return connectionData; } diff --git a/pitiupi/src/pitiupi/plugin/Pitiupi.java b/pitiupi/src/pitiupi/plugin/Pitiupi.java index bbbec22..7e029f0 100644 --- a/pitiupi/src/pitiupi/plugin/Pitiupi.java +++ b/pitiupi/src/pitiupi/plugin/Pitiupi.java @@ -33,14 +33,18 @@ public class Pitiupi { return connectionManager.sendTcp(message, address); } - public TcpServer openTcpServer(String pluginId) { - return connectionManager.getTcpServer(pluginId); + public TcpServer openTcpServer(String serverName, String pluginId) { + return connectionManager.getTcpServer(serverName, pluginId); } public TcpClient connectToTcpServer(ConnectionData connectionData, String pluginId) { return connectionManager.connectToTcpServer(connectionData, pluginId); } + public void closeTcpServer(TcpServer tcpServer) { + connectionManager.closeTcpServer(tcpServer); + } + public String getUserName() { return connectionManager.getUserName(); }