Any kind of proper acknowledgement constitutes an alive connection for 30 seconds.
This commit is contained in:
@@ -0,0 +1,45 @@
|
|||||||
|
package com.github.manevolent.ts3j.event;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* TeamSpeak 3 Java API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 Bert De Geyter
|
||||||
|
* %%
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class DisconnectedEvent extends BaseEvent {
|
||||||
|
|
||||||
|
public DisconnectedEvent(Map<String, String> map) {
|
||||||
|
super(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getReasonId() {
|
||||||
|
return getInt("reasonid");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fire(TS3Listener listener) {
|
||||||
|
listener.onDisconnected(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -63,4 +63,6 @@ public interface TS3Listener {
|
|||||||
void onClientChannelGroupChanged(ClientChannelGroupChangedEvent e);
|
void onClientChannelGroupChanged(ClientChannelGroupChangedEvent e);
|
||||||
|
|
||||||
void onClientChanged(ClientUpdatedEvent e);
|
void onClientChanged(ClientUpdatedEvent e);
|
||||||
|
|
||||||
|
void onDisconnected(DisconnectedEvent e);
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-7
@@ -37,6 +37,8 @@ import java.util.concurrent.*;
|
|||||||
public abstract class AbstractTeamspeakClientSocket
|
public abstract class AbstractTeamspeakClientSocket
|
||||||
extends AbstractTeamspeakSocket
|
extends AbstractTeamspeakSocket
|
||||||
implements TeamspeakClientSocket {
|
implements TeamspeakClientSocket {
|
||||||
|
public static long TIMEOUT = 30000L;
|
||||||
|
|
||||||
private static final byte[] INIT1_MAC = new byte[] {
|
private static final byte[] INIT1_MAC = new byte[] {
|
||||||
0x54, 0x53, 0x33, 0x49, 0x4E, 0x49, 0x54, 0x31
|
0x54, 0x53, 0x33, 0x49, 0x4E, 0x49, 0x54, 0x31
|
||||||
};
|
};
|
||||||
@@ -66,6 +68,7 @@ public abstract class AbstractTeamspeakClientSocket
|
|||||||
private int clientId = 0;
|
private int clientId = 0;
|
||||||
private int packetId = 0;
|
private int packetId = 0;
|
||||||
|
|
||||||
|
private long lastResponse;
|
||||||
private long lastPing;
|
private long lastPing;
|
||||||
|
|
||||||
private final NetworkReader networkReader = new NetworkReader();
|
private final NetworkReader networkReader = new NetworkReader();
|
||||||
@@ -396,7 +399,7 @@ public abstract class AbstractTeamspeakClientSocket
|
|||||||
response = new PacketResponse(
|
response = new PacketResponse(
|
||||||
networkPacket,
|
networkPacket,
|
||||||
sendQueue,
|
sendQueue,
|
||||||
networkPacket.getHeader().getType().canResend() ? 10 : 0
|
networkPacket.getHeader().getType().canResend() ? 30 : 0
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else
|
} else
|
||||||
@@ -408,13 +411,14 @@ public abstract class AbstractTeamspeakClientSocket
|
|||||||
|
|
||||||
// If necessary, fulfill promise for the packet acknowledgement or throw TimeoutException
|
// If necessary, fulfill promise for the packet acknowledgement or throw TimeoutException
|
||||||
if (response != null) {
|
if (response != null) {
|
||||||
while (response.getRetries() < response.getMaxTries()) {
|
while (response.getRetries() < response.getMaxTries() &&
|
||||||
|
getState() != ClientConnectionState.DISCONNECTED) {
|
||||||
try {
|
try {
|
||||||
if (getState() == ClientConnectionState.DISCONNECTED)
|
if (getState() == ClientConnectionState.DISCONNECTED)
|
||||||
throw new IllegalStateException("no longer connected");
|
throw new IllegalStateException("no longer connected");
|
||||||
|
|
||||||
// Wait one cycle for an ACK
|
// Wait one cycle for an ACK
|
||||||
response.waitForAcknowledgement(1000);
|
response.waitForAcknowledgement(1000L);
|
||||||
break;
|
break;
|
||||||
} catch (TimeoutException e) {
|
} catch (TimeoutException e) {
|
||||||
if (response.willResend())
|
if (response.willResend())
|
||||||
@@ -530,9 +534,14 @@ public abstract class AbstractTeamspeakClientSocket
|
|||||||
networkPacket = readNetworkPacket((int) timeout);
|
networkPacket = readNetworkPacket((int) timeout);
|
||||||
} catch (SocketTimeoutException e) {
|
} catch (SocketTimeoutException e) {
|
||||||
if (getState() == ClientConnectionState.CONNECTED) {
|
if (getState() == ClientConnectionState.CONNECTED) {
|
||||||
|
if (System.currentTimeMillis() - lastResponse >= TIMEOUT) {
|
||||||
|
Ts3Debugging.debug("Connection timed out.");
|
||||||
|
setState(ClientConnectionState.DISCONNECTED); // Timeout
|
||||||
|
} else {
|
||||||
writePacket(new PacketBody4Ping(getRole().getOut()));
|
writePacket(new PacketBody4Ping(getRole().getOut()));
|
||||||
lastPing = System.currentTimeMillis();
|
lastPing = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -593,16 +602,28 @@ public abstract class AbstractTeamspeakClientSocket
|
|||||||
switch (packet.getHeader().getType()) {
|
switch (packet.getHeader().getType()) {
|
||||||
case ACK:
|
case ACK:
|
||||||
response = sendQueue.get(((PacketBody6Ack)packet.getBody()).getPacketId());
|
response = sendQueue.get(((PacketBody6Ack)packet.getBody()).getPacketId());
|
||||||
if (response == null)
|
if (response == null) {
|
||||||
Ts3Debugging.debug("Unrecognized ACK: " + ((PacketBody6Ack)packet.getBody()).getPacketId());
|
Ts3Debugging.debug("Unrecognized ACK: " + ((PacketBody6Ack) packet.getBody()).getPacketId());
|
||||||
|
} else {
|
||||||
|
lastResponse = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
handle = false;
|
handle = false;
|
||||||
break;
|
break;
|
||||||
case ACK_LOW:
|
case ACK_LOW:
|
||||||
|
lastResponse = System.currentTimeMillis();
|
||||||
|
|
||||||
response = sendQueueLow.get(((PacketBody7AckLow)packet.getBody()).getPacketId());
|
response = sendQueueLow.get(((PacketBody7AckLow)packet.getBody()).getPacketId());
|
||||||
if (response == null)
|
if (response == null) {
|
||||||
Ts3Debugging.debug("Unrecognized ACK_LOW: " + ((PacketBody6Ack)packet.getBody()).getPacketId());
|
Ts3Debugging.debug("Unrecognized ACK_LOW: " + ((PacketBody6Ack) packet.getBody()).getPacketId());
|
||||||
|
} else {
|
||||||
|
lastResponse = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
handle = false;
|
handle = false;
|
||||||
break;
|
break;
|
||||||
|
case PONG:
|
||||||
|
lastResponse = System.currentTimeMillis();
|
||||||
default:
|
default:
|
||||||
handle = true;
|
handle = true;
|
||||||
response = null;
|
response = null;
|
||||||
|
|||||||
+46
-4
@@ -9,9 +9,7 @@ import com.github.manevolent.ts3j.command.*;
|
|||||||
import com.github.manevolent.ts3j.command.parameter.CommandSingleParameter;
|
import com.github.manevolent.ts3j.command.parameter.CommandSingleParameter;
|
||||||
import com.github.manevolent.ts3j.command.response.AbstractCommandResponse;
|
import com.github.manevolent.ts3j.command.response.AbstractCommandResponse;
|
||||||
import com.github.manevolent.ts3j.command.response.CommandResponse;
|
import com.github.manevolent.ts3j.command.response.CommandResponse;
|
||||||
import com.github.manevolent.ts3j.event.ChannelListEvent;
|
import com.github.manevolent.ts3j.event.*;
|
||||||
import com.github.manevolent.ts3j.event.TS3Event;
|
|
||||||
import com.github.manevolent.ts3j.event.TS3Listener;
|
|
||||||
import com.github.manevolent.ts3j.identity.LocalIdentity;
|
import com.github.manevolent.ts3j.identity.LocalIdentity;
|
||||||
import com.github.manevolent.ts3j.identity.Uid;
|
import com.github.manevolent.ts3j.identity.Uid;
|
||||||
import com.github.manevolent.ts3j.protocol.NetworkPacket;
|
import com.github.manevolent.ts3j.protocol.NetworkPacket;
|
||||||
@@ -58,7 +56,7 @@ public class LocalTeamspeakClientSocket
|
|||||||
|
|
||||||
private List<TS3Listener> listeners = new LinkedList<>();
|
private List<TS3Listener> listeners = new LinkedList<>();
|
||||||
|
|
||||||
private int acceptingReturnCode = 0;
|
private int acceptingReturnCode = Integer.MAX_VALUE;
|
||||||
private int lastReturnCode = 0;
|
private int lastReturnCode = 0;
|
||||||
|
|
||||||
private Integer serverId = null;
|
private Integer serverId = null;
|
||||||
@@ -80,6 +78,27 @@ public class LocalTeamspeakClientSocket
|
|||||||
});
|
});
|
||||||
|
|
||||||
namedProcessors.put("channellistfinished", new ChannelListFinishedHandler());
|
namedProcessors.put("channellistfinished", new ChannelListFinishedHandler());
|
||||||
|
|
||||||
|
namedProcessors.put("notifyclientleftview", new CommandProcessor() {
|
||||||
|
@Override
|
||||||
|
public void process(AbstractTeamspeakClientSocket client, SingleCommand command)
|
||||||
|
throws CommandProcessException {
|
||||||
|
int clientId = Integer.parseInt(command.get("clid").getValue());
|
||||||
|
if (clientId == getClientId()) {
|
||||||
|
try {
|
||||||
|
setState(ClientConnectionState.DISCONNECTED);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TS3Listener listener : listeners)
|
||||||
|
listener.onDisconnected(new DisconnectedEvent(command.toMap()));
|
||||||
|
} else {
|
||||||
|
for (TS3Listener listener : listeners)
|
||||||
|
listener.onClientLeave(new ClientLeaveEvent(command.toMap()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addListener(TS3Listener listener) {
|
public void addListener(TS3Listener listener) {
|
||||||
@@ -164,6 +183,9 @@ public class LocalTeamspeakClientSocket
|
|||||||
setClientId(0);
|
setClientId(0);
|
||||||
setPacketId(0);
|
setPacketId(0);
|
||||||
setGenerationId(0);
|
setGenerationId(0);
|
||||||
|
serverId = null;
|
||||||
|
awaitingCommands.clear();
|
||||||
|
acceptingReturnCode = lastReturnCode = 0;
|
||||||
|
|
||||||
setOption("client.hostname", remote.getHostString());
|
setOption("client.hostname", remote.getHostString());
|
||||||
|
|
||||||
@@ -745,4 +767,24 @@ public class LocalTeamspeakClientSocket
|
|||||||
|
|
||||||
executeCommand(command).complete();
|
executeCommand(command).complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void disconnect()
|
||||||
|
throws
|
||||||
|
IOException, TimeoutException,
|
||||||
|
ExecutionException, InterruptedException {
|
||||||
|
switch (getState()) {
|
||||||
|
case CONNECTING:
|
||||||
|
case RETRIEVING_DATA:
|
||||||
|
waitForState(ClientConnectionState.CONNECTED, 10000L);
|
||||||
|
case CONNECTED:
|
||||||
|
writePacket(new PacketBody2Command(
|
||||||
|
ProtocolRole.CLIENT,
|
||||||
|
new SingleCommand("clientdisconnect", ProtocolRole.CLIENT))
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,16 +40,9 @@ public class ServerConnectionTest {
|
|||||||
|
|
||||||
assertEquals(client.getState(), ClientConnectionState.CONNECTED);
|
assertEquals(client.getState(), ClientConnectionState.CONNECTED);
|
||||||
|
|
||||||
client.sendServerMessage("Heyyyy");
|
client.disconnect();
|
||||||
|
|
||||||
while (true) {
|
client.waitForState(ClientConnectionState.DISCONNECTED, 10000L);
|
||||||
Thread.sleep(1000L);
|
|
||||||
|
|
||||||
for (Channel channel : client.listChannels()) {
|
|
||||||
Ts3Debugging.debug(channel.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user