== DNS client

Often you will find yourself in situations where you need to obtain DNS informations in an asynchronous fashion.
Unfortunally this is not possible with the API that is shipped with the Java Virtual Machine itself. Because of
this Vert.x offers it's own API for DNS resolution which is fully asynchronous.

To obtain a DnsClient instance you will create a new via the Vertx instance.

[source,java]
----
DnsClient client = vertx.createDnsClient(53, "10.0.0.1");
----

You can also create the client with options and configure the query timeout.

[source,java]
----
DnsClient client = vertx.createDnsClient(new DnsClientOptions()
  .setPort(53)
  .setHost("10.0.0.1")
  .setQueryTimeout(10000)
);
----

Creating the client with no arguments or omitting the server address will use the address of the server used internally
for non blocking address resolution.

[source,java]
----
DnsClient client1 = vertx.createDnsClient();

// Just the same but with a different query timeout
DnsClient client2 = vertx.createDnsClient(new DnsClientOptions().setQueryTimeout(10000));
----

A client uses a single event loop for querying purposes, it can safely be used from any thread, including non Vert.x thread.

=== lookup

Try to lookup the A (ipv4) or AAAA (ipv6) record for a given name. The first which is returned will be used,
so it behaves the same way as you may be used from when using "nslookup" on your operation system.

To lookup the A / AAAA record for "vertx.io" you would typically use it like:

[source,java]
----
DnsClient client = vertx.createDnsClient(53, "9.9.9.9");
client
  .lookup("vertx.io")
  .onComplete(ar -> {
    if (ar.succeeded()) {
      System.out.println(ar.result());
    } else {
      System.out.println("Failed to resolve entry" + ar.cause());
    }
  });
----

=== lookup4

Try to lookup the A (ipv4) record for a given name. The first which is returned will be used, so it behaves
the same way as you may be used from when using "nslookup" on your operation system.

To lookup the A record for "vertx.io" you would typically use it like:

[source,java]
----
DnsClient client = vertx.createDnsClient(53, "9.9.9.9");
client
  .lookup4("vertx.io")
  .onComplete(ar -> {
    if (ar.succeeded()) {
      System.out.println(ar.result());
    } else {
      System.out.println("Failed to resolve entry" + ar.cause());
    }
  });
----

=== lookup6

Try to lookup the AAAA (ipv6) record for a given name. The first which is returned will be used, so it behaves the
same way as you may be used from when using "nslookup" on your operation system.

To lookup the A record for "vertx.io" you would typically use it like:

[source,java]
----
DnsClient client = vertx.createDnsClient(53, "9.9.9.9");
client
  .lookup6("vertx.io")
  .onComplete(ar -> {
    if (ar.succeeded()) {
      System.out.println(ar.result());
    } else {
      System.out.println("Failed to resolve entry" + ar.cause());
    }
  });
----

=== resolveA

Try to resolve all A (ipv4) records for a given name. This is quite similar to using "dig" on unix like operation
systems.

To lookup all the A records for "vertx.io" you would typically do:

[source,java]
----
DnsClient client = vertx.createDnsClient(53, "9.9.9.9");
client
  .resolveA("vertx.io")
  .onComplete(ar -> {
    if (ar.succeeded()) {
      List<String> records = ar.result();
      for (String record : records) {
        System.out.println(record);
      }
    } else {
      System.out.println("Failed to resolve entry" + ar.cause());
    }
  });
----

=== resolveAAAA

Try to resolve all AAAA (ipv6) records for a given name. This is quite similar to using "dig" on unix like
operation systems.

To lookup all the AAAAA records for "vertx.io" you would typically do:

[source,java]
----
DnsClient client = vertx.createDnsClient(53, "9.9.9.9");
client
  .resolveAAAA("vertx.io")
  .onComplete(ar -> {
    if (ar.succeeded()) {
      List<String> records = ar.result();
      for (String record : records) {
        System.out.println(record);
      }
    } else {
      System.out.println("Failed to resolve entry" + ar.cause());
    }
  });
----

=== resolveCNAME

Try to resolve all CNAME records for a given name. This is quite similar to using "dig" on unix like operation
systems.

To lookup all the CNAME records for "vertx.io" you would typically do:

[source,java]
----
DnsClient client = vertx.createDnsClient(53, "9.9.9.9");
client
  .resolveCNAME("vertx.io")
  .onComplete(ar -> {
    if (ar.succeeded()) {
      List<String> records = ar.result();
      for (String record : records) {
        System.out.println(record);
      }
    } else {
      System.out.println("Failed to resolve entry" + ar.cause());
    }
  });
----

=== resolveMX

Try to resolve all MX records for a given name. The MX records are used to define which Mail-Server accepts
emails for a given domain.

To lookup all the MX records for "vertx.io" you would typically do:

[source,java]
----
DnsClient client = vertx.createDnsClient(53, "9.9.9.9");
client
  .resolveMX("vertx.io")
  .onComplete(ar -> {
    if (ar.succeeded()) {
      List<MxRecord> records = ar.result();
      for (MxRecord record : records) {
        System.out.println(record);
      }
    } else {
      System.out.println("Failed to resolve entry" + ar.cause());
    }
  });
----

Be aware that the List will contain the `link:../../apidocs/io/vertx/core/dns/MxRecord.html[MxRecord]` sorted by the priority of them, which
means MX records with smaller priority coming first in the List.

The `link:../../apidocs/io/vertx/core/dns/MxRecord.html[MxRecord]` allows you to access the priority and the name of the MX record by offer methods for it like:

