Commit Graph
154 Commits
Author SHA1 Message Date
erikbrockoandClaude Opus 5.5 4aa9341ec4 Drop the connection when a command never gets through
The server handles commands in order and holds back everything sent
after a lost one, so giving up on a command now ends the connection, as
in the official client. A connection lost without either side saying
goodbye (a timeout, or such a command) is now reported to listeners as
a disconnect ("connection lost").

- A command's acknowledgement is awaited in the background: ensureSent
  is often called from the packet handler thread, which must keep
  handling while resends go on. A command that fails makes way for the
  next one.
- One packet that fails to handle no longer ends the handler thread,
  which left everything after it unhandled while ACKs and pings kept the
  connection looking alive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 10:08:09 +00:00
erikbrockoandClaude Opus 5.5 5a5fb6baaf Encrypt each packet with its own EAX cipher
TS3 derives a packet's key and nonce from its id, so resending a packet
encrypts it under the same pair again. BouncyCastle has since learned to
refuse that on a cipher that has already used the pair ("cannot reuse
nonce for EAX encryption"), which broke resends on the current version
the Android build uses. A fresh cipher per packet keeps them working.

Moves to bcprov-jdk18on 1.86, the maintained line, so every platform runs
the same BouncyCastle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 08:42:48 +00:00
erikbrockoandClaude Opus 5.5 3625cc24cf Look up SRV records without requiring JNDI
TS3DNS resolved SRV records through JNDI's DNS provider, which Android
does not have. The JNDI code moves into its own class that is only
loaded where JNDI exists; elsewhere a server is reached by its address,
as when it publishes no SRV record. TS3DNS.setSrvLookup lets a platform
supply its own resolver.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 08:13:09 +00:00
erikbrockoandClaude Opus 5.5 2018c1c593 Resend like the official client; keep the handshake consistent under loss
- Resend unacknowledged packets on the official client's schedule (mean RTT
  + 3 sigma + 50 ms over the last 20 samples, x1.4 per resend) and give up
  after 18 s, instead of a fixed 1 s x 30.
- Resend INIT1 packets until the server answers; they are never ACKed.
- Answer each server Init1 step once: a duplicated step-3 reply sent a second
  clientinitiv with a new alpha, leaving client and server with different
  keys (MAC check failures).
- Disconnect without blocking on an ACK the server may never send.
- Fail waitForState promptly when the connection drops, and name the packet
  in decrypt errors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 04:58:21 +00:00
erikbrockoandClaude Opus 5.5 45cb8fd559 Send clientinit without waiting for clientek's ACK
The server does not acknowledge a resent clientek, so losing its first ACK
stalled the handshake: we kept resending clientek and never got to
clientinit. Send clientek without blocking (resends continue in the
background via the new writePacketAsync) and follow with clientinit right
away; the server cannot decrypt clientinit before it has processed
clientek, so the two stay in order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 23:21:44 +00:00
erikbrockoandClaude Opus 5.5 765bfb25fd Fall back to the handshake key when a packet fails to decrypt
The server encrypts initivexpand2 (COMMAND 0 and 1) with the handshake
key. If our ACK for one of those fragments is lost, its retransmit arrives
after we switched to the session key, fails with "mac check in EAX
failed", is never acknowledged and blocks the server's command stream
until it drops us. Common on lossy links such as mobile data.

Retry generation 0 packets that fail under the session key with the
handshake key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 23:21:44 +00:00
erikbrockoandClaude Opus 5.5 b335c2c511 Tolerate an empty client_servergroups in Client.getServerGroups
Some servers list a client with an empty client_servergroups; parsing it
threw NumberFormatException and aborted iterating the whole client list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:30:48 +00:00
erikbrockoandClaude Opus 5.5 6fe787de30 Resolve incoming packet generations relative to the newest packet
RemoteCounterFull only knew a 100-packet window. A packet that arrived more
than 100 IDs late - typically a retransmit after a loss in the large burst a
busy server sends on connect - was assumed to belong to the next generation,
as was packet ID 0 right after a wrap. The generation feeds the EAX key, so
those packets failed with "mac check in EAX failed", were never acknowledged
and stalled the command stream.

