⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sres.c

📁 sip协议栈
💻 C
📖 第 1 页 / 共 5 页
字号:
su_log_t sresolv_log[] = { SU_LOG_INIT("sresolv", "SRESOLV_DEBUG", 3) };/** Internal errors */enum {  SRES_EDNS0_ERR = 255		/**< Server did not support EDNS. */};/* ---------------------------------------------------------------------- *//**Create a resolver. * * Allocate and initialize a new sres resolver object. The resolver object * contains the parsed resolv.conf file, a cache object containing past * answers from DNS, and a list of active queries. The default resolv.conf * file can be overriden by giving the name of the configuration file as @a * conf_file_path. * * @param conf_file_path name of the resolv.conf configuration file  * * @return A pointer to a newly created sres resolver object, or NULL upon * an error. */sres_resolver_t *sres_resolver_new(char const *conf_file_path){  return sres_resolver_new_internal(NULL, NULL, conf_file_path, NULL);}/** Copy a resolver. * * Make a copy of resolver with old */sres_resolver_t *sres_resolver_copy(sres_resolver_t *res){  char const *cnffile;  sres_config_t *config;  sres_cache_t *cache;  char const **options;  if (!res)    return NULL;  cnffile = res->res_cnffile;  config = su_home_ref(res->res_config->c_home);  cache = res->res_cache;  options = res->res_options;  return sres_resolver_new_internal(cache, config, cnffile, options);}/**New resolver object. * * Allocate and initialize a new sres resolver object. The resolver object * contains the parsed resolv.conf file, a cache object containing past * answers from DNS, and a list of active queries. The default resolv.conf * file can be overriden by giving the name of the configuration file as @a * conf_file_path. * * It is also possible to override the values in the resolv.conf and * RES_OPTIONS by giving the directives in the NULL-terminated list. * * @param conf_file_path name of the resolv.conf configuration file  * @param cache          optional pointer to a resolver cache * @param option, ...    list of resolv.conf options directives  *                       (overriding options in conf_file) * * @par Environment Variables * - LOCALDOMAIN overrides @c domain or @c search directives * - RES_OPTIONS overrides values of @a options in resolv.conf * - SRES_OPTIONS overrides values of @a options in resolv.conf, RES_OPTIONS, *   and @a options, ... list given as argument for this function * * @return A pointer to a newly created sres resolver object, or NULL upon * an error. */sres_resolver_t *sres_resolver_new_with_cache(char const *conf_file_path,			     sres_cache_t *cache,			     char const *option, ...){  sres_resolver_t *retval;  va_list va;  va_start(va, option);  retval = sres_resolver_new_with_cache_va(conf_file_path, cache, option, va);  va_end(va);  return retval;}/**Create a resolver. * * Allocate and initialize a new sres resolver object.  * * This is a stdarg version of sres_resolver_new_with_cache(). */sres_resolver_t *sres_resolver_new_with_cache_va(char const *conf_file_path,				sres_cache_t *cache,				char const *option,				va_list va){  va_list va0;  size_t i;  char const *o, *oarray[16], **olist = oarray;  sres_resolver_t *res;  va_copy(va0, va);    for (i = 0, o = option; o; o = va_arg(va0, char const *)) {    if (i < 16)      olist[i] = o;    i++;  }  if (i >= 16) {    olist = malloc((i + 1) * sizeof *olist);    if (!olist)      return NULL;    for (i = 0, o = option; o; o = va_arg(va, char const *)) {      olist[i++] = o;      i++;    }  }  olist[i] = NULL;  res = sres_resolver_new_internal(cache, NULL, conf_file_path, olist);  if (olist != oarray)    free(olist);  return res;}sres_resolver_t *sres_resolver_new_internal(sres_cache_t *cache,			   sres_config_t const *config,			   char const *conf_file_path,			   char const **options){  sres_resolver_t *res;  size_t i, n, len;  char **array, *o, *end;   for (n = 0, len = 0; options && options[n]; n++)    len += strlen(options[n]) + 1;  res = su_home_new(sizeof(*res) + (n + 1) * (sizeof *options) + len);  if (res == NULL)    return NULL;  array = (void *)(res + 1);  o = (void *)(array + n + 1);  end = o + len;  for (i = 0; options && options[i]; i++)    o = memccpy(array[i] = o, options[i], '\0', len - (end - o));  assert(o == end);  su_home_desctructor(res->res_home, sres_resolver_destructor);  while (res->res_id == 0) {#if HAVE_DEV_URANDOM    int fd;    if ((fd = open("/dev/urandom", O_RDONLY, 0)) != -1) {      read(fd, &res->res_id, (sizeof res->res_id));      close(fd);    }    else#endif    res->res_id = time(NULL);  }  time(&res->res_now);  if (cache)    res->res_cache = sres_cache_ref(cache);  else    res->res_cache = sres_cache_new(0);  res->res_config = config;  if (conf_file_path && conf_file_path != sres_conf_file_path)    res->res_cnffile = su_strdup(res->res_home, conf_file_path);  else    res->res_cnffile = conf_file_path = sres_conf_file_path;  if (!res->res_cache || !res->res_cnffile) {    perror("sres: malloc");  }  else if (sres_qtable_resize(res->res_home, res->res_queries, 0) < 0) {    perror("sres: res_qtable_resize");  }  else if (sres_resolver_update(res, config == NULL) < 0) {    perror("sres: sres_resolver_update");  }  else {    return res;  }  sres_resolver_unref(res);  return NULL;}/** Increase reference count on a resolver object. */sres_resolver_t *sres_resolver_ref(sres_resolver_t *res){  return su_home_ref(res->res_home);}		     /** Decrease the reference count on a resolver object.  */voidsres_resolver_unref(sres_resolver_t *res){  su_home_unref(res->res_home);}/** Set userdata pointer. * * @return New userdata pointer. *  * @ERRORS * @ERROR EFAULT @a res points outside the address space */void *sres_resolver_set_userdata(sres_resolver_t *res, 			   void *userdata){  void *old;  if (!res)    return su_seterrno(EFAULT), (void *)NULL;  old = res->res_userdata, res->res_userdata = userdata;  return old;}/**Get userdata pointer. * * @return Userdata pointer. *  * @ERRORS * @ERROR EFAULT @a res points outside the address space */void *sres_resolver_get_userdata(sres_resolver_t const *res){  if (res == NULL)    return su_seterrno(EFAULT), (void *)NULL;  else    return res->res_userdata;}/** Set async object. * * @return Set async object. *  * @ERRORS * @ERROR EFAULT @a res points outside the address space * @ERROR EALREADY different async callback already set */sres_async_t *sres_resolver_set_async(sres_resolver_t *res,			sres_update_f *callback,			sres_async_t *async, 			int update_all){  if (!res)    return su_seterrno(EFAULT), (void *)NULL;  if (res->res_updcb && res->res_updcb != callback)    return su_seterrno(EALREADY), (void *)NULL;      res->res_async = async;  res->res_updcb = callback;  res->res_update_all = callback && update_all != 0;  return async;}sres_async_t *sres_resolver_get_async(sres_resolver_t const *res,			sres_update_f *callback){  if (res == NULL)    return su_seterrno(EFAULT), (void *)NULL;  else if (callback == NULL)    return res->res_async ? (sres_async_t *)-1 : 0;  else if (res->res_updcb != callback)    return NULL;  else    return res->res_async;}/**Send a DNS query. * * Sends a DNS query with specified @a type and @a domain to the DNS server.  * The sres resolver takes care of retransmitting the query if * sres_resolver_timer() is called in regular intervals. It generates an * error record with nonzero status if no response is received. * * @sa sres_search(), sres_blocking_query(), sres_query_make() * * @ERRORS * @ERROR EFAULT @a res or @a domain point outside the address space * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME * @ERROR ENOMEM memory exhausted */sres_query_t *sres_query(sres_resolver_t *res,	   sres_answer_f *callback,	   sres_context_t *context,	   uint16_t type,	   char const *domain){  sres_query_t *query = NULL;  size_t dlen;    char b[8];  SU_DEBUG_9(("sres_query(%p, %p, %p, %s, \"%s\") called\n",	      res, callback, context, sres_record_type(type, b), domain));  if (res == NULL || domain == NULL)    return su_seterrno(EFAULT), (void *)NULL;  dlen = strlen(domain);  if (dlen > SRES_MAXDNAME ||      (dlen == SRES_MAXDNAME && domain[dlen - 1] != '.')) {    su_seterrno(ENAMETOOLONG);    return NULL;  }  /* Reread resolv.conf if needed */  sres_resolver_update(res, 0);  query = sres_query_alloc(res, callback, context, type, domain);  if (query && sres_send_dns_query(res, query) != 0)    sres_free_query(res, query), query = NULL;  return query;}/**Search DNS. * * Sends DNS queries with specified @a type and @a name to the DNS server.  * If the @a name does not contain enought dots, the search domains are * appended to the name and resulting domain name are also queried. * * The sres resolver takes care of retransmitting the queries if * sres_resolver_timer() is called in regular intervals. It generates an * error record with nonzero status if no response is received. * * @param res pointer to resolver object * @param callback pointer to completion function * @param context argument given to the completion function * @param type record type to search (or sres_qtype_any for any record) * @param name host or domain name to search from DNS * * @ERRORS * @ERROR EFAULT @a res or @a domain point outside the address space * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME * @ERROR ENOMEM memory exhausted * * @sa sres_query(), sres_blocking_search() */sres_query_t *sres_search(sres_resolver_t *res,	    sres_answer_f *callback,	    sres_context_t *context,	    uint16_t type,	    char const *name){  char const *domain = name;  sres_query_t *query = NULL;  size_t dlen;  unsigned dots; char const *dot;  char b[8];  SU_DEBUG_9(("sres_search(%p, %p, %p, %s, \"%s\") called\n",	      res, callback, context, sres_record_type(type, b), domain));  if (res == NULL || domain == NULL)    return su_seterrno(EFAULT), (void *)NULL;  dlen = strlen(domain);  if (dlen > SRES_MAXDNAME ||      (dlen == SRES_MAXDNAME && domain[dlen - 1] != '.')) {    su_seterrno(ENAMETOOLONG);    return NULL;  }  sres_resolver_update(res, 0);  if (sres_has_search_domain(res))    for (dots = 0, dot = strchr(domain, '.');	 dots < res->res_config->c_opt.ndots && dot; 	 dots++, dot = strchr(dot + 1, '.'))      ;  else    dots = 0;  query = sres_query_alloc(res, callback, context, type, domain);  if (query) {    /* Create sub-query for each search domain */    if (dots < res->res_config->c_opt.ndots) {      sres_query_t *sub;      int i, subs, len;      char const **domains = res->res_config->c_search;      char search[SRES_MAXDNAME + 1];      memcpy(search, domain, dlen);      search[dlen++] = '.';      search[dlen] = '\0';      for (i = 0, subs = 0; i <= SRES_MAX_SEARCH; i++) {	if (domains[i]) {	  len = strlen(domains[i]);	  	  if (dlen + len + 1 > SRES_MAXDNAME)	    continue;	  memcpy(search + dlen, domains[i], len);	  search[dlen + len] = '.';	  search[dlen + len + 1] = '\0';	  sub = sres_query_alloc(res, sres_answer_subquery, (void *)query,				 type, search);	  if (sres_send_dns_query(res, sub) == 0) {	    query->q_subqueries[i] = sub;	  }	  else {	    sres_free_query(res, sub), sub = NULL;	  }	  subs += sub != NULL;	}      }      query->q_n_subs = subs;    }    if (sres_send_dns_query(res, query) != 0) {      if (!query->q_n_subs)	sres_free_query(res, query), query = NULL;      else	query->q_id = 0;    }  }  return query;}/** Make a reverse DNS query. * * Send a query to DNS server with specified @a type and domain name formed * from the socket address @a addr. The sres resolver takes care of * retransmitting the query if sres_resolver_timer() is called in regular * intervals. It generates an error record with nonzero status if no * response is received. */sres_query_t *sres_query_sockaddr(sres_resolver_t *res,		    sres_answer_f *callback,		    sres_context_t *context,		    uint16_t type,		    struct sockaddr const *addr){  char name[80];   if (!res || !addr)    return su_seterrno(EFAULT), (void *)NULL;  if (!sres_sockaddr2string(res, name, sizeof(name), addr))    return NULL;  return sres_query(res, callback, context, type, name);}/** Make a DNS query. * * Sends a DNS query with specified @a type and @a domain to the DNS server.  * The sres resolver takes care of retransmitting the query if * sres_resolver_timer() is called in regular intervals. It generates an * error record with nonzero status if no response is received. * * This function just makes sure that we have the @a socket is valid, * otherwise it behaves exactly like sres_query(). */sres_query_t *sres_query_make(sres_resolver_t *res,		sres_answer_f *callback,		sres_context_t *context,		int socket,		uint16_t type,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -