Commit d1259899 authored by Pekka Pessi's avatar Pekka Pessi

Fixed problems with updated API. Added sres_resolver_update().

darcs-hash:20060324154145-65a35-f2f34cc64b65ef2e65bb802f81028d89ce00874a.gz
parent 0d583fa4
......@@ -12,7 +12,7 @@ INCLUDES = -I$(srcdir)/../su -I../su
noinst_LTLIBRARIES = libsresolv.la
noinst_PROGRAMS = test_sresolv
noinst_PROGRAMS = test_virgin test_sresolv
TESTS = run_test_sresolv
......@@ -35,6 +35,7 @@ LDADD = libsresolv.la \
../su/libsu.la
test_sresolv_LDFLAGS = -static
test_virgin_LDFLAGS = -static
# ----------------------------------------------------------------------
# Distribution
......
......@@ -103,17 +103,7 @@ typedef struct sres_query_s sres_query_t;
struct sockaddr;
/** Prototype for callback function.
*
* This kind of function is called when a query is completed. The called
* function is responsible for freeing the list of answers and it must
* (eventually) call sres_free_answers().
*/
typedef void sres_answer_f(sres_context_t *context,
sres_query_t *query,
sres_record_t **answers);
/** Create an resolver object. */
/** New resolver object. */
sres_resolver_t *sres_resolver_new(char const *resolv_conf_path);
sres_resolver_t *
......@@ -130,48 +120,24 @@ sres_resolver_t *sres_resolver_ref(sres_resolver_t *res);
void sres_resolver_unref(sres_resolver_t *res);
/** Re-read resolv.conf if needed */
int sres_resolver_update(sres_resolver_t *res, int always);
/** Set userdata pointer. */
void *sres_resolver_set_userdata(sres_resolver_t *res, void *userdata);
/** Get userdata pointer. */
void *sres_resolver_get_userdata(sres_resolver_t const *res);
/** Prototype for update function.
*
* This kind of function is called when the nameserver configuration has
* been updated.
*
* If the old_socket is not -1, it indicates that old_socket will be closed
* and it should be removed from poll() or select() set.
/** Prototype for callback function.
*
* If the new_socket is not -1, it indicates that resolver has created new
* socket that should be added to the poll() or select() set.
* This kind of function is called when a query is completed. The called
* function is responsible for freeing the list of answers and it must
* (eventually) call sres_free_answers().
*/
typedef int sres_update_f(sres_async_t *async,
int new_socket,
int old_socket);
/** Set asynchronous operation data. */
sres_async_t *sres_resolver_set_async(sres_resolver_t *res,
sres_update_f *update,
sres_async_t *async,
int update_all);
/** Get async operation data. */
sres_async_t *sres_resolver_get_async(sres_resolver_t const *res,
sres_update_f *update);
/** Create sockets for resolver. */
int sres_resolver_sockets(sres_resolver_t *res, int *sockets, int n);
/** Resolver timer function. */
void sres_resolver_timer(sres_resolver_t *res, int dummy);
/** Receive DNS response from socket. */
int sres_resolver_receive(sres_resolver_t *res, int socket);
/** Receive error message from socket. */
int sres_resolver_error(sres_resolver_t *res, int socket);
typedef void sres_answer_f(sres_context_t *context,
sres_query_t *query,
sres_record_t **answers);
/** Make a DNS query. */
sres_query_t *sres_query(sres_resolver_t *res,
......@@ -208,27 +174,27 @@ void sres_query_bind(sres_query_t *q,
sres_answer_f *callback,
sres_context_t *context);
/** Send a query, return results. */
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);
/** Send a query, wait for answer, return results. */
int sres_blocking_query(sres_resolver_t *res,
uint16_t type,
char const *domain,
sres_record_t ***return_records);
/** Send a a reverse DNS query, return results. */
/** 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,
sres_record_t ***return_records);
/** Get a list of matching records from cache. */
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);
/** Sort the list of records */
int sres_sort_answers(sres_resolver_t *res, sres_record_t **answers);
......
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef SOFIA_RESOLV_SRES_ASYNC_H
/** Defined when <sofia-resolv/sres_async.h> has been included. */
#define SOFIA_RESOLV_SRES_ASYNC_H
/**
* @file sofia-resolv/sres_async.h
*
* Asynchronous interface for Sofia DNS Resolver.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>,
*
* @par Include Context
* @code
* #include <stdint.h>
* #include <netinet/in.h>
* #include <sofia-resolv/sres.h>
* #include <sofia-resolv/sres_async.h>
* @endcode
*
*/
#ifdef __cplusplus
extern "C" { }
#endif
/** Prototype for update function.
*
* This kind of function is called when the nameserver configuration has
* been updated.
*
* If the old_socket is not -1, it indicates that old_socket will be closed
* and it should be removed from poll() or select() set.
*
* If the new_socket is not -1, it indicates that resolver has created new
* socket that should be added to the poll() or select() set.
*/
typedef int sres_update_f(sres_async_t *async,
int new_socket,
int old_socket);
/** Set asynchronous operation data. */
sres_async_t *sres_resolver_set_async(sres_resolver_t *res,
sres_update_f *update,
sres_async_t *async,
int update_all);
/** Get async operation data. */
sres_async_t *sres_resolver_get_async(sres_resolver_t const *res,
sres_update_f *update);
/** Create sockets for resolver. */
int sres_resolver_sockets(sres_resolver_t *res, int *sockets, int n);
/** Resolver timer function. */
void sres_resolver_timer(sres_resolver_t *res, int dummy);
/** Receive DNS response from socket. */
int sres_resolver_receive(sres_resolver_t *res, int socket);
/** Receive error message from socket. */
int sres_resolver_error(sres_resolver_t *res, int socket);
#ifdef __cplusplus
}
#endif
#endif /* SOFIA_RESOLV_SRES_ASYNC_H */
......@@ -23,7 +23,7 @@
*/
#ifndef SRESOLV_SOFIA_H
/** Defined when <sofia-sip/sresolv_sofia.h> has been included. */
/** Defined when <sofia-sip/sresolv.h> has been included. */
#define SRESOLV_SOFIA_H
/**
......@@ -41,6 +41,7 @@
#include <sofia-resolv/sres.h>
#include <sofia-resolv/sres_record.h>
#include <sofia-resolv/sres_async.h>
SOFIA_BEGIN_DECLS
......@@ -62,7 +63,7 @@ sres_resolver_t *sres_resolver_create(su_root_t *root,
/** Destroy a resolver object. */
int sres_resolver_destroy(sres_resolver_t *res);
/* Return socket used by root */
/* Return socket used by root. @deprecated */
int sres_resolver_root_socket(sres_resolver_t *res);
SOFIA_END_DECLS
......
......@@ -47,6 +47,7 @@
#include "sofia-resolv/sres.h"
#include "sofia-resolv/sres_cache.h"
#include "sofia-resolv/sres_record.h"
#include "sofia-resolv/sres_async.h"
#include <sofia-sip/su_alloc.h>
#include <sofia-sip/su_strlst.h>
......@@ -126,6 +127,7 @@ struct sres_resolver_s {
struct sres_config {
su_home_t c_home[1];
time_t c_update;
time_t c_modified;
char const *c_filename;
......@@ -264,8 +266,6 @@ sres_has_search_domain(sres_resolver_t *res)
static void sres_resolver_destructor(void *);
static int sres_resolver_update(sres_resolver_t *res);
static sres_server_t **sres_servers_new(sres_resolver_t *res,
sres_config_t const *c);
......@@ -519,7 +519,7 @@ sres_resolver_new_with_cache_va(char const *conf_file_path,
else if (sres_qtable_resize(res->res_home, res->res_queries, 0) < 0) {
perror("sres: res_qtable_resize");
}
else if (sres_resolver_update(res) < 0) {
else if (sres_resolver_update(res, 1) < 0) {
perror("sres: res_qtable_resize");
}
else {
......@@ -556,10 +556,14 @@ void *
sres_resolver_set_userdata(sres_resolver_t *res,
void *userdata)
{
void *old;
if (!res)
return su_seterrno(EFAULT), (void *)NULL;
return res->res_userdata = userdata;
old = res->res_userdata, res->res_userdata = userdata;
return old;
}
/**Get userdata pointer.
......@@ -600,7 +604,7 @@ sres_resolver_set_async(sres_resolver_t *res,
res->res_async = async;
res->res_updcb = callback;
res->res_update_all = update_all != 0;
res->res_update_all = callback && update_all != 0;
return async;
}
......@@ -635,7 +639,7 @@ sres_query(sres_resolver_t *res,
size_t dlen;
int enough_dots;
SU_DEBUG_9(("sres_query_make() called\n"));
SU_DEBUG_9(("sres_query() called\n"));
if (res == NULL || domain == NULL)
return su_seterrno(EFAULT), (void *)NULL;
......@@ -649,7 +653,7 @@ sres_query(sres_resolver_t *res,
enough_dots = strchr(domain, '.') != NULL;
time(&res->res_now);
sres_resolver_update(res, 0);
query = sres_query_alloc(res, callback, context, type, domain);
......@@ -719,6 +723,9 @@ sres_query_sockaddr(sres_resolver_t *res,
{
char name[80];
if (!res || !addr)
return su_seterrno(EFAULT), (void *)NULL;
if (!sres_sockaddr2string(res, name, sizeof(name), addr))
return NULL;
......@@ -771,6 +778,9 @@ sres_query_make_sockaddr(sres_resolver_t *res,
{
char name[80];
if (!res || !addr)
return su_seterrno(EFAULT), (void *)NULL;
if (socket == -1)
return errno = EINVAL, NULL;
......@@ -945,6 +955,9 @@ sres_resolver_destructor(void *arg)
res->res_cache = NULL;
sres_servers_unref(res, res->res_servers);
if (res->res_updcb)
res->res_updcb(res->res_async, -1, -1);
}
/*
......@@ -1219,16 +1232,23 @@ static int sres_parse_options(sres_config_t *c, char const *value);
static int sres_parse_nameserver(sres_config_t *c, char const *server);
static time_t sres_config_timestamp(sres_config_t const *c);
static
int sres_resolver_update(sres_resolver_t *res)
/** Update configuration
*
*/
int sres_resolver_update(sres_resolver_t *res, int always)
{
sres_config_t *previous, *c = NULL;
sres_server_t **servers, **old_servers;
previous = res->res_config;
if (previous && previous->c_modified == sres_config_timestamp(previous))
time(&res->res_now);
if (!always && previous &&
(res->res_now < previous->c_update ||
sres_config_timestamp(previous) == previous->c_modified)) {
return 0;
}
c = sres_parse_resolv_conf(res);
if (!c)
......@@ -1246,6 +1266,8 @@ int sres_resolver_update(sres_resolver_t *res)
res->res_i_server = 0;
res->res_n_servers = sres_servers_count(servers);
res->res_servers = servers;
c->c_update = res->res_now + 5; /* Do not try to read for 5 sec? */
sres_servers_unref(res, old_servers);
su_home_unref(previous->c_home);
......@@ -1363,9 +1385,6 @@ int sres_parse_config(sres_config_t *c, FILE *f)
c->c_modified = st.st_mtime;
}
if (c->c_modified == 0)
time(&c->c_modified);
if (localdomain)
c->c_search[0] = localdomain;
else if (domain)
......@@ -1555,13 +1574,13 @@ void sres_servers_unref(sres_resolver_t *res,
if (!servers[i])
break;
if (servers[i]->dns_socket) {
if (servers[i]->dns_socket != -1) {
if (res->res_updcb)
res->res_updcb(res->res_async, -1, servers[i]->dns_socket);
su_close(servers[i]->dns_socket);
}
}
su_free(res->res_home, servers);
}
......@@ -1851,6 +1870,8 @@ void sres_resolver_timer(sres_resolver_t *res, int dummy)
now = time(&res->res_now);
SU_DEBUG_9(("sres_resolver_timer() called at %lu\n", (long) now));
if (res->res_queries->qt_used) {
/** Every time it is called it goes through all query structures, and
* retransmits all the query messages, which have not been answered yet.
......@@ -1970,7 +1991,6 @@ sres_canonize_sockaddr(struct sockaddr_storage *from, socklen_t *fromlen)
}
}
#if HAVE_IP_RECVERR || HAVE_IPV6_RECVERR
#include <linux/types.h>
#include <linux/errqueue.h>
......
......@@ -46,6 +46,7 @@ typedef struct sres_blocking_context_s sres_blocking_context_t;
#define SRES_ASYNC_T struct sres_blocking_s
#include "sofia-resolv/sres.h"
#include "sofia-resolv/sres_async.h"
#if HAVE_POLL
#include <poll.h>
......
......@@ -28,9 +28,9 @@ typedef struct sres_sofia_s sres_sofia_t;
typedef struct sres_sofia_register_s sres_sofia_register_t;
struct sres_sofia_register_s {
sres_sofia_t *srsr_ptr;
int srsr_socket;
int srsr_index; /**< Registration index */
sres_sofia_t *reg_ptr;
int reg_socket;
int reg_index; /**< Registration index */
};
struct sres_sofia_s {
......@@ -83,6 +83,7 @@ sres_resolver_create(su_root_t *root,
srs->srs_resolver = res;
srs->srs_root = root;
srs->srs_socket = -1;
sres_resolver_set_async(res, sres_sofia_update, srs, 0);
......@@ -131,18 +132,24 @@ static int sres_sofia_update(sres_sofia_t *srs,
{
char const *what = NULL;
su_wait_t wait[1];
sres_sofia_register_t *srsr = NULL;
sres_sofia_register_t *old_srsr = NULL;
sres_sofia_register_t *reg = NULL;
sres_sofia_register_t *old_reg = NULL;
int i, index = -1, error = 0;
int N = SRES_MAX_NAMESERVERS;
SU_DEBUG_9(("sres_sofia_update(%p, %d, %d)\n", srs, new_socket, old_socket));
if (srs == NULL)
return 0;
if (old_socket == new_socket) {
if (old_socket == -1) {
sres_resolver_set_async(srs->srs_resolver, sres_sofia_update, NULL, 0);
/* Destroy srs */
for (i = 0; i < N; i++) {
if (!srs->srs_reg[i].srsr_index)
if (!srs->srs_reg[i].reg_index)
continue;
su_root_deregister(srs->srs_root, srs->srs_reg[i].srsr_index);
su_root_deregister(srs->srs_root, srs->srs_reg[i].reg_index);
memset(&srs->srs_reg[i], 0, sizeof(srs->srs_reg[i]));
}
su_timer_destroy(srs->srs_timer), srs->srs_timer = NULL;
......@@ -153,55 +160,57 @@ static int sres_sofia_update(sres_sofia_t *srs,
if (old_socket != -1)
for (i = 0; i < N; i++)
if ((srs->srs_reg + i)->srsr_socket == old_socket) {
old_srsr = srs->srs_reg + i;
if ((srs->srs_reg + i)->reg_socket == old_socket) {
old_reg = srs->srs_reg + i;
break;
}
if (new_socket != -1) {
if (old_srsr == NULL) {
if (old_reg == NULL) {
for (i = 0; i < N; i++) {
if (!(srs->srs_reg + i)->srsr_ptr)
if (!(srs->srs_reg + i)->reg_ptr)
break;
}
if (i > N)
return su_seterrno(ENOMEM);
srsr = srs->srs_reg + i;
reg = srs->srs_reg + i;
}
else
srsr = old_srsr;
reg = old_reg;
}
if (srsr) {
if (reg) {
if (su_wait_create(wait, new_socket, SU_WAIT_IN | SU_WAIT_ERR) == -1) {
srsr = NULL;
reg = NULL;
what = "su_wait_create";
error = su_errno();
}
if (srsr)
index = su_root_register(srs->srs_root, wait, sres_sofia_poll, srsr, 0);
if (reg)
index = su_root_register(srs->srs_root, wait, sres_sofia_poll, reg, 0);
if (index < 0) {
srsr = NULL;
reg = NULL;
what = "su_root_register";
error = su_errno();
su_wait_destroy(wait);
}
}
if (old_srsr) {
srsr->srsr_socket = -1;
su_root_deregister(srs->srs_root, old_srsr->srsr_index);
memset(old_srsr, 0, sizeof *old_srsr);
if (old_reg) {
if (old_socket == srs->srs_socket)
srs->srs_socket = -1;
su_root_deregister(srs->srs_root, old_reg->reg_index);
memset(old_reg, 0, sizeof *old_reg);
}
if (srsr) {
if (reg) {
srs->srs_socket = new_socket;
srsr->srsr_ptr = srs;
srsr->srsr_socket = new_socket;
srsr->srsr_index = index;
reg->reg_ptr = srs;
reg->reg_socket = new_socket;
reg->reg_index = index;
}
if (!what)
......@@ -213,7 +222,7 @@ static int sres_sofia_update(sres_sofia_t *srs,
}
/** Return socket registered to su_root_t object.
/** Return a socket registered to su_root_t object.
*
* @retval sockfd if succesful
* @retval -1 upon an error
......@@ -230,23 +239,30 @@ int sres_resolver_root_socket(sres_resolver_t *res)
if (res == NULL)
return su_seterrno(EFAULT);
srs = sres_resolver_get_userdata(res);
srs = sres_resolver_get_async(res, sres_sofia_update);
if (!srs)
return su_seterrno(EINVAL);
if (sres_resolver_set_async(res, sres_sofia_update, srs, 1) < 0)
return -1;
if (srs->srs_socket != -1)
return srs->srs_socket;
for (i = 0; i < N; i++) {
if (!srs->srs_reg[i].srsr_ptr)
if (!srs->srs_reg[i].reg_ptr)
break;
}
if (i == N)
return su_seterrno(EINVAL);
srs->srs_socket = srs->srs_reg[i].srsr_socket;
if (i < N) {
srs->srs_socket = srs->srs_reg[i].reg_socket;
}
else {
int socket;
if (sres_resolver_sockets(res, &socket, 1) < 0)
return -1;
}
return srs->srs_socket;
}
......@@ -266,11 +282,11 @@ static
int
sres_sofia_poll(su_root_magic_t *magic,
su_wait_t *w,
sres_sofia_register_t *srsr)
sres_sofia_register_t *reg)
{
sres_sofia_t *srs = srsr->srsr_ptr;
sres_sofia_t *srs = reg->reg_ptr;
int retval = 0;
int socket = srsr->srsr_socket;
int socket = reg->reg_socket;
int events = su_wait_events(w, socket);
if (events & SU_WAIT_ERR)
......
......@@ -1667,9 +1667,9 @@ int test_api_errors(sres_context_t *noctx)
TEST(sres_resolver_get_userdata(NULL), NULL);
TEST(sres_resolver_get_userdata(res), NULL);
TEST(sres_resolver_set_userdata(res, sa), sa);
TEST(sres_resolver_set_userdata(res, sa), NULL);
TEST(sres_resolver_get_userdata(res), sa);
TEST(sres_resolver_set_userdata(res, NULL), NULL);
TEST(sres_resolver_set_userdata(res, NULL), sa);
TEST(sres_resolver_get_userdata(res), NULL);
errno = 0;
......
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