Place each ID in the generation closest to the newest packet received, and
remember the last 32768 positions for duplicate detection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:09:09 +00:00
erikbrocko 49f2ce874d Request voice properties in clientlist
Without -voice the server omits client_input_muted/output_muted and
the hardware flags entirely, so a bare clientlist leaves callers
unable to tell "false" from "not reported" and defaults them wrong.
2026-08-17 08:42:59 +00:00
erikbrockoandClaude Opus 5 0e5724b877 Keep the virtual server properties from initserver
initserver announces the whole virtual server (its name above all), but only
the client and server ids were taken from it and the rest was dropped. The
name is not obtainable elsewhere: servergetvariables answers without it, and
notifyserveredited only fires when someone edits the server.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 14:15:26 +00:00
erikbrockoandClaude Opus 5 dce4e68150 Drop the commons-lang and dnsjava dependencies
Both were pulled in for a single call each: commons-lang for
ConstructorUtils.invokeConstructor when building a packet handler, and
dnsjava for the _ts3._udp SRV lookup. Together they added over a
megabyte to a shaded jar (and dnsjava drops jnamed/update classes into
the jar root). Plain reflection and JNDI's dns: provider cover both.

Also drop the BouncyCastleProvider registration: every digest here is
requested by a name the SUN provider already answers, so the only thing
it accomplished was keeping the whole JCE provider, the post-quantum
suite and the X.509 stack reachable for a shaded-jar tree-shaker.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 23:46:56 +00:00
Mario Beck f756fe852a fix getUseType and rename enum 2025-07-27 21:02:00 +02:00
Mario Beck f4aeca87f0 handle ts5/6 license correctly
allows joining of a ts6 beta server
2025-07-27 20:53:43 +02:00
nodamnway 41c8c8a899 Fragments: All parts should have NEW_PROTOCOL flag if original Packet has it
Fragments: fix last packet detection
2022-10-22 03:57:42 +02:00
sump pump ac8e7cf6f3 Update LocalTeamspeakClientSocket.java
Change client.password to client.server_password in LocalTeamspeakClientSocket.java so that password authentication is properly passed at connection time.
2020-08-11 10:49:58 -06:00
Phyrone baf74654f1 replaced IllegalArgumentException with an UnknownTeamspeakEvent if the event is not registered 2020-05-23 15:43:00 +02:00
Phyrone 0b5d63b6f7 unknown events will be catched and no longer break the whole client (f.e. on teaspeak servers) 2020-05-21 13:06:27 +02:00
Manevolent 289aa31645 Update tests 2019-12-04 22:01:47 -07:00
Manevolent 3a137f63c5 Increase maximum accepted reassembled packet size to 1MB, but continue to constrain directly received packet size at 65KB 2019-12-04 22:01:29 -07:00
Manevolent 475af91eef Don't optimistically send a command in onAssigned: causes a blocking issue 2019-11-26 11:44:11 -07:00
Manevolent 28c570f253 Remote socket address correctly passed 2019-11-26 11:34:30 -07:00
Manevolent 614b3d9d69 Address #9 and fix thread exits, add InterruptedException handlers, and make Microphone handling more stateful (don't run a thread all the time if nobody ever sets it) 2019-11-24 19:42:23 -07:00
Manevolent 92d97f96dc Fix two exceptions and fix channel password support 2019-11-22 09:07:38 -07:00
Manevolent 9694a3f2c5 The new TS3 server version broke TS3j, it is now ‭218092286‬ decimal. 2019-11-14 01:19:36 -07:00
Phyrone 06c21c0c56 made clientversion changeable 2019-07-16 23:47:05 +09:00
Manevolent d7b996e897 Merge remote-tracking branch 'origin/master' 2019-05-29 11:50:47 -04:00
Manevolent a86381a47b Exception propagation 2019-05-29 11:50:40 -04:00
Manevolent 51aac79189 Merge remote-tracking branch 'origin/master' 2019-03-05 11:05:05 -05:00
Manevolent d750f9685c Setting description, editing client properties 2019-03-05 11:04:54 -05:00
Manevolent 299a0457bd runtime error 2019-02-12 18:35:24 -05:00
Manevolent 9648bd6226 adding/removing client permissions 2019-02-12 18:35:18 -05:00
Manevolent 55b10d6ba5 Merge remote-tracking branch 'origin/master' 2019-02-05 08:51:54 -05:00
Manevolent a883c8beef notifyclientchatclosed event handled 2019-02-05 08:51:46 -05:00
Manevolent 7c33cfa97a - There was a bug that could cause TS3J to stop firing certain events to all event listeners if the command execution codes were generated quickly, sequentially by those event listener threads. This is now fixed.
- There is now more detailed output for command futures when reconnecting: "client reconnecting" instead of "client disconnected"
 - The MusicPlayer example now returns exit code -1 when it is kicked/disconnected prematurely.
