Sofia Asynchronous DNS Resolver

1.12.1

Module Information

The Sofia sresolv module consists of an asynchronous DNS resolver with EDNS extensions. The interface to library is declared in <sofia-sip/sresolv.h>.

An alternative interface is defined by <sofia-resolv/sres.h>, <sofia-resolv/sres_record.h>, <sofia-resolv/sres_async.h>, and <sofia-resolv/sres_cache.h>.

Contact:
Pekka Pessi <Pekka.Pessi@nokia-email.address.hidden>
Status:
Core library
License:
LGPL
Todo:
Caching Policy and Cache Poisoning
The policy for caching non-authoritave entries should be solved.

Using Sofia Resolver

The sresolv works usually asynchronously, in other words, it sends a query to DNS server and returns immediately to the caller. When the query is completed, sresolv signals application through a callback function.

The application can either explicitly poll(2) or select(2) on file descriptors used by resolver and call the driver functions, or it can use su root a pointer to a su_root_t object. Third option is to use resolver synchronously with sres_blocking_query().

There is an internal cache used by sresolv. The query functions add records to the cache: using the cache is made similar as if receiving entries directly from DNS server.

Please note that you have to create a separate resolver object for each thread using Sofia resolver. The resolver objects can share the cache, however.

Interface in <sofia-sip/sresolv.h>

The simple use of Sofia resolver driven from su_root_t is defined in <sofia-sip/sresolv.h>. The resolver object can be created with sres_resolver_create() and

#include <sofia-sip/sresolv.h>

sres_resolver_t *sres_resolver_create(su_root_t *root, 
                                      char const *resolv_conf,
                                      tag_type_t, tag_value_t, ...);

int sres_resolver_destroy(sres_resolver_t *res);

Sending DNS Queries

The second part of interface is used when sending DNS queries:

sres_query_t *sres_query(sres_resolver_t *res,
                         sres_answer_f *callback,
                         sres_context_t *context,
                         int socket,
                         uint16_t type,
                         char const *domain);

sres_query_t *sres_query_sockaddr(sres_resolver_t *res,
                                  sres_answer_f *callback,
                                  sres_context_t *context,
                                  int socket,
                                  uint16_t type,
                                  struct sockaddr const *addr);

void sres_query_bind(sres_query_t *q,
                     sres_answer_f *callback,
                     sres_context_t *context);

Handling DNS Records

The third part is used to handle the records which were returned by DNS query or stored into the cache:

sres_record_t **sres_cached_answers(sres_resolver_t *res,
                                    uint16_t type,
                                    char const *domain);

sres_record_t **sres_cached_answers_sockaddr(sres_resolver_t *res,
                                             uint16_t type,
                                             struct sockaddr const *addr);

int sres_sort_answers(sres_resolver_t *res, sres_record_t **answers);

int sres_filter_answers(sres_resolver_t *sres, sres_record_t **answers, 
                        uint16_t type);

void sres_free_answers(sres_resolver_t *res, sres_record_t **answers);

void sres_free_answer(sres_resolver_t *res, sres_record_t *answer);

Using Sofia Resolver

Here is a short code fragment showing how to use resolver driven from su_root_t:

#define SRES_CONTEXT_T struct context

#include <sofia-sip/sresolv.h>

...

struct context
{
  ...
  su_root_t *root;
  sres_resolver_t *sres;
  sres_query_t *query;
  ...
} *context;

...

  context->sres = sres_resolver_create(context->root, NULL, TAG_END());

...

  sres_record_t *results;

  results = sres_cached_answers(context->sres, sres_type_naptr, domain);
  if (results) {
    process_natpr(context, NULL, results);
  }
  else {
    context->query = sres_query(context->sres, 
                                process_natpr, context,
                                sres_type_naptr, domain);
    if (!context->query)
      process_naptr(context, NULL, NULL);
  }
}
...

void process_natpr(sres_context_t *context,
                   sres_query_t *q,
                   sres_record_t *answers[])
{
  sres_sort_answers(context->sres, answers);
 
  ...
 
  sres_free_answers(context->sres, answers);
}

Interface in <sofia-resolv/sres.h>

The generic interface to Sofia resolver is defined in <sofia-resolv/sres.h>. The first part of interface consists of functions for handling resolver objects:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <sofia-resolv/sres.h>

sres_resolver_t *sres_resolver_new(char const *resolv_conf_path);

sres_resolver_t *sres_resolver_new_with_cache(char const *conf_file_path,
                                              sres_cache_t *cache,
                                              char const *options, ...);

sres_resolver_t *sres_resolver_ref(sres_resolver_t *res);
void sres_resolver_unref(sres_resolver_t *res);

sres_resolver_t *sres_resolver_copy(sres_resolver_t *);

void *sres_resolver_set_userdata(sres_resolver_t *res, void *userdata);
void *sres_resolver_get_userdata(sres_resolver_t const *res);

Using Sofia Resolver Synchronously

It is possible to use Sofia resolver synchronously, that is, the function call making the DNS query does not return until the query is responded or times out.

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <sofia-resolv/sres.h>

int sres_blocking_query(sres_resolver_t *res,
                        uint16_t type,
                        char const *domain,
                        sres_record_t ***return_records);

int sres_blocking_query_sockaddr(sres_resolver_t *res,
                                 uint16_t type,
                                 struct sockaddr const *addr,
                                 sres_record_t ***return_records);

Asynchronous Interface in <sofia-resolv/sres_async.h>

It is also possible to use resolver asynchronously without su_root_t object.

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <sofia-resolv/sres_async.h>

sres_async_t *sres_resolver_set_async(sres_resolver_t *res, 
                                      sres_update_f *update,
                                      sres_async_t *async,
                                      int update_all);
sres_async_t *sres_resolver_get_async(sres_resolver_t const *res,
                                      sres_update_f *update);

int sres_resolver_sockets(sres_resolver_t const *res, int *sockets, int n);
void sres_resolver_timer(sres_resolver_t *, int socket);

int sres_resolver_receive(sres_resolver_t *res, int socket);
int sres_resolver_error(sres_resolver_t *res, int socket);

Sofia-SIP 1.12.1 - Copyright (C) 2006 Nokia Corporation. All rights reserved. Licensed under the terms of the GNU Lesser General Public License.