diff --git a/pom.xml b/pom.xml index 5d85690..2dcc19c 100644 --- a/pom.xml +++ b/pom.xml @@ -45,5 +45,11 @@ commons-lang 2.6 + + + dnsjava + dnsjava + 2.1.8 + \ No newline at end of file diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/TS3DNS.java b/src/main/java/com/github/manevolent/ts3j/protocol/TS3DNS.java new file mode 100644 index 0000000..8b6fab9 --- /dev/null +++ b/src/main/java/com/github/manevolent/ts3j/protocol/TS3DNS.java @@ -0,0 +1,43 @@ +package com.github.manevolent.ts3j.protocol; + +import org.xbill.DNS.*; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.UnknownHostException; +import java.util.*; +import java.util.stream.Collectors; + +public class TS3DNS { + private static final int TS3_VOICE_DEFAULT_PORT = 9987; + private static final int TS3_QUERY_DEFAULT_PORT = 10011; + private static final int TS3_FILETRANSFER_DEFAULT_PORT = 30033; + private static final int TSDNS_DEFAULT_PORT = 41144; + + private static final String DNS_PREFIX_TCP = "_tsdns._tcp."; + private static final String DNS_PREFIX_UDP = "_ts3._udp."; + + private static List lookupSRV(String domain) throws IOException { + org.xbill.DNS.Record[] records = new Lookup(domain, Type.SRV).run(); + + if (records == null || records.length <= 0) throw new UnknownHostException("Host not found"); + + return Arrays.stream(records) + .filter(Objects::nonNull) + .map(x -> (SRVRecord) x) + .filter(x -> x.getTarget() != null) + .sorted((a, b) -> { + // Loose sorting + int prioComp = Integer.compare(a.getPriority(), b.getPriority()); + if (prioComp != 0) return prioComp; + else return Integer.compare(a.getWeight(), b.getWeight()); + }) + .map(x -> new InetSocketAddress(x.getTarget().toString(), x.getPort())) + .collect(Collectors.toList()); + } + + public static List lookup(String domain) throws IOException { + return lookupSRV(DNS_PREFIX_UDP + domain); + } +} diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/LocalTeamspeakClientSocket.java b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/LocalTeamspeakClientSocket.java index 1594fdf..61fc912 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/LocalTeamspeakClientSocket.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/LocalTeamspeakClientSocket.java @@ -12,10 +12,7 @@ import com.github.manevolent.ts3j.command.response.CommandResponse; import com.github.manevolent.ts3j.event.*; import com.github.manevolent.ts3j.identity.LocalIdentity; import com.github.manevolent.ts3j.identity.Uid; -import com.github.manevolent.ts3j.protocol.NetworkPacket; -import com.github.manevolent.ts3j.protocol.PacketKind; -import com.github.manevolent.ts3j.protocol.ProtocolRole; -import com.github.manevolent.ts3j.protocol.SocketRole; +import com.github.manevolent.ts3j.protocol.*; import com.github.manevolent.ts3j.protocol.client.ClientConnectionState; import com.github.manevolent.ts3j.protocol.header.PacketHeader; import com.github.manevolent.ts3j.protocol.packet.PacketBody0Voice; @@ -24,6 +21,7 @@ import com.github.manevolent.ts3j.protocol.packet.statistics.PacketStatistics; import com.github.manevolent.ts3j.util.HighPrecisionRecurrentTask; import com.github.manevolent.ts3j.util.Ts3Debugging; import com.github.manevolent.ts3j.util.Pair; +import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils; import java.io.EOFException; import java.io.IOException; @@ -33,6 +31,7 @@ import java.nio.ByteOrder; import java.util.*; import java.util.concurrent.*; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Collectors; public class LocalTeamspeakClientSocket @@ -255,12 +254,35 @@ public class LocalTeamspeakClientSocket remote = null; } + + /** + * Initiates a connection to a server + * @param hostname Hostname to contact + * @param password server password (may be null) + * @param timeout timeout, in milliseconds, to complete a connection. + */ + public void connect(String hostname, String password, long timeout) throws + UnknownHostException, + IOException, + TimeoutException { + + InetSocketAddress address; + + try { + // Attempt TS3DNS + address = TS3DNS.lookup(hostname).stream().findFirst().orElseThrow(() -> new UnknownHostException(hostname)); + } catch (UnknownHostException e) { + address = new InetSocketAddress(hostname, 9987); + } + + connect(address, password, timeout); + } + /** * Initiates a connection to a server * @param remote remote sever to contact - * @param password server password + * @param password server password (may be null) * @param timeout timeout, in milliseconds, to complete a connection. - * @throws IOException */ public void connect(InetSocketAddress remote, String password, long timeout) throws IOException, TimeoutException { @@ -287,7 +309,7 @@ public class LocalTeamspeakClientSocket setOption("client.hostname", remote.getHostString()); - if (password != null) setOption("client.password", password); + if (password != null && password.length() > 0) setOption("client.password", password); setState(ClientConnectionState.CONNECTING); @@ -298,6 +320,7 @@ public class LocalTeamspeakClientSocket 0.01F, new MicrophoneTask() ); + microphoneThread.setDaemon(true); microphoneThread.start(); } catch (TimeoutException e) { diff --git a/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java b/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java index c332d85..93e325d 100644 --- a/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java +++ b/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java @@ -37,10 +37,7 @@ public class ServerConnectionTest { client.setOption("client.hwid", "JAVAJAVAJAVA"); client.connect( - new InetSocketAddress( - "ts.teamlixo.net", - 9987 - ), + "teamlixo.net", null, 10000L ); diff --git a/src/test/java/com/github/manevolent/ts3j/TS3DNSTest.java b/src/test/java/com/github/manevolent/ts3j/TS3DNSTest.java new file mode 100644 index 0000000..a34fbb6 --- /dev/null +++ b/src/test/java/com/github/manevolent/ts3j/TS3DNSTest.java @@ -0,0 +1,27 @@ +package com.github.manevolent.ts3j; + +import com.github.manevolent.ts3j.protocol.TS3DNS; +import com.github.manevolent.ts3j.util.Ts3Debugging; +import junit.framework.TestCase; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.List; + +public class TS3DNSTest extends TestCase { + + public static void main(String[] args) throws Exception { + new TS3DNSTest().testParser(); + } + + public void testParser() throws Exception { + Ts3Debugging.setEnabled(true); + + List soaddr = TS3DNS.lookup("voice.teamspeak.com"); + + assertTrue(soaddr.size() > 0); + + for (SocketAddress socketAddress : soaddr) + Ts3Debugging.debug(socketAddress); + } +}