📄 sresolv.c
字号:
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 + -