[source,java]
----
record.priority();
record.name();
----

=== resolveTXT

Try to resolve all TXT records for a given name. TXT records are often used to define extra information for a domain.

To resolve all the TXT records for "vertx.io" you could use something along these lines:

[source,java]
----
DnsClient client = vertx.createDnsClient(53, "9.9.9.9");
client
  .resolveTXT("vertx.io")
  .onComplete(ar -> {
    if (ar.succeeded()) {
      List<String> records = ar.result();
      for (String record : records) {
        System.out.println(record);
      }
    } else {
      System.out.println("Failed to resolve entry" + ar.cause());
    }
  });
----

=== resolveNS

Try to resolve all NS records for a given name. The NS records specify which DNS Server hosts the DNS informations
for a given domain.

To resolve all the NS records for "vertx.io" you could use something along these lines:

[source,java]
----
DnsClient client = vertx.createDnsClient(53, "9.9.9.9");
client
  .resolveNS("vertx.io")
  .onComplete(ar -> {
    if (ar.succeeded()) {
      List<String> records = ar.result();
      for (String record : records) {
        System.out.println(record);
      }
    } else {
      System.out.println("Failed to resolve entry" + ar.cause());
    }
  });
----

=== resolveSRV

Try to resolve all SRV records for a given name. The SRV records are used to define extra information like port and
hostname of services. Some protocols need this extra information.

To lookup all the SRV records for "vertx.io" you would typically do:

[source,java]
----
DnsClient client = vertx.createDnsClient(53, "9.9.9.9");
client
  .resolveSRV("vertx.io")
  .onComplete(ar -> {
    if (ar.succeeded()) {
      List<SrvRecord> records = ar.result();
      for (SrvRecord record : records) {
        System.out.println(record);
      }
    } else {
      System.out.println("Failed to resolve entry" + ar.cause());
    }
  });
----

Be aware that the List will contain the SrvRecords sorted by the priority of them, which means SrvRecords
with smaller priority coming first in the List.

The `link:../../apidocs/io/vertx/core/dns/SrvRecord.html[SrvRecord]` allows you to access all information contained in the SRV record itself:

[source,java]
----
record.priority();
record.name();
record.weight();
record.port();
record.protocol();
record.service();
record.target();
----

Please refer to the API docs for the exact details.

=== resolvePTR

Try to resolve the PTR record for a given name. The PTR record maps an ipaddress to a name.

To resolve the PTR record for the ipaddress 10.0.0.1 you would use the PTR notion of "1.0.0.10.in-addr.arpa"

[source,java]
----
DnsClient client = vertx.createDnsClient(53, "9.9.9.9");
client
  .resolvePTR("1.0.0.10.in-addr.arpa")
  .onComplete(ar -> {
    if (ar.succeeded()) {
      String record = ar.result();
      System.out.println(record);
    } else {
      System.out.println("Failed to resolve entry" + ar.cause());
    }
  });
----

=== reverseLookup

Try to do a reverse lookup for an ipaddress. This is basically the same as resolve a PTR record, but allows you to
just pass in the ipaddress and not a valid PTR query string.

To do a reverse lookup for the ipaddress 10.0.0.1 do something similar like this:

[source,java]
----
DnsClient client = vertx.createDnsClient(53, "9.9.9.9");
client
  .reverseLookup("10.0.0.1")
  .onComplete(ar -> {
    if (ar.succeeded()) {
      String record = ar.result();
      System.out.println(record);
    } else {
      System.out.println("Failed to resolve entry" + ar.cause());
    }
  });
----

=== Error handling

As you saw in previous sections the DnsClient allows you to pass in a Handler which will be notified with an
AsyncResult once the query was complete. In case of an error it will be notified with a DnsException which will
hole a `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html[DnsResponseCode]` that indicate why the resolution failed. This DnsResponseCode
can be used to inspect the cause in more detail.

Possible DnsResponseCodes are:

- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#NOERROR[NOERROR]` No record was found for a given query
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#FORMERROR[FORMERROR]` Format error
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#SERVFAIL[SERVFAIL]` Server failure
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#NXDOMAIN[NXDOMAIN]` Name error
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#NOTIMPL[NOTIMPL]` Not implemented by DNS Server
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#REFUSED[REFUSED]` DNS Server refused the query
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#YXDOMAIN[YXDOMAIN]` Domain name should not exist
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#YXRRSET[YXRRSET]` Resource record should not exist
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#NXRRSET[NXRRSET]` RRSET does not exist
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#NOTZONE[NOTZONE]` Name not in zone
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#BADVERS[BADVERS]` Bad extension mechanism for version
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#BADSIG[BADSIG]` Bad signature
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#BADKEY[BADKEY]` Bad key
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#BADTIME[BADTIME]` Bad timestamp

All of those errors are "generated" by the DNS Server itself.

You can obtain the DnsResponseCode from the DnsException like:

[source,java]
----
DnsClient client = vertx.createDnsClient(53, "10.0.0.1");
client
  .lookup("nonexisting.vert.xio")
  .onComplete(ar -> {
    if (ar.succeeded()) {
      String record = ar.result();
      System.out.println(record);
    } else {
      Throwable cause = ar.cause();
      if (cause instanceof DnsException) {
        DnsException exception = (DnsException) cause;
        DnsResponseCode code = exception.code();
        // ...
      } else {
        System.out.println("Failed to resolve entry" + ar.cause());
      }
    }
  });
----