Commit edca0c58 authored by Pekka Pessi's avatar Pekka Pessi

Updated sresolv API.

Added sres_search() and sres_search_cached_answers() to the sresolv API.
Added sres_blocking_search(). Added ignore_cache parameter to
sres_blocking_query() and sres_blocking_query_sockaddr() prototypes.
Renumbered SRES_TIMEOUT_ERR and SRES_RECORD_ERR so that they do not overlap
with transaction signature errors.
Added sres_record_type().

darcs-hash:20060502112706-65a35-6590bbde8d56325650345a620f893b9e6ef3feff.gz
parent c15894a6
......@@ -154,6 +154,13 @@ sres_query_t *sres_query(sres_resolver_t *res,
uint16_t type,
char const *domain);
/**Search DNS. */
sres_query_t *sres_search(sres_resolver_t *res,
sres_answer_f *callback,
sres_context_t *context,
uint16_t type,
char const *name);
/** Make a reverse DNS query. */
sres_query_t *sres_query_sockaddr(sres_resolver_t *res,
sres_answer_f *callback,
......@@ -187,6 +194,11 @@ sres_record_t **sres_cached_answers(sres_resolver_t *res,
uint16_t type,
char const *domain);
/**Search for a list of matching (type/name) records from cache. */
sres_record_t **sres_search_cached_answers(sres_resolver_t *res,
uint16_t type,
char const *name);
/**Get a list of matching (type/domain) records from cache. */
sres_record_t **sres_cached_answers_sockaddr(sres_resolver_t *res,
uint16_t type,
......@@ -196,15 +208,24 @@ sres_record_t **sres_cached_answers_sockaddr(sres_resolver_t *res,
int sres_blocking_query(sres_resolver_t *res,
uint16_t type,
char const *domain,
int ignore_cache,
sres_record_t ***return_records);
/** Search DNS, return results. */
int sres_blocking_search(sres_resolver_t *res,
uint16_t type,
char const *name,
int ignore_cache,
sres_record_t ***return_records);
/** Send a a reverse DNS query, wait for answer, return results. */
int sres_blocking_query_sockaddr(sres_resolver_t *res,
uint16_t type,
struct sockaddr const *addr,
int ignore_cache,
sres_record_t ***return_records);
/** Return true (and set it in blocking mode) if resolver can block. */
/** Return true (and set resolver in blocking mode) if resolver can block. */
int sres_is_blocking(sres_resolver_t *res);
/** Sort the list of records */
......
......@@ -66,9 +66,10 @@ enum {
SRES_NAME_ERR = 3, /**< No domain name. */
SRES_UNIMPL_ERR = 4, /**< Not implemented. */
SRES_AUTH_ERR = 5, /**< Refused */
/* Errors generated by sresolv */
SRES_TIMEOUT_ERR = 16, /**< Timeout occurred */
SRES_RECORD_ERR = 17 /**< Name has no given record type */
SRES_TIMEOUT_ERR = 32, /**< Timeout occurred */
SRES_RECORD_ERR = 33 /**< Name has no given record type */
};
/** Start of a zone of authority record (@RFC1035). */
......@@ -223,13 +224,13 @@ enum {
sres_type_nimloc = 32, /**< Nimrod Locator. */
sres_type_srv = 33, /**< Server Selection. */
sres_type_atma = 34, /**< ATM Address */
sres_type_naptr = 35, /**< Naming Authority PoinTeR (RFC 2915) */
sres_type_naptr = 35, /**< Naming Authority PoinTeR (@RFC2915) */
sres_type_kx = 36, /**< Key Exchange */
sres_type_cert = 37, /**< Certification record */
sres_type_a6 = 38, /**< IPv6 address (deprecates AAAA) */
sres_type_dname = 39, /**< Non-terminal DNAME (for IPv6) */
sres_type_sink = 40, /**< Kitchen sink (experimental) */
sres_type_opt = 41, /**< EDNS 0 option (RFC 2671) */
sres_type_opt = 41, /**< EDNS 0 option (@RFC2671) */
sres_qtype_tsig = 250, /**< Transaction signature. */
sres_qtype_ixfr = 251, /**< Incremental zone transfer. */
......@@ -239,6 +240,9 @@ enum {
sres_qtype_any = 255 /**< Wildcard match. */
};
/** Convert type to its name. */
char const *sres_record_type(int type, char buffer[8]);
/** Compare two records. */
int sres_record_compare(sres_record_t const *, sres_record_t const *);
......
This diff is collapsed.
......@@ -233,7 +233,7 @@ sres_blocking_t *sres_set_blocking(sres_resolver_t *res)
return b;
}
/** Return true (and set it in blocking mode) if resolver can block. */
/** Return true (and set resolver in blocking mode) if resolver can block. */
int sres_is_blocking(sres_resolver_t *res)
{
if (res == NULL)
......@@ -241,15 +241,34 @@ int sres_is_blocking(sres_resolver_t *res)
return sres_set_blocking(res) != NULL;
}
/** Send a DNS query, return results.
/**Send a DNS query, wait for response, return results.
*
* Sends a DNS query with specified @a type and @a domain to the DNS server,
* if @a ignore_cache is not given or no records are found from cache.
* Function returns an error record with nonzero status if no response is
* received from DNS server.
*
* @param res pointer to resolver object
* @param type record type to search (or sres_qtype_any for any record)
* @param domain domain name to query
* @param ignore_cache ignore cached answers if nonzero
* @param return_records return-value parameter for dns records
*
* @retval >0 if query was responded
* @retval 0 if result was found from cache
* @retval -1 upon error
*
* @sa sres_query(), sres_blocking_search()
*
* @note A blocking query converts a resolver object permanently into
* blocking mode. If you need to make blocking and non-blocking queries, use
* sres_resolver_copy() to make a separate resolver object for blocking
* queries.
*/
int sres_blocking_query(sres_resolver_t *res,
uint16_t type,
char const *domain,
int ignore_cache,
sres_record_t ***return_records)
{
sres_blocking_context_t c[1];
......@@ -258,14 +277,18 @@ int sres_blocking_query(sres_resolver_t *res,
if (return_records == NULL)
return errno = EFAULT, -1;
*return_records = NULL;
c->block = sres_set_blocking(res);
if (c->block == NULL)
return -1;
return -1; /* Resolver in asynchronous mode */
cached = sres_cached_answers(res, type, domain);
if (cached) {
*return_records = cached;
return 0;
if (!ignore_cache) {
cached = sres_cached_answers(res, type, domain);
if (cached) {
*return_records = cached;
return 0;
}
}
c->ready = 0;
......@@ -276,15 +299,85 @@ int sres_blocking_query(sres_resolver_t *res,
return sres_blocking_complete(c);
}
/** Search DNS, return results.
*
* Search for @a name with specified @a type and @a name from 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.
*
* @param res pointer to resolver object
* @param type record type to search (or sres_qtype_any for any record)
* @param name host or domain name to search from DNS
* @param ignore_cache ignore cached answers if nonzero
* @param return_records return-value parameter for dns records
*
* @retval >0 if query was responded
* @retval 0 if result was found from cache
* @retval -1 upon error
*
* @sa sres_blocking_query(), sres_search()
*
* @note A blocking query converts a resolver object permanently into
* blocking mode. If you need to make blocking and non-blocking queries, use
* sres_resolver_copy() to make a separate resolver object for blocking
* queries.
*/
int sres_blocking_search(sres_resolver_t *res,
uint16_t type,
char const *name,
int ignore_cache,
sres_record_t ***return_records)
{
sres_blocking_context_t c[1];
sres_record_t **cached;
if (return_records == NULL)
return errno = EFAULT, -1;
*return_records = NULL;
c->block = sres_set_blocking(res);
if (c->block == NULL)
return -1; /* Resolver in asynchronous mode */
if (!ignore_cache) {
cached = sres_search_cached_answers(res, type, name);
if (cached) {
*return_records = cached;
return 0;
}
}
c->ready = 0;
c->resolver = res;
c->return_records = return_records;
c->query = sres_search(res, sres_blocking_callback, c, type, name);
return sres_blocking_complete(c);
}
/** Send a a reverse DNS query, return results.
*
* Sends a reverse DNS query with specified @a type and @a domain to the DNS
* server if @a ignore_cache is not given or no cached records are found from
* the cache. Function returns an error record with nonzero status if no
* response is received from DNS server.
*
* @retval >0 if query was responded
* @retval 0 if result was found from cache
* @retval -1 upon error
*
* @sa sres_blocking_query(), sres_query_sockaddr()
*
* @note A blocking query converts a resolver object permanently into
* blocking mode. If you need to make blocking and non-blocking queries, use
* sres_resolver_copy() to make a separate resolver object for blocking
* queries.
*/
int sres_blocking_query_sockaddr(sres_resolver_t *res,
uint16_t type,
struct sockaddr const *addr,
int ignore_cache,
sres_record_t ***return_records)
{
sres_blocking_context_t c[1];
......@@ -292,15 +385,19 @@ int sres_blocking_query_sockaddr(sres_resolver_t *res,
if (return_records == NULL)
return errno = EFAULT, -1;
*return_records = NULL;
c->block = sres_set_blocking(res);
if (c->block == NULL)
return -1;
return -1; /* Resolver in asynchronous mode */
cached = sres_cached_answers_sockaddr(res, type, addr);
if (cached) {
*return_records = cached;
return 0;
if (!ignore_cache) {
cached = sres_cached_answers_sockaddr(res, type, addr);
if (cached) {
*return_records = cached;
return 0;
}
}
c->ready = 0;
......
......@@ -170,14 +170,15 @@ int sres_cache_get(sres_cache_t *cache,
int result_size, rr_count = 0;
unsigned hash;
time_t now;
char b[8];
if (!domain || !return_cached)
return -1;
*return_cached = NULL;
SU_DEBUG_9(("%s(res, %02d, \"%s\") called\n", "sres_cached_answers",
type, domain));
SU_DEBUG_9(("%s(%p, %s, \"%s\") called\n", "sres_cache_get",
cache, sres_record_type(type, b), domain));
hash = sres_hash_key(domain);
......@@ -239,7 +240,8 @@ int sres_cache_get(sres_cache_t *cache,
UNLOCK(cache);
SU_DEBUG_9(("sres_cached_answers(res, %02d, %s) returned\n", type, domain));
SU_DEBUG_9(("%s(%p, %s, \"%s\") returned %d entries\n", "sres_cache_get",
cache, sres_record_type(type, b), domain, rr_count));
*return_cached = result;
......
......@@ -549,7 +549,7 @@ int test_a(sres_context_t *ctx)
sres_free_answers(res, result);
/* Try sub-queries */
TEST_1(sres_query(res, test_answer, ctx, sres_type_a, "sip00"));
TEST_1(sres_search(res, test_answer, ctx, sres_type_a, "sip00"));
TEST_RUN(ctx);
......@@ -597,6 +597,20 @@ int test_a(sres_context_t *ctx)
/* Error gets TTL from example.com SOA record minimum time */
TEST(rr_a->a_record->r_ttl, 60);
/* Cached search */
TEST_1(result = sres_search_cached_answers(res, sres_type_a, "sip00"));
TEST_1(rr_a = result[0]->sr_a);
TEST(rr_a->a_record->r_status, 0);
TEST_S(rr_a->a_record->r_name, "sip00.example.com.");
TEST(rr_a->a_record->r_type, sres_type_a);
TEST(rr_a->a_record->r_class, sres_class_in);
TEST(rr_a->a_record->r_ttl, 60);
TEST_S(inet_ntoa(rr_a->a_addr), "194.2.188.133");
if (result[1]) {
TEST(result[1]->sr_a->a_record->r_type, sres_type_a);
}
END();
}
......@@ -842,9 +856,9 @@ int test_cname(sres_context_t *ctx)
TEST_1(result = ctx->result);
TEST_1(rr = result[0]->sr_cname);
TEST(rr->cname_record->r_class, sres_class_in);
TEST(rr->cname_record->r_type, sres_type_cname);
TEST(rr->cname_record->r_ttl, 60);
TEST(rr->cn_record->r_class, sres_class_in);
TEST(rr->cn_record->r_type, sres_type_cname);
TEST(rr->cn_record->r_ttl, 60);
TEST_S(rr->cn_cname, "sip00.example.com.");
sres_free_answers(res, ctx->result), ctx->result = NULL;
......@@ -1197,9 +1211,9 @@ int test_cache(sres_context_t *ctx)
TEST_1(result[0] != NULL);
rr_cname = result[0]->sr_cname;
TEST(rr_cname->cname_record->r_type, sres_type_cname);
TEST(rr_cname->cname_record->r_class, sres_class_in);
TEST(rr_cname->cname_record->r_ttl, 60);
TEST(rr_cname->cn_record->r_type, sres_type_cname);
TEST(rr_cname->cn_record->r_class, sres_class_in);
TEST(rr_cname->cn_record->r_ttl, 60);
TEST_S(rr_cname->cn_cname, "sip00.example.com.");
sres_free_answers(res, result);
......
......@@ -156,6 +156,7 @@ Command line utilities for Sofia SIP UA library.
%{_prefix}/bin/addrinfo
%{_prefix}/bin/sip-options
%{_prefix}/bin/sip-date
%{_prefix}/bin/sip-dig
%{_mandir}/man?/*
%changelog
......
......@@ -195,9 +195,11 @@ void print_result(char const *addr, char const *port, char const *tport,
double weight,
unsigned preference);
int prepare_transport(struct transport tports[N_TPORT], char const *tport);
int prepare_transport(struct dig *dig, char const *tport);
int count_transports(struct transport const *, char const *tp1, char const *tp2);
int count_transports(struct dig *dig,
char const *tp1,
char const *tp2);
void usage(int exitcode)
{
......@@ -240,20 +242,20 @@ int main(int argc, char *argv[])
if (proto == NULL)
usage(1);
prepare_transport(dig->tports, proto);
prepare_transport(dig, proto);
}
else if (strcmp(argv[1], "--udp") == 0)
prepare_transport(dig->tports, "udp");
prepare_transport(dig, "udp");
else if (strcmp(argv[1], "--tcp") == 0)
prepare_transport(dig->tports, "tcp");
prepare_transport(dig, "tcp");
else if (strcmp(argv[1], "--tls") == 0)
prepare_transport(dig->tports, "tls");
prepare_transport(dig, "tls");
else if (strcmp(argv[1], "--sctp") == 0)
prepare_transport(dig->tports, "sctp");
prepare_transport(dig, "sctp");
else if (strcmp(argv[1], "--tls-sctp") == 0)
prepare_transport(dig->tports, "tls-sctp");
prepare_transport(dig, "tls-sctp");
else if (strcmp(argv[1], "--tls-udp") == 0)
prepare_transport(dig->tports, "tls-udp");
prepare_transport(dig, "tls-udp");
else if (strcmp(argv[1], "--no-sctp") == 0)
o_sctp = 0, o_tls_sctp = 0;
else if (strcmp(argv[1], "--help") == 0)
......@@ -280,14 +282,14 @@ int main(int argc, char *argv[])
multiple = argv[1] && argv[2];
if (!count_transports(dig->tports, NULL, NULL)) {
prepare_transport(dig->tports, "udp");
prepare_transport(dig->tports, "tcp");
if (!count_transports(dig, NULL, NULL)) {
prepare_transport(dig, "udp");
prepare_transport(dig, "tcp");
if (o_sctp)
prepare_transport(dig->tports, "sctp");
prepare_transport(dig->tports, "tls");
prepare_transport(dig, "sctp");
prepare_transport(dig, "tls");
if (o_tls_sctp)
prepare_transport(dig->tports, "tls-sctp");
prepare_transport(dig, "tls-sctp");
}
dig->sres = sres_resolver_new(getenv("SRESOLV_CONF"));
......@@ -364,8 +366,9 @@ int transport_is_secure(char const *tportname)
return tportname && strncasecmp(tportname, "tls", 3) == 0;
}
int prepare_transport(struct transport tports[N_TPORT], char const *tport)
int prepare_transport(struct dig *dig, char const *tport)
{
struct transport *tports = dig->tports;
int j;
for (j = 0; j < N_TPORT - 1; j++) {
......@@ -415,13 +418,17 @@ int prepare_transport(struct transport tports[N_TPORT], char const *tport)
}
int
count_transports(struct transport const *tports,
count_transports(struct dig *dig,
char const *tport,
char const *tport2)
{
int i, tcount = 0;
struct transport const *tports = dig->tports;
for (i = 0; tports[i].name; i++) {
if (dig->sips && !transport_is_secure(tports[i].name))
continue;
if (!tport || strcasecmp(tport, tports[i].name) == 0)
tcount++;
if (tport2 && strcasecmp(tport2, tports[i].name) == 0)
......@@ -453,7 +460,7 @@ int dig_naptr(struct dig *dig,
int i, error;
int order = 0, count = 0, nacount = 0, scount = 0;
error = sres_blocking_query(dig->sres, sres_type_naptr, host, &answers);
error = sres_blocking_query(dig->sres, sres_type_naptr, host, 0, &answers);
if (error < 0)
return 0;
......@@ -538,7 +545,7 @@ int dig_all_srvs(struct dig *dig,
char const *proto; sres_record_t **answers;
} srvs[N_TPORT + 1] = {{ NULL }};
tcount = count_transports(dig->tports, tport, NULL);
tcount = count_transports(dig, tport, NULL);
if (!tcount)
return 0;
......@@ -546,10 +553,13 @@ int dig_all_srvs(struct dig *dig,
if (tport && strcasecmp(dig->tports[i].name, tport))
continue;
if (dig->sips && !transport_is_secure(dig->tports[i].name))
continue;
domain = su_strcat(NULL, dig->tports[i].srv, host);
if (domain) {
if (sres_blocking_query(dig->sres, sres_type_srv, domain,
if (sres_blocking_query(dig->sres, sres_type_srv, domain, 0,
&srvs[n].answers) >= 0) {
srvs[n++].proto = dig->tports[i].name;
}
......@@ -608,7 +618,7 @@ int dig_srv(struct dig *dig,
assert(tport && domain);
error = sres_blocking_query(dig->sres, sres_type_srv, domain, &answers);
error = sres_blocking_query(dig->sres, sres_type_srv, domain, 0, &answers);
if (error < 0)
return 0;
......@@ -707,12 +717,12 @@ int dig_addr(struct dig *dig,
tport = "udp", tport2 = "tcp";
}
tcount = count_transports(dig->tports, tport, tport2);
tcount = count_transports(dig, tport, tport2);
if (!tcount)
return 0;
if (type1) {
error = sres_blocking_query(dig->sres, type1, host, &answers1);
error = sres_blocking_query(dig->sres, type1, host, 0, &answers1);
if (error >= 0)
for (i = 0; answers1[i]; i++) {
sres_common_t *r = answers1[i]->sr_record;
......@@ -721,7 +731,7 @@ int dig_addr(struct dig *dig,
}
if (type2) {
error = sres_blocking_query(dig->sres, type2, host, &answers2);
error = sres_blocking_query(dig->sres, type2, host, 0, &answers2);
if (error >= 0)
for (i = 0; answers2[i]; i++) {
sres_common_t *r = answers2[i]->sr_record;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment