Commit 226691ae authored by Pekka Pessi's avatar Pekka Pessi

New API working with test program.

darcs-hash:20060324132308-65a35-838fca9e9a4d520e83a7ce6f0086ec9fd23d76f0.gz
parent 55bedfa8
......@@ -27,7 +27,7 @@ CLEANFILES = resolv.conf error.conf named.conf.tmp \
nobase_include_sofia_HEADERS = sofia-sip/sresolv.h
libsresolv_la_SOURCES = sresolv.c sres_cache.c sres.c
libsresolv_la_SOURCES = sres.c sres_cache.c sres_blocking.c sresolv.c
COVERAGE_INPUT = $(libsresolv_la_SOURCES) $(include_sofia_HEADERS)
......
......@@ -124,6 +124,11 @@ zone "0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.int" in {
file "3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0";
};
zone "0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.arpa" in {
type master;
file "3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa";
};
EOF
PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin"
......
......@@ -41,6 +41,8 @@
*
*/
#include <stdarg.h>
#ifdef __cplusplus
extern "C" { }
#endif
......@@ -99,17 +101,7 @@ typedef SRES_CONTEXT_T sres_context_t;
typedef struct sres_query_s sres_query_t;
/** Prototype for update function.
*
* This kind of function is called when the nameserver configuration has
* been updated. The called function should register the @a new_sockets with
* resolver: it is up to thread to invoke sres_resolver_receive() whenever
* it receives data from one of the new sockets. The @a old_sockets are
* provided for reference.
*/
typedef int sres_update_f(sres_async_t *async,
int new_socket,
int old_socket);
struct sockaddr;
/** Prototype for callback function.
*
......@@ -122,8 +114,17 @@ typedef void sres_answer_f(sres_context_t *context,
sres_record_t **answers);
/** Create an resolver object. */
sres_resolver_t *sres_resolver_new(char const *resolv_conf_path,
sres_cache_t *cache);
sres_resolver_t *sres_resolver_new(char const *resolv_conf_path);
sres_resolver_t *
sres_resolver_new_with_cache(char const *conf_file_path,
sres_cache_t *cache,
char const *options, ...);
sres_resolver_t *
sres_resolver_new_with_cache_va(char const *conf_file_path,
sres_cache_t *cache,
char const *options, va_list va);
sres_resolver_t *sres_resolver_ref(sres_resolver_t *res);
......@@ -135,6 +136,21 @@ 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.
*
* 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,
......@@ -145,8 +161,11 @@ sres_async_t *sres_resolver_set_async(sres_resolver_t *res,
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);
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);
......@@ -155,16 +174,32 @@ int sres_resolver_receive(sres_resolver_t *res, int socket);
int sres_resolver_error(sres_resolver_t *res, int socket);
/** Make a DNS query. */
sres_query_t *sres_query(sres_resolver_t *res,
sres_answer_f *callback,
sres_context_t *context,
uint16_t type,
char const *domain);
/** Make a DNS query. */
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);
/** Make a DNS query with socket. */
sres_query_t *sres_query_make(sres_resolver_t *res,
sres_answer_f *callback,
sres_context_t *context,
int dummy,
uint16_t type,
char const *domain);
/** Make a reverse DNS query. */
/** Make a reverse DNS query with socket. */
sres_query_t *sres_query_make_sockaddr(sres_resolver_t *res,
sres_answer_f *callback,
sres_context_t *context,
int dummy,
uint16_t type,
struct sockaddr const *addr);
......@@ -173,6 +208,18 @@ void sres_query_bind(sres_query_t *q,
sres_answer_f *callback,
sres_context_t *context);
/** Send a query, 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. */
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,
......
......@@ -60,7 +60,7 @@ enum {
#define SRES_CACHE_TIMER_INTERVAL (SRES_CACHE_TIMER_INTERVAL)
};
sres_cache_t *sres_cache_new(size_t n);
sres_cache_t *sres_cache_new(int n);
sres_cache_t *sres_cache_ref(sres_cache_t *);
......
......@@ -40,6 +40,7 @@
#include <sofia-sip/su_tag.h>
#include <sofia-resolv/sres.h>
#include <sofia-resolv/sres_record.h>
SOFIA_BEGIN_DECLS
......@@ -64,20 +65,6 @@ int sres_resolver_destroy(sres_resolver_t *res);
/* Return socket used by root */
int sres_resolver_root_socket(sres_resolver_t *res);
/** Make a DNS query. */
sres_query_t *sres_query(sres_resolver_t *res,
sres_answer_f *callback,
sres_context_t *context,
uint16_t type,
char const *domain);
/** Make a DNS query. */
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);
SOFIA_END_DECLS
#endif
This diff is collapsed.
/*
* 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
*
*/
/**@CFILE sres_sync.c
* @brief Synchronous interface for Sofia DNS Resolver implementation.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*/
#include "config.h"
#if HAVE_STDINT_H
#include <stdint.h>
#elif HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
typedef struct sres_blocking_s sres_blocking_t;
typedef struct sres_blocking_context_s sres_blocking_context_t;
#define SRES_CONTEXT_T struct sres_blocking_context_s
#define SRES_ASYNC_T struct sres_blocking_s
#include "sofia-resolv/sres.h"
#if HAVE_POLL
#include <poll.h>
#elif HAVE_SELECT
#include <sys/select.h>
#endif
#include <stdlib.h>
#include <errno.h>
struct sres_blocking_s
{
int n_sockets;
#if HAVE_POLL
struct pollfd fds[SRES_MAX_NAMESERVERS];
#elif HAVE_SELECT
struct { int fd; } fds[SRES_MAX_NAMESERVERS];
#else
#error No wait mechanism!
#endif
sres_record_t ***return_records;
};
struct sres_blocking_context_s
{
int ready;
sres_resolver_t *resolver;
sres_blocking_t *block;
sres_query_t *query;
sres_record_t ***return_records;
};
static
int sres_blocking_update(sres_blocking_t *b,
int new_socket,
int old_socket)
{
int i, N = b->n_sockets;
if (old_socket == new_socket) {
if (old_socket == -1) {
free(b); /* Destroy us */
}
return 0;
}
if (old_socket != -1) {
for (i = 0; i < N; i++) {
if (b->fds[i].fd == old_socket)
break;
}
if (i == N)
return -1;
N--;
b->fds[i].fd = b->fds[N].fd;
b->fds[i].events = b->fds[N].events;
b->fds[N].fd = -1;
b->fds[N].events = 0;
b->n_sockets = N;
}
if (new_socket != -1) {
if (N == SRES_MAX_NAMESERVERS)
return -1;
b->fds[N].fd = new_socket;
#if HAVE_POLL
b->fds[N].events = POLLIN;
#endif
b->n_sockets = N + 1;
}
return 0;
}
static
int sres_blocking_complete(sres_blocking_context_t *c)
{
while (c->ready > 0) {
int n, i;
#if HAVE_POLL
n = poll(c->block->fds, c->block->n_sockets, 500);
if (n < 0) {
c->ready = n;
}
else if (n == 0) {
sres_resolver_timer(c->resolver, -1);
}
else for (i = 0; i < c->block->n_sockets; i++) {
if (c->block->fds[n].revents | POLLERR)
sres_resolver_error(c->resolver, c->block->fds[n].fd);
if (c->block->fds[n].revents | POLLIN)
sres_resolver_receive(c->resolver, c->block->fds[n].fd);
}
#elif HAVE_SELECT
fd_set readfds[1], errorfds[1];
struct timeval timeval[1];
FD_ZERO(readfds);
FD_ZERO(errorfds);
timeval->tv_sec = 0;
timeval->tv_usec = 500000;
for (i = 0, n = 0; i < c->block->n_sockets; i++) {
FD_SET(c->block->fds[n].fd, readfds);
FD_SET(c->block->fds[n].fd, errorfds);
if (c->block->fds[n].fd >= n)
n = c->block->fds[n].fd + 1;
}
n = select(n, readfds, NULL, writefds, timeval);
XXX;
#endif
}
return c->ready;
}
static
void sres_blocking_callback(sres_blocking_context_t *c,
sres_query_t *query,
sres_record_t **answers)
{
c->ready = 1;
*c->return_records = answers;
}
static
sres_blocking_t *sres_set_blocking(sres_resolver_t *res)
{
sres_blocking_t *b;
int i;
b = sres_resolver_get_async(res, sres_blocking_update);
if (b)
return b;
/* Create a synchronous (blocking) interface towards resolver */
b = calloc(1, sizeof *b);
for (i = 0; i < SRES_MAX_NAMESERVERS; i++)
b->fds[i].fd = -1;
if (!sres_resolver_set_async(res, sres_blocking_update, b, 0)) {
free(b), b = NULL;
}
return b;
}
/** Send a query, return results. */
int sres_blocking_query(sres_resolver_t *res,
uint16_t type,
char const *domain,
sres_record_t ***return_records)
{
sres_blocking_context_t c[1];
sres_record_t **cached;
if (return_records == NULL)
return errno = EFAULT, -1;
c->block = sres_set_blocking(res);
if (c->block == NULL)
return -1;
cached = sres_cached_answers(res, type, domain);
if (cached) {
*return_records = cached;
return 0;
}
c->ready = 0;
c->resolver = res;
c->return_records = return_records;
c->query = sres_query(res, sres_blocking_callback, c, type, domain);
return sres_blocking_complete(c);
}
/** Send a a reverse DNS query, return results. */
int sres_blocking_query_sockaddr(sres_resolver_t *res,
uint16_t type,
struct sockaddr const *addr,
sres_record_t ***return_records)
{
sres_blocking_context_t c[1];
sres_record_t **cached;
if (return_records == NULL)
return errno = EFAULT, -1;
c->block = sres_set_blocking(res);
if (c->block == NULL)
return -1;
cached = sres_cached_answers_sockaddr(res, type, addr);
if (cached) {
*return_records = cached;
return 0;
}
c->ready = 0;
c->resolver = res;
c->return_records = return_records;
c->query = sres_query_sockaddr(res, sres_blocking_callback, c, type, addr);
return sres_blocking_complete(c);
}
......@@ -83,7 +83,7 @@ HTABLE_PROTOS(sres_htable, ht, sres_rr_hash_entry_t);
/* ---------------------------------------------------------------------- */
/* Public functions */
sres_cache_t *sres_cache_new(size_t n)
sres_cache_t *sres_cache_new(int n)
{
sres_cache_t *cache = su_home_new(sizeof *cache);
......@@ -215,7 +215,7 @@ sres_cache_alloc_record(sres_cache_t *cache,
if (sr) {
sr->sr_size = size;
sr->sr_name = memcpy(size + (char *)name, name, name_length + 1);
sr->sr_name = memcpy(size + (char *)sr, name, name_length + 1);
}
return sr;
......
......@@ -37,6 +37,7 @@ struct sres_sofia_s {
sres_resolver_t *srs_resolver;
su_root_t *srs_root;
su_timer_t *srs_timer;
int srs_socket;
sres_sofia_register_t srs_reg[SRES_MAX_NAMESERVERS];
};
......@@ -74,7 +75,7 @@ sres_resolver_create(su_root_t *root,
TAG_END());
ta_end(ta);
res = sres_resolver_new(conf_file_path, NULL);
res = sres_resolver_new_with_cache(conf_file_path, NULL, NULL);
srs = res ? su_zalloc(0, sizeof *srs) : NULL;
if (res && srs) {
......@@ -114,13 +115,8 @@ sres_resolver_destroy(sres_resolver_t *res)
if (srs == NULL)
return su_seterrno(EINVAL);
su_timer_destroy(srs->srs_timer), srs->srs_timer = NULL;
sres_resolver_set_async(res, sres_sofia_update, NULL, 0);
sres_resolver_unref(srs->srs_resolver);
su_free(NULL, srs);
return 0;
}
......@@ -140,8 +136,20 @@ static int sres_sofia_update(sres_sofia_t *srs,
int i, index = -1, error = 0;
int N = SRES_MAX_NAMESERVERS;
if (old_socket == new_socket)
if (old_socket == new_socket) {
if (old_socket == -1) {
/* Destroy srs */
for (i = 0; i < N; i++) {
if (!srs->srs_reg[i].srsr_index)
continue;
su_root_deregister(srs->srs_root, srs->srs_reg[i].srsr_index);
memset(&srs->srs_reg[i], 0, sizeof(srs->srs_reg[i]));
}
su_timer_destroy(srs->srs_timer), srs->srs_timer = NULL;
su_free(NULL, srs);
}
return 0;
}
if (old_socket != -1)
for (i = 0; i < N; i++)
......@@ -184,11 +192,13 @@ static int sres_sofia_update(sres_sofia_t *srs,
}
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 (srsr) {
srs->srs_socket = new_socket;
srsr->srsr_ptr = srs;
srsr->srsr_socket = new_socket;
srsr->srsr_index = index;
......@@ -203,12 +213,51 @@ static int sres_sofia_update(sres_sofia_t *srs,
}
/** Return socket registered to su_root_t object.
*
* @retval sockfd if succesful
* @retval -1 upon an error
*
* @ERRORS
* @ERROR EFAULT Invalid argument passed.
* @ERROR EINVAL Resolver is not using su_root_t.
*/
int sres_resolver_root_socket(sres_resolver_t *res)
{
sres_sofia_t *srs;
int i, N = SRES_MAX_NAMESERVERS;
if (res == NULL)
return su_seterrno(EFAULT);
srs = sres_resolver_get_userdata(res);
if (!srs)
return su_seterrno(EINVAL);
if (srs->srs_socket != -1)
return srs->srs_socket;
for (i = 0; i < N; i++) {
if (!srs->srs_reg[i].srsr_ptr)
break;
}
if (i == N)
return su_seterrno(EINVAL);
srs->srs_socket = srs->srs_reg[i].srsr_socket;
return srs->srs_socket;
}
/** Sofia timer wrapper. */
static
void
sres_sofia_timer(su_root_magic_t *magic, su_timer_t *t, sres_sofia_t *srs)
{
sres_resolver_timer(srs->srs_resolver);
sres_resolver_timer(srs->srs_resolver, -1);
}
......@@ -231,51 +280,3 @@ sres_sofia_poll(su_root_magic_t *magic,
return retval;
}
sres_query_t *
sres_query(sres_resolver_t *res,
sres_answer_f *callback,
sres_context_t *context,
uint16_t type,
char const *domain)
{
sres_sofia_t *srs;
if (res == NULL)
return su_seterrno(EFAULT), (void *)NULL;
srs = sres_resolver_get_async(res, sres_sofia_update);
if (srs)
return sres_query_make(res, callback, context, type, domain);
else
return su_seterrno(EINVAL), (void *)NULL;
}
/** 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_sockaddr(sres_resolver_t *res,
sres_answer_f *callback,
sres_context_t *context,
uint16_t type,
struct sockaddr const *addr)
{
sres_sofia_t *srs;
if (res == NULL)
return su_seterrno(EFAULT), (void *)NULL;
srs = sres_resolver_get_async(res, sres_sofia_update);
if (srs)
return sres_query_make_sockaddr(res, callback, context, type, addr);
else
return su_seterrno(EINVAL), (void *)NULL;
}
This diff is collapsed.
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