# HG changeset patch # User Mikael Hallendal # Date 1217581309 -7200 # Node ID 2006c0c0a63db8ef18b54de63b91289eb084460f # Parent 5aa76e995f0d6718ca9a5d2795976e3907eeccd3 More work on the asyncns srv lookup. Moved the srv_parse function to LmResolver to be used by both blocking and non-blocking versions. diff -r 5aa76e995f0d -r 2006c0c0a63d loudmouth/.gitignore --- a/loudmouth/.gitignore Thu Jul 31 20:03:42 2008 +0200 +++ b/loudmouth/.gitignore Fri Aug 01 11:01:49 2008 +0200 @@ -1,2 +1,2 @@ lm-marshal.[ch] -test-dns-blocking +test-dns diff -r 5aa76e995f0d -r 2006c0c0a63d loudmouth/lm-asyncns-resolver.c --- a/loudmouth/lm-asyncns-resolver.c Thu Jul 31 20:03:42 2008 +0200 +++ b/loudmouth/lm-asyncns-resolver.c Fri Aug 01 11:01:49 2008 +0200 @@ -24,6 +24,14 @@ #include #define freeaddrinfo(x) asyncns_freeaddrinfo(x) +/* Needed on Mac OS X */ +#if HAVE_ARPA_NAMESER_COMPAT_H +#include +#endif + +#include +#include + #include "lm-error.h" #include "lm-internals.h" #include "lm-marshal.h" @@ -138,7 +146,9 @@ } static gboolean -asyncns_resolver_prep (LmResolver *resolver, GError **error) +asyncns_resolver_prep (LmResolver *resolver, + GIOFunc func, + GError **error) { LmAsyncnsResolverPriv *priv = GET_PRIV (resolver); GMainContext *context; @@ -166,7 +176,7 @@ lm_misc_add_io_watch (context, priv->resolv_channel, G_IO_IN, - (GIOFunc) asyncns_resolver_done, + func, resolver); return TRUE; @@ -186,7 +196,7 @@ req.ai_socktype = SOCK_STREAM; req.ai_protocol = IPPROTO_TCP; - if (!asyncns_resolver_prep (resolver, NULL)) { + if (!asyncns_resolver_prep (resolver, (GIOFunc) asyncns_resolver_done, NULL)) { g_warning ("Signal error\n"); return; } @@ -203,9 +213,90 @@ */ } +static gboolean +asyncns_resolver_srv_done (GSource *source, + GIOCondition condition, + LmResolver *resolver) +{ + LmAsyncnsResolverPriv *priv = GET_PRIV (resolver); + unsigned char *srv_ans; + int srv_len; + gboolean result = FALSE; + + if (!asyncns_isdone (priv->asyncns_ctx, priv->resolv_query)) { + /* Still waiting for the NS lookup to finish */ + return TRUE; + } + + srv_len = asyncns_res_done (priv->asyncns_ctx, + priv->resolv_query, &srv_ans); + + priv->resolv_query = NULL; + + if (srv_len <= 0) { + /* FIXME: Report error */ + g_warning ("Failed to read srv request results"); + } else { + gchar *new_server; + guint new_port; + + result = _lm_resolver_parse_srv_response (srv_ans, srv_len, + &new_server, + &new_port); + if (result == TRUE) { + g_object_set (resolver, + "host", new_server, + "port", new_port, + NULL); + } + + g_free (new_server); + /* TODO: Check whether srv_ans needs freeing */ + } + + asyncns_resolver_cleanup (resolver); + + if (result == TRUE) { + asyncns_resolver_lookup_host (resolver); + } + + return FALSE; +} + static void asyncns_resolver_lookup_service (LmResolver *resolver) { + LmAsyncnsResolverPriv *priv = GET_PRIV (resolver); + gchar *domain; + gchar *service; + gchar *protocol; + gchar *srv; + + g_object_get (resolver, + "domain", &domain, + "service", &service, + "protocol", &protocol, + NULL); + + srv = lm_resolver_create_srv_string (domain, service, protocol); + + if (!asyncns_resolver_prep (resolver, + (GIOFunc) asyncns_resolver_srv_done, + /* Use GError? */ NULL)) { + /* FIXME: Signal error */ + return; + } + + priv->resolv_query = + asyncns_res_query (priv->asyncns_ctx, srv, C_IN, T_SRV); +#if 0 + asyncns_setuserdata (priv->asyncns_ctx, socket->resolv_query, (gpointer) PHASE_1); +#endif + + g_free (srv); + g_free (domain); + g_free (service); + g_free (protocol); } static void diff -r 5aa76e995f0d -r 2006c0c0a63d loudmouth/lm-blocking-resolver.c --- a/loudmouth/lm-blocking-resolver.c Thu Jul 31 20:03:42 2008 +0200 +++ b/loudmouth/lm-blocking-resolver.c Fri Aug 01 11:01:49 2008 +0200 @@ -131,68 +131,6 @@ g_free (host); } -static gboolean -blocking_resolver_parse_srv_response (unsigned char *srv, - int srv_len, - gchar **out_server, - guint *out_port) -{ - int qdcount; - int ancount; - int len; - const unsigned char *pos; - unsigned char *end; - HEADER *head; - char name[256]; - char pref_name[256]; - guint pref_port = 0; - guint pref_prio = 9999; - - pref_name[0] = 0; - - pos = srv + sizeof (HEADER); - end = srv + srv_len; - head = (HEADER *) srv; - - qdcount = ntohs (head->qdcount); - ancount = ntohs (head->ancount); - - /* Ignore the questions */ - while (qdcount-- > 0 && (len = dn_expand (srv, end, pos, name, 255)) >= 0) { - g_assert (len >= 0); - pos += len + QFIXEDSZ; - } - - /* Parse the answers */ - while (ancount-- > 0 && (len = dn_expand (srv, end, pos, name, 255)) >= 0) { - /* Ignore the initial string */ - uint16_t pref, weight, port; - - g_assert (len >= 0); - pos += len; - /* Ignore type, ttl, class and dlen */ - pos += 10; - GETSHORT (pref, pos); - GETSHORT (weight, pos); - GETSHORT (port, pos); - - len = dn_expand (srv, end, pos, name, 255); - if (pref < pref_prio) { - pref_prio = pref; - strcpy (pref_name, name); - pref_port = port; - } - pos += len; - } - - if (pref_name[0]) { - *out_server = g_strdup (pref_name); - *out_port = pref_port; - return TRUE; - } - return FALSE; -} - static void blocking_resolver_lookup_service (LmBlockingResolver *resolver) { @@ -218,8 +156,8 @@ len = res_query (srv, C_IN, T_SRV, srv_ans, SRV_LEN); - result = blocking_resolver_parse_srv_response (srv_ans, len, - &new_server, &new_port); + result = _lm_resolver_parse_srv_response (srv_ans, len, + &new_server, &new_port); if (result == FALSE) { g_print ("Error while parsing srv response in %s\n", G_STRFUNC); diff -r 5aa76e995f0d -r 2006c0c0a63d loudmouth/lm-resolver.c --- a/loudmouth/lm-resolver.c Thu Jul 31 20:03:42 2008 +0200 +++ b/loudmouth/lm-resolver.c Fri Aug 01 11:01:49 2008 +0200 @@ -20,6 +20,16 @@ #include +#include + +/* Needed on Mac OS X */ +#if HAVE_ARPA_NAMESER_COMPAT_H +#include +#endif + +#include +#include + #include "lm-asyncns-resolver.h" #include "lm-blocking-resolver.h" #include "lm-internals.h" @@ -395,3 +405,65 @@ priv->callback (resolver, result, priv->user_data); } +gboolean +_lm_resolver_parse_srv_response (unsigned char *srv, + int srv_len, + gchar **out_server, + guint *out_port) +{ + int qdcount; + int ancount; + int len; + const unsigned char *pos; + unsigned char *end; + HEADER *head; + char name[256]; + char pref_name[256]; + guint pref_port = 0; + guint pref_prio = 9999; + + pref_name[0] = 0; + + pos = srv + sizeof (HEADER); + end = srv + srv_len; + head = (HEADER *) srv; + + qdcount = ntohs (head->qdcount); + ancount = ntohs (head->ancount); + + /* Ignore the questions */ + while (qdcount-- > 0 && (len = dn_expand (srv, end, pos, name, 255)) >= 0) { + g_assert (len >= 0); + pos += len + QFIXEDSZ; + } + + /* Parse the answers */ + while (ancount-- > 0 && (len = dn_expand (srv, end, pos, name, 255)) >= 0) { + /* Ignore the initial string */ + uint16_t pref, weight, port; + + g_assert (len >= 0); + pos += len; + /* Ignore type, ttl, class and dlen */ + pos += 10; + GETSHORT (pref, pos); + GETSHORT (weight, pos); + GETSHORT (port, pos); + + len = dn_expand (srv, end, pos, name, 255); + if (pref < pref_prio) { + pref_prio = pref; + strcpy (pref_name, name); + pref_port = port; + } + pos += len; + } + + if (pref_name[0]) { + *out_server = g_strdup (pref_name); + *out_port = pref_port; + return TRUE; + } + return FALSE; +} + diff -r 5aa76e995f0d -r 2006c0c0a63d loudmouth/lm-resolver.h --- a/loudmouth/lm-resolver.h Thu Jul 31 20:03:42 2008 +0200 +++ b/loudmouth/lm-resolver.h Fri Aug 01 11:01:49 2008 +0200 @@ -84,6 +84,10 @@ void _lm_resolver_set_result (LmResolver *resolver, LmResolverResult result, struct addrinfo *results); +gboolean _lm_resolver_parse_srv_response (unsigned char *srv, + int srv_len, + gchar **out_server, + guint *out_port); G_END_DECLS