Fail a refused connect with the server's reason
An error answering the handshake, such as "too many clones already connected", used to surface only as "disconnected while waiting for CONNECTED state". connect() now fails with the server's message, and the CommandException carrying its error id is the cause. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+16
-2
@@ -1,6 +1,7 @@
|
||||
package com.github.manevolent.ts3j.protocol.packet.handler.client;
|
||||
|
||||
import com.github.manevolent.ts3j.command.Command;
|
||||
import com.github.manevolent.ts3j.command.CommandException;
|
||||
import com.github.manevolent.ts3j.command.SingleCommand;
|
||||
import com.github.manevolent.ts3j.command.parameter.CommandSingleParameter;
|
||||
import com.github.manevolent.ts3j.protocol.Packet;
|
||||
@@ -265,15 +266,28 @@ public class LocalClientHandlerConnecting extends LocalClientHandler {
|
||||
getClient().setCommandProcessor(getClient());
|
||||
getClient().setState(ClientConnectionState.RETRIEVING_DATA);
|
||||
} else if (command.getName().equals("error")) {
|
||||
getClient().setState(ClientConnectionState.DISCONNECTED);
|
||||
CommandException refusal = refusal(command);
|
||||
getClient().refuse(refusal);
|
||||
|
||||
throw new IOException(command.get("msg").getValue());
|
||||
throw new IOException(refusal.getMessage(), refusal);
|
||||
} else {
|
||||
throw new IOException("Unknown Init command: " + command.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The server's answer to a handshake command it refused, as an exception carrying its error id. */
|
||||
static CommandException refusal(SingleCommand error) {
|
||||
String message = error.has("msg") ? error.get("msg").getValue() : "connection refused";
|
||||
int id;
|
||||
try {
|
||||
id = error.has("id") ? Integer.parseInt(error.get("id").getValue()) : -1;
|
||||
} catch (NumberFormatException e) {
|
||||
id = -1;
|
||||
}
|
||||
return new CommandException(message, id);
|
||||
}
|
||||
|
||||
private SingleCommand createInitIv() {
|
||||
alphaBytes = new byte[10];
|
||||
new Random().nextBytes(alphaBytes);
|
||||
|
||||
+5
-4
@@ -1,9 +1,9 @@
|
||||
package com.github.manevolent.ts3j.protocol.packet.handler.client;
|
||||
|
||||
import com.github.manevolent.ts3j.command.CommandException;
|
||||
import com.github.manevolent.ts3j.command.CommandProcessException;
|
||||
import com.github.manevolent.ts3j.command.CommandProcessor;
|
||||
import com.github.manevolent.ts3j.command.MultiCommand;
|
||||
import com.github.manevolent.ts3j.protocol.client.ClientConnectionState;
|
||||
import com.github.manevolent.ts3j.protocol.socket.client.LocalTeamspeakClientSocket;
|
||||
|
||||
|
||||
@@ -15,13 +15,14 @@ public class LocalClientHandlerRetrievingData extends LocalClientHandlerFull {
|
||||
@Override
|
||||
protected void handleCommand(MultiCommand command) throws CommandProcessException {
|
||||
if (command.getName().equalsIgnoreCase("error")) {
|
||||
// clientinit was refused, e.g. for a nickname in use or a wrong server password.
|
||||
CommandException refusal = LocalClientHandlerConnecting.refusal(command.simplifyOne());
|
||||
try {
|
||||
getClient().setState(ClientConnectionState.DISCONNECTED);
|
||||
getClient().refuse(refusal);
|
||||
} catch (Exception e) {
|
||||
getClient().getExceptionHandler().accept(e);
|
||||
}
|
||||
|
||||
throw new CommandProcessException(command.simplifyOne().get("msg").getValue());
|
||||
throw new CommandProcessException(refusal.getMessage());
|
||||
}
|
||||
|
||||
CommandProcessor processor = getClient().getCommandProcessor();
|
||||
|
||||
+20
-2
@@ -1,5 +1,7 @@
|
||||
package com.github.manevolent.ts3j.protocol.socket.client;
|
||||
|
||||
import com.github.manevolent.ts3j.command.CommandException;
|
||||
|
||||
import com.github.manevolent.ts3j.command.*;
|
||||
import com.github.manevolent.ts3j.identity.Identity;
|
||||
import com.github.manevolent.ts3j.protocol.NetworkPacket;
|
||||
@@ -52,6 +54,8 @@ public abstract class AbstractTeamspeakClientSocket
|
||||
private final Map<String, Object> clientOptions = new ConcurrentHashMap<>();
|
||||
|
||||
private final Object connectionStateLock = new Object();
|
||||
/** Why the server turned the connection down while it was being set up; null otherwise. */
|
||||
private volatile CommandException refusal;
|
||||
|
||||
private final LinkedBlockingDeque<Packet> readQueue = new LinkedBlockingDeque<>(65536);
|
||||
|
||||
@@ -172,8 +176,10 @@ public abstract class AbstractTeamspeakClientSocket
|
||||
|
||||
boolean initialState = this.connectionState == null;
|
||||
|
||||
if (state == ClientConnectionState.CONNECTING)
|
||||
if (state == ClientConnectionState.CONNECTING) {
|
||||
refusal = null;
|
||||
setReading(true);
|
||||
}
|
||||
|
||||
this.connectionState = state;
|
||||
|
||||
@@ -260,13 +266,25 @@ public abstract class AbstractTeamspeakClientSocket
|
||||
connectionStateLock.wait(Math.max(0L, wait - (System.currentTimeMillis() - start)));
|
||||
}
|
||||
|
||||
if (connectionState != state && connectionState == ClientConnectionState.DISCONNECTED)
|
||||
if (connectionState != state && connectionState == ClientConnectionState.DISCONNECTED) {
|
||||
CommandException refused = refusal;
|
||||
if (refused != null) throw new IOException(refused.getMessage(), refused);
|
||||
throw new IOException("disconnected while waiting for " + state.name() + " state");
|
||||
}
|
||||
if (connectionState != state)
|
||||
throw new TimeoutException("timeout waiting for " + state.name() + " state");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the error the server answered a handshake command with, and leaves the connection:
|
||||
* {@link #waitForState} then fails with it rather than with a bare disconnect.
|
||||
*/
|
||||
public void refuse(CommandException error) throws IOException, TimeoutException {
|
||||
refusal = error;
|
||||
setState(ClientConnectionState.DISCONNECTED);
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return connectionState == ClientConnectionState.CONNECTED;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user