it works minus SRV
This commit is contained in:
@@ -212,14 +212,16 @@ public class ArcNetProvider implements NetProvider{
|
|||||||
@Override
|
@Override
|
||||||
public void pingHost(String address, int port, Cons<Host> valid, Cons<Exception> invalid){
|
public void pingHost(String address, int port, Cons<Host> valid, Cons<Exception> invalid){
|
||||||
long time = Time.millis();
|
long time = Time.millis();
|
||||||
var socket = new InetSocketAddress(address, port);
|
|
||||||
Log.info("Time to resolve @: @", address, Time.timeSinceMillis(time));
|
|
||||||
|
|
||||||
AsyncUdp.send(socket, 2000, 512, ByteBuffer.wrap(new byte[]{-2, 1}), data -> {
|
Dns.resolveAddress(address, inetaddr -> {
|
||||||
Host host = NetworkIO.readServerData((int)Time.timeSinceMillis(time), socket.getAddress().getHostAddress(), data);
|
var socket = new InetSocketAddress(inetaddr, port);
|
||||||
host.port = port;
|
|
||||||
Core.app.post(() -> valid.get(host));
|
AsyncUdp.send(socket, 2000, 512, ByteBuffer.wrap(new byte[]{-2, 1}), data -> {
|
||||||
}, e -> Core.app.post(() -> invalid.get(e)));
|
Host host = NetworkIO.readServerData((int)Time.timeSinceMillis(time), socket.getAddress().getHostAddress(), data);
|
||||||
|
host.port = port;
|
||||||
|
Core.app.post(() -> valid.get(host));
|
||||||
|
}, e -> Core.app.post(() -> invalid.get(e)));
|
||||||
|
}, err -> Core.app.post(() -> invalid.get(err)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
try{
|
try{
|
||||||
|
|||||||
@@ -54,15 +54,14 @@ public class AsyncUdp{
|
|||||||
|
|
||||||
request.received.get(buffer);
|
request.received.get(buffer);
|
||||||
request.close();
|
request.close();
|
||||||
}catch(IOException error){
|
}catch(Exception error){
|
||||||
request.fail(error);
|
request.fail(error);
|
||||||
//TODO remove logging, this is not needed outside of debugging
|
|
||||||
Log.err(error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}catch(IOException e){
|
}catch(Throwable e){
|
||||||
|
//should not happen
|
||||||
Log.err(e);
|
Log.err(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,7 +97,6 @@ public class AsyncUdp{
|
|||||||
|
|
||||||
removals.offer(req);
|
removals.offer(req);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
Log.err(e);
|
|
||||||
failed.get(e);
|
failed.get(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -115,6 +113,8 @@ public class AsyncUdp{
|
|||||||
final DatagramChannel channel;
|
final DatagramChannel channel;
|
||||||
final SelectionKey key;
|
final SelectionKey key;
|
||||||
|
|
||||||
|
boolean closed = false;
|
||||||
|
|
||||||
public Request(InetSocketAddress address, long timeout, int bufferSize, ByteBuffer data, DatagramChannel channel, SelectionKey key, Cons<ByteBuffer> received, Cons<Exception> failed){
|
public Request(InetSocketAddress address, long timeout, int bufferSize, ByteBuffer data, DatagramChannel channel, SelectionKey key, Cons<ByteBuffer> received, Cons<Exception> failed){
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
@@ -128,8 +128,8 @@ public class AsyncUdp{
|
|||||||
}
|
}
|
||||||
|
|
||||||
void close(){
|
void close(){
|
||||||
if(!key.isValid()) return;
|
|
||||||
try{
|
try{
|
||||||
|
closed = true;
|
||||||
key.cancel();
|
key.cancel();
|
||||||
channel.close();
|
channel.close();
|
||||||
}catch(Exception close){
|
}catch(Exception close){
|
||||||
@@ -138,9 +138,10 @@ public class AsyncUdp{
|
|||||||
}
|
}
|
||||||
|
|
||||||
void fail(Exception error){
|
void fail(Exception error){
|
||||||
if(!key.isValid()) return;
|
if(!closed){
|
||||||
failed.get(error);
|
failed.get(error);
|
||||||
close();
|
close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
146
core/src/mindustry/net/Dns.java
Normal file
146
core/src/mindustry/net/Dns.java
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
package mindustry.net;
|
||||||
|
|
||||||
|
import arc.func.*;
|
||||||
|
import arc.math.*;
|
||||||
|
import arc.struct.*;
|
||||||
|
import arc.util.*;
|
||||||
|
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.*;
|
||||||
|
import java.nio.channels.*;
|
||||||
|
import java.nio.charset.*;
|
||||||
|
import java.util.regex.*;
|
||||||
|
|
||||||
|
public class Dns{
|
||||||
|
private static final Pattern ipPattern = Pattern.compile("^((0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)\\.){3}(0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)$");
|
||||||
|
private static final int aRecord = 1, srvRecord = 33;
|
||||||
|
private static IntMap<ObjectMap<String, Seq<?>>> cache = new IntMap<>();
|
||||||
|
private static Seq<InetSocketAddress> nameservers = Seq.with(new InetSocketAddress("1.1.1.1", 53), new InetSocketAddress("8.8.8.8", 53));
|
||||||
|
|
||||||
|
static <T> void resolve(int type, String domain, Func<ByteBuffer, T> reader, Cons<Seq<T>> result, Cons<Exception> error){
|
||||||
|
ObjectMap<String, Seq<?>> map;
|
||||||
|
|
||||||
|
synchronized(cache){
|
||||||
|
map = cache.get(type, ObjectMap::new);
|
||||||
|
|
||||||
|
//TODO timeout
|
||||||
|
if(map.containsKey(domain)){
|
||||||
|
result.get((Seq<T>)map.get(domain));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send(Seq.with(new InetSocketAddress("1.1.1.1", 53)), 0, type, domain, reader, records -> {
|
||||||
|
synchronized(cache){
|
||||||
|
//cache the records
|
||||||
|
map.put(domain, records);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.get(records);
|
||||||
|
}, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resolveAddress(String domain, Cons<InetAddress> result, Cons<Exception> error){
|
||||||
|
if(ipPattern.matcher(domain).matches()){
|
||||||
|
try{
|
||||||
|
result.get(InetAddress.getByName(domain));
|
||||||
|
}catch(Exception e){
|
||||||
|
error.get(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(aRecord, domain, bytes -> {
|
||||||
|
byte[] address = new byte[4];
|
||||||
|
bytes.get(address);
|
||||||
|
return address;
|
||||||
|
}, addresses -> {
|
||||||
|
try{
|
||||||
|
if(addresses.size > 0){
|
||||||
|
result.get(InetAddress.getByAddress(addresses.get(0)));
|
||||||
|
}else{
|
||||||
|
//there are no records found
|
||||||
|
error.get(new UnresolvedAddressException());
|
||||||
|
}
|
||||||
|
}catch(UnknownHostException unknown){
|
||||||
|
error.get(unknown);
|
||||||
|
}
|
||||||
|
}, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T> void send(Seq<InetSocketAddress> addresses, int index, int type, String domain, Func<ByteBuffer, T> reader, Cons<Seq<T>> recordResult, Cons<Exception> error){
|
||||||
|
short id = (short)new Rand().nextInt(Short.MAX_VALUE);
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(512);
|
||||||
|
|
||||||
|
buffer.putShort(id); // Id
|
||||||
|
buffer.putShort((short) 0x0100); // Flags (recursion enabled)
|
||||||
|
buffer.putShort((short) 1); // Questions
|
||||||
|
buffer.putShort((short) 0); // Answers
|
||||||
|
buffer.putShort((short) 0); // Authority
|
||||||
|
buffer.putShort((short) 0); // Additional
|
||||||
|
|
||||||
|
// Domain
|
||||||
|
for(String part : domain.split("\\.")) {
|
||||||
|
buffer.put((byte) part.length());
|
||||||
|
buffer.put(part.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
buffer.put((byte) 0);
|
||||||
|
|
||||||
|
buffer.putShort((short) type); // Type
|
||||||
|
buffer.putShort((short) 1); // Class (Internet)
|
||||||
|
|
||||||
|
buffer.flip();
|
||||||
|
|
||||||
|
AsyncUdp.send(addresses.get(index), 2000, 512, buffer, result -> {
|
||||||
|
short responseId = result.getShort();
|
||||||
|
if(responseId != id) {
|
||||||
|
throw new ArcRuntimeException("Invalid response ID");
|
||||||
|
}
|
||||||
|
|
||||||
|
result.getShort();
|
||||||
|
result.getShort();
|
||||||
|
int answers = result.getShort() & 0xFFFF;
|
||||||
|
result.getShort();
|
||||||
|
result.getShort();
|
||||||
|
|
||||||
|
byte len;
|
||||||
|
while((len = result.get()) != 0) {
|
||||||
|
result.position(result.position() + len);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.getShort();
|
||||||
|
result.getShort();
|
||||||
|
|
||||||
|
var records = new Seq<T>(answers);
|
||||||
|
|
||||||
|
for(int i = 0; i < answers; i++) {
|
||||||
|
result.getShort(); // OFFSET
|
||||||
|
int answerType = result.getShort() & 0xFFFF; // Type
|
||||||
|
result.getShort(); // Class
|
||||||
|
long ttl = result.getInt() & 0xFFFFFFFFL; // TTL
|
||||||
|
int length = result.getShort() & 0xFFFF; // Data length
|
||||||
|
|
||||||
|
// Optionally CNAME results will be returned with the A results, skip those
|
||||||
|
if(answerType != type){
|
||||||
|
result.position(result.position() + length);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int position = result.position();
|
||||||
|
|
||||||
|
records.add(reader.get(result));
|
||||||
|
|
||||||
|
result.position(position + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
recordResult.get(records);
|
||||||
|
}, e -> {
|
||||||
|
if(index >= addresses.size - 1){
|
||||||
|
error.get(e);
|
||||||
|
}else{
|
||||||
|
send(addresses, index + 1, type, domain, reader, recordResult, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user