Sofia的异步DNS解析器--“sresolv“

"sresolv" 模块信息

        Sofia 的sresolv 模块实现了一个带有EDNS扩展功能的异步DNS解析器。在头文件中声明了使用su_root_t的相关接口。

        还有一套可选的备用接口,由下面一组文件共同声明:

        相关RFC文档包括:RFC 1034, RFC 1035, RFC 1886, RFC 2671, RFC 2782, RFC 2915。

 

为什么Sofia要自己实现DNS解析?

        通常的开源DNS解析库要么是同步的,要么只解析主机名,换句话说,在DNS查询时,要么堵塞线程,要么信息不够。由于SIP协议除了使用常规的A类和AAAA类查询之外,还使用NATPR和SRV查询,那么这类DNS库显然不能满足SIP应用的需求。

        Sofia的解析器使用DNS的常规配置。在类Unix系统中,DNS配置存储在/etc/resolv.conf文件里;在Windows系统中,则存储在注册表中。Sofia在监测到配置修改时,会自动重新加载这些配置。

        除了配置文件之外,可以利用环境变量 SRES_OPTIONS 和RES_OPTIONS改变解析器的行为。

 

Sofia 解析器的使用

        Sofia解析器通常是异步工作的,换句话说,它生成查询请求并发给DNS服务器,并立即返回调用点。当收到DNS应答消息时,查询结束,sresolv模块通过回调函数通知应用层。

        应用层既可以对解析器所使用的文件描述符显式调用poll 或select,并调用驱动函数,也可以使用一个指向 su_root_t对象的指针。此外,还有第三种选择:调用解析器提供的同步接口 sres_blocking_query()。

        sresolv模块有一个内部缓存。查询函数会把DNS记录添加到缓存中,使用缓存记录的方式和直接从DNS服务器上查询的方式是一样的。

        请注意:你必须为每个使用Sofia解析器的线程单独创建resolver对象。但是,resolver对象之间是可以共享缓存的。

 

里声明的接口

       里声明了从su_root_t 驱动Sofia解析器的简单使用接口。可以用sres_resolver_create()创建resolver对象。提供的 root 对象负责调用sres_query()和sres_query_sockaddr(),以及回调函数。

#include 

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);

发送DNS请求

        所声明接口的第二部分是发送DNS查询接口:

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);

处理DNS应答

        接口声明的第三部分是处理DNS应答和记录,并把返回的记录添加到缓存:

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);

Interface in 里声明的接口

        里声明了Sofia解析器的通用接口。首先是处理resolver对象的函数:

#include 
#include 
#include 

#include 

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);

同步解析

         还提供了一个堵塞接口,可以执行同步DNS查询,换句话说,调用这个接口查询DNS不会马上返回,而是一直等到查询结束或超时。

#include 
#include 
#include 

#include 

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);

里的异步接口

        不用su_root_t 对象也可以实现异步查询:

#include 
#include 
#include 

#include 

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);

 

以下是一个简单的代码片段,展示如何使用su_root_t驱动解析器:

#define SRES_CONTEXT_T struct context

#include 

...

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);
}

 

你可能感兴趣的:(Sofia)