2019-01-22 21:07:51 -05:00
Manevolent 0fed4c68ce Clamp high precision timer to specific tick drift 2019-01-22 11:50:03 -05:00
Manevolent 8cd5fd100c We don't have an "onConnected" event, adding that now. 2019-01-20 19:34:26 -05:00
Manevolent 941308d67b Example of music streaming from disk 2018-12-24 20:32:26 -05:00
Manevolent 7b25be6420 Improper order of operations for ident export 2018-12-22 11:59:36 -05:00
Manevolent d9c2805528 com.sun package breaking Jitpack.io 2018-12-21 16:15:53 -05:00
Manevolent 9d602a8f98 Added audio sender test and disconnect reasons 2018-12-21 11:02:08 -05:00
Manevolent 72c585a089 Ts3 INI saving, API is in. Loads into the official client, too. Check out LocalIdentity.save() methods 2018-12-21 09:57:49 -05:00
Manevolent 91187964c5 Ts3 INI identity loading 2018-11-05 14:48:31 -05:00
Manevolent 3987f3c097 Allow getChannelInfo when in RETRIEVING_DATA state 2018-10-23 09:52:46 -04:00
Manevolent f06634879b Merge remote-tracking branch 'origin/master'
# Conflicts:
#	src/main/java/com/github/manevolent/ts3j/protocol/socket/client/LocalTeamspeakClientSocket.java
2018-10-22 13:42:29 -04:00
Manevolent efd4b4b771 Reorganizing the removal of awaiting commands and so forth in hopes that lock-ups don't happen on reconnect. 2018-10-22 13:40:43 -04:00
Manevolent 99398369f1 Move stuff around 2018-10-13 16:32:23 -04:00
Manevolent 7889dc0caf Send serverflag0 with new packets as a test of sorts 2018-10-13 16:31:34 -04:00
Manevolent 61ce9df1f8 Compilation issues with jitpack 2018-10-13 16:14:07 -04:00
Manevolent 2202b3ab9a Now that we have discerned the issue with receiving audio packets, I feel better reverting back to only providing the packet body, and not the header also, in the user callbacks. 2018-10-13 16:08:55 -04:00
Manevolent d97b95f021 When the COMPRESSED flag is set by the official Teamspeak Gbmh client on a VOICE or VOICE_WHISPER packet, which is done for the first 5 packets of any decoder session, the packet is always 1 byte longer. More importantly, the final byte is static for those 5 packets.
You have to trim that last byte off, otherwise your audio will be corrupted.  TS3J now does this automatically and stores it in ServerFlag0 for you, as a nullable Byte object. This way you can handle it if you need to. This has also been factored into the output/write stage.

Digging into theory, I believe this ID has something to do with the opening of a new decoder to ensure that the decoder opens cleanly each time. You do NOT have to do anything to your decoder to reset states, etc., from what I can tell. In other words, COMPRESSED being on shouldn't change the behavior of your decoding.
2018-10-13 16:03:51 -04:00