correção de bugs
This commit is contained in:
1 parent
e25d3a425d
commit
ab3840e4a4
8 files changed
+202
-34
No files matched your search
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,12 +117,16 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
private void sendHandshake(DataOutputStream output, ConnectionData serverData, ConnectionData clientData) throws IOException {
|
||||
TcpHandshake handshake = TcpHandshake.createPrivate(serverData, clientData);
|
||||
|
||||
@@ -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<ConnectionData, TcpServer> 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<InetAddress, TcpPitiupi> connections;
|
||||
private final List<TcpClient> clients;
|
||||
private final ExecutorService connectionExecutor;
|
||||
private final ServerSocket serverSocket;
|
||||
|
||||
private final Consumer<byte[]> handleMessage;
|
||||
|
||||
private boolean isRunning;
|
||||
private volatile boolean isRunning;
|
||||
|
||||
public TcpManager(int port, Consumer<byte[]> 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,8 +73,12 @@ public final class TcpManager extends Thread{
|
||||
}
|
||||
|
||||
public boolean send(Message message, InetAddress receiverAddress, int port) {
|
||||
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;
|
||||
@@ -69,6 +88,8 @@ public final class TcpManager extends Thread{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void receive() {
|
||||
while (isRunning) {
|
||||
Socket socket = null;
|
||||
@@ -89,6 +110,7 @@ public final class TcpManager extends Thread{
|
||||
}
|
||||
|
||||
private void processConnection(Socket socket) {
|
||||
connectionExecutor.submit(() -> {
|
||||
try {
|
||||
TcpPitiupi tcpPitiupi = tcpFactory.createFromReceiver(socket);
|
||||
|
||||
@@ -96,17 +118,21 @@ public final class TcpManager extends Thread{
|
||||
|
||||
if (tcpPitiupi instanceof TcpClient client) {
|
||||
ConnectionData serverData = client.getServerData();
|
||||
TcpServer tcpServer = servers.get(serverData);
|
||||
|
||||
TcpServer tcpServer;
|
||||
|
||||
tcpServer = servers.get(serverData);
|
||||
|
||||
clients.add(client);
|
||||
tcpServer.addClient(client);
|
||||
}
|
||||
else {
|
||||
} 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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
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.
|
||||
*
|
||||
* <p>Primeiro lê o tamanho da mensagem e, em seguida, lê aquantidade
|
||||
* <p>Primeiro lê o tamanho da mensagem e, em seguida, lê a quantidade
|
||||
* correspondente de bytes.</p>
|
||||
*
|
||||
* @return mensagem recebida
|
||||
@@ -43,21 +60,34 @@ class TcpPitiupi {
|
||||
* for encerrada antes que a mensagem seja completamente recebida
|
||||
*/
|
||||
public byte[] receive() throws IOException {
|
||||
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);
|
||||
|
||||
if (message.length != length) {
|
||||
throw new IOException("Connection closed before receiving the complete message.");
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user