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

📄 sresolv.c

📁 Internet Phone, Chat, Conferencing
💻 C
📖 第 1 页 / 共 5 页
字号:
  return NULL;}		     /** Decrease the reference count on a resolver object.  * */voidsres_resolver_unref(sres_resolver_t *res){  if (LOCK(res)) {    sres_resolver_t res0[1];    if (res->res_refcount > 0)      res->res_refcount--;    if (res->res_refcount == 0) {      *res0 = *res;      su_home_unref(res->res_home);      res = res0;    }    UNLOCK(res);  }}/** Set userdata pointer. * * @return Previously used userdata pointer. *  * @ERRORS * @ERROR EFAULT @a res points outside the address space */void *sres_resolver_set_userdata(sres_resolver_t *res, void *userdata){  if (LOCK(res)) {    void *old;    old = res->res_userdata;    res->res_userdata = userdata;    UNLOCK(res);    return old;  }  return NULL;}/** Set 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;}/** Make a DNS query. * * The function sres_query_make() sends a query with specified @a type and * @a domain. The sres resolver takes care of retransmitting the query, and * generating an error record with nonzero status if no response is * received. */sres_query_t *sres_query_make(sres_resolver_t *res,		sres_answer_f *callback,		sres_context_t *context,		int socket,		uint16_t type,		char const *domain){  sres_query_t *query = NULL;  size_t dlen;  int enough_dots;  SU_DEBUG_9(("sres_query_make() called\n"));  if (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;  }  enough_dots = strchr(domain, '.') != NULL;  if (!LOCK(res))    return NULL;  time(&res->res_now);  query = sres_query_alloc(res, callback, context, socket, type, domain);  if (query) {    /* Create sub-query for each search domain */    if (sres_has_search_domain(res) && !enough_dots) {      sres_query_t *sub;      int i, subs, len;      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 (res->res_search[i]) {	  len = strlen(res->res_search[i]);	  	  if (dlen + len + 1 > SRES_MAXDNAME)	    continue;	  memcpy(search + dlen, res->res_search[i], len);	  search[dlen + len] = '.';	  search[dlen + len + 1] = '\0';	  sub = sres_query_alloc(res, sres_answer_subquery, 				 (sres_context_t *)query, 				 socket, 				 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;    }  }  UNLOCK(res);  return query;}/** Make a reverse DNS query. * * The function sres_query_sockaddr() sends a query with specified @a type * and domain name formed from the socket address @a addr. The sres resolver * takes care of retransmitting the query, and generating an error record * with nonzero status if no response is received. * */sres_query_t *sres_query_make_sockaddr(sres_resolver_t *res,			 sres_answer_f *callback,			 sres_context_t *context,			 int socket,			 uint16_t type,			 struct sockaddr const *addr){  sres_query_t *query;  char name[80];   if (!sres_sockaddr2string(name, sizeof(name), addr))    return NULL;  query = sres_query_make(res, callback, context, socket, type, name);  return query;}void sres_query_bind(sres_query_t *q,                     sres_answer_f *callback,                     sres_context_t *context){  q->q_callback = callback;  q->q_context = context;}/**Get a list of matching (type/domain) records from cache. * *  * * @retval  * pointer to an array of pointers to cached records, or * NULL if no entry was found. * * @ERRORS * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME * @ERROR ENOENT no cached records were found * @ERROR EFAULT @a res or @a domain point outside the address space * @ERROR ENOMEM memory exhausted */sres_record_t **sres_cached_answers(sres_resolver_t *res,		    uint16_t type,		    char const *domain){  sres_record_t **result = NULL, *rr = NULL;  sres_rr_hash_entry_t **rr_iter, **rr_iter2;  int result_size, rr_count = 0;  unsigned hash;  char rooted_domain[SRES_MAXDNAME];  domain = sres_toplevel(rooted_domain, domain);  if (!domain)    return NULL;  SU_DEBUG_9(("%s(res, %02d, \"%s\") called\n", "sres_cached_answers",	      type, domain));  if (!LOCK(res))    return NULL;  time(&res->res_now);  /* Find the domain records from the hash table */  /* First pass: just count the number of rr:s for array allocation */  hash = sres_hash_key(domain);  rr_iter2 = sres_htable_hash(res->res_cache, hash);  for (rr_iter = rr_iter2;        rr_iter && *rr_iter;        rr_iter = sres_htable_next(res->res_cache, rr_iter)) {    rr = (*rr_iter)->rr;    if (rr != NULL &&	res->res_now - (*rr_iter)->rr_received <= rr->sr_ttl &&        (type == sres_qtype_any || rr->sr_type == type) &&        rr->sr_name != NULL &&        strcasecmp(rr->sr_name, domain) == 0)       rr_count++;  }  result_size = (sizeof *result) * (rr_count + 1);  result = rr_count ? su_zalloc(res->res_home, result_size) : NULL;    if (result == NULL) {    UNLOCK(res);    if (rr_count == 0)      su_seterrno(ENOENT);    return NULL;  }  /* Second pass: add the rr pointers to the allocated array */  for (rr_iter = rr_iter2, rr_count = 0;        rr_iter && *rr_iter;        rr_iter = sres_htable_next(res->res_cache, rr_iter)) {    rr = (*rr_iter)->rr;    if (rr != NULL &&	res->res_now - (*rr_iter)->rr_received <= rr->sr_ttl &&        (type == sres_qtype_any || rr->sr_type == type) &&        rr->sr_name != NULL &&        strcasecmp(rr->sr_name, domain) == 0) {      SU_DEBUG_9(("rr found in cache: %s %02d\n", 		  rr->sr_name, rr->sr_type));      result[rr_count++] = rr;      rr->sr_refcount++;    }  }  result[rr_count] = NULL;  SU_DEBUG_9(("sres_cached_answers(res, %02d, %s) returned\n", type, domain));  UNLOCK(res);  return result;}/**Get a list of matching (type/domain) records from cache. * *  * * @retval  * pointer to an array of pointers to cached records, or * NULL if no entry was found. * * @ERRORS * @ERROR EAFNOSUPPORT address family specified in @a addr is not supported * @ERROR ENOENT no cached records were found * @ERROR EFAULT @a res or @a addr point outside the address space * @ERROR ENOMEM memory exhausted */sres_record_t **sres_cached_answers_sockaddr(sres_resolver_t *res,			     uint16_t type,			     struct sockaddr const *addr){  sres_record_t **result;  char name[80];  if (!sres_sockaddr2string(name, sizeof name, addr))    return NULL;  result = sres_cached_answers(res, type, name);  return result;}/** Sort answers. */intsres_sort_answers(sres_resolver_t *res, sres_record_t **answers){  int i, j;  if (res == NULL || answers == NULL)    return su_seterrno(EFAULT);  if (answers[0] == NULL || answers[1] == NULL)    return 0;  /* Simple insertion sorting */  /*   * We do not use qsort because we want later extend this to sort    * local A records first etc.   */  for (i = 1; answers[i]; i++) {    for (j = 0; j < i; j++) {      if (sres_record_compare(answers[i], answers[j]) < 0)	break;    }    if (j < i) {      sres_record_t *r = answers[i];      for (; j < i; i--) {	answers[i] = answers[i - 1];      }      answers[j] = r;    }  }  return 0;}/** Sort and filter query results */intsres_filter_answers(sres_resolver_t *sres, sres_record_t **answers, uint16_t type){		      int i, n;  for (n = 0, i = 0; answers && answers[i]; i++) {     if (answers[i]->sr_record->r_status ||	answers[i]->sr_record->r_class != sres_class_in ||	(type != 0 && answers[i]->sr_record->r_type != type)) {      sres_free_answer(sres, answers[i]);      continue;    }    answers[n++] = answers[i];  }  answers[n] = NULL;  sres_sort_answers(sres, answers);  return n;}/** Free and zero one record. */void sres_free_answer(sres_resolver_t *res, sres_record_t *answer){  if (LOCK(res)) {    _sres_free_answer(res, answer);    UNLOCK(res);  }}void sres_free_answers(sres_resolver_t *res,		  sres_record_t **answers){  if (LOCK(res)) {    _sres_free_answers(res, answers);    UNLOCK(res);  }}/* Private functions */static inlinevoid _sres_free_answer(sres_resolver_t *res, sres_record_t *answer){  if (answer) {    if (answer->sr_refcount <= 1)      su_free(res->res_home, answer);    else       answer->sr_refcount--;  }}static inlinevoid _sres_free_answers(sres_resolver_t *res,		   sres_record_t **answers){  if (answers != NULL) {    int i;    for (i = 0; answers[i] != NULL; i++) {      if (answers[i]->sr_refcount <= 1)	su_free(res->res_home, answers[i]);      else 	answers[i]->sr_refcount--;      answers[i] = NULL;    }    su_free(res->res_home, answers);  }}/* * 3571 is a prime =>  * we hash successive id values to different parts of hash tables */#define Q_PRIME 3571#define SRES_QUERY_HASH(q) ((q)->q_hash)HTABLE_BODIES(sres_qtable, qt, sres_query_t, SRES_QUERY_HASH);/** Allocate a query structure */staticsres_query_t *sres_query_alloc(sres_resolver_t *res,		 sres_answer_f *callback,		 sres_context_t *context,		 int socket,		 uint16_t type,		 char const *domain){  sres_query_t *query;  size_t dlen = strlen(domain);  if (sres_qtable_is_full(res->res_queries))    if (sres_qtable_resize(res->res_home, res->res_queries, 0) < 0)      return NULL;  query = su_alloc(res->res_home, sizeof(*query) + dlen + 1);  if (query) {    memset(query, 0, sizeof *query);    query->q_res = res;    query->q_callback = callback;    query->q_context = context;    query->q_socket = socket;    query->q_type = type;    query->q_class = sres_class_in;    query->q_timestamp = res->res_now;    query->q_i_server = res->res_i_server;    query->q_name = strcpy((char *)(query + 1), domain);    query->q_id = sres_new_id(res); assert(query->q_id);    query->q_hash = query->q_id * Q_PRIME;    sres_qtable_append(res->res_queries, query);  }  return query;}static inlinevoid sres_remove_query(sres_resolver_t *res, sres_query_t *q, int all){  int i;  if (q->q_hash) {    sres_qtable_remove(res->res_queries, q), q->q_hash = 0;    if (all)      for (i = 0; i <= SRES_MAX_SEARCH; i++) {	if (q->q_subqueries[i] && q->q_subqueries[i]->q_hash) {	  sres_qtable_remove(res->res_queries, q->q_subqueries[i]);	  q->q_subqueries[i]->q_hash = 0;	}      }  }}/** Remove a query from hash table and free it. */staticvoid sres_free_query(sres_resolver_t *res, sres_query_t *q){  int i;  if (q == NULL)    return;  if (q->q_hash)    sres_qtable_remove(res->res_queries, q), q->q_hash = 0;  for (i = 0; i <= SRES_MAX_SEARCH; i++) {    sres_query_t *sq;    sq = q->q_subqueries[i];    q->q_subqueries[i] = NULL;    if (sq)      sres_free_query(res, sq);    if (q->q_subanswers[i])      _sres_free_answers(res, q->q_subanswers[i]);    q->q_subanswers[i] = NULL;  }   su_free(res->res_home, q);}/** Compare two records. */int 

⌨️ 快捷键说明

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