# HG changeset patch # User Mikael Hallendal # Date 1172329354 -3600 # Node ID fa0794ef35707fd789a2f10a2867bf56fd2a4cd7 # Parent b0b17385a143eb220cdb762706159d3650428fd5 Implement SRV lookups, patch from Senko Rasic diff -r b0b17385a143 -r fa0794ef3570 loudmouth/lm-socket.c --- a/loudmouth/lm-socket.c Sat Feb 24 16:02:34 2007 +0100 +++ b/loudmouth/lm-socket.c Sat Feb 24 16:02:34 2007 +0100 @@ -1,6 +1,8 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2006 Imendio AB + * Copyright (C) 2006 Nokia Corporation. All rights reserved. + * Copyright (C) 2007 Collabora Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License as @@ -21,6 +23,8 @@ #include #include +#include +#include #include "lm-debug.h" #include "lm-internals.h" @@ -612,6 +616,59 @@ return TRUE; } +static gboolean +_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 = srv + sizeof(HEADER); + unsigned char *end = srv + srv_len; + HEADER *head = (HEADER *)srv; + char name[256]; + char pref_name[256]; + guint pref_port = 0; + guint pref_prio = 9999; + + pref_name[0] = 0; + + 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; +} + LmSocket * lm_socket_create (GMainContext *context, IncomingDataFunc func, @@ -627,7 +684,12 @@ LmSocket *socket; struct addrinfo req; struct addrinfo *ans; + const char *remote_addr; LmConnectData *data; + int err; + char *srv; +#define SRV_LEN 8192 + unsigned char srv_ans[SRV_LEN]; g_return_val_if_fail (server != NULL, NULL); g_return_val_if_fail ((port >= MIN_PORT && port <= MAX_PORT), NULL); @@ -653,53 +715,39 @@ socket->func = func; socket->user_data = user_data; + res_init (); + srv = g_strdup_printf ("_xmpp-client._tcp.%s", socket->server); + err = res_query (srv, C_IN, T_SRV, srv_ans, SRV_LEN); + if (err > 0) { + _parse_srv_response (srv_ans, err, &(socket->server), &(socket->port)); + } + g_free (srv); + if (context) { socket->context = g_main_context_ref (context); } if (proxy) { - int err; - const gchar *proxy_server; - socket->proxy = lm_proxy_ref (proxy); - - proxy_server = lm_proxy_get_server (socket->proxy); + remote_addr = lm_proxy_get_server (socket->proxy); + } else { + remote_addr = socket->server; + } - /* Connect through proxy */ - g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, - "Going to connect to proxy %s\n", proxy_server); - - err = getaddrinfo (proxy_server, NULL, &req, &ans); - if (err != 0) { - const char *str; + g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, + "Going to connect to %s%s:%u\n", (proxy) ? "proxy " : "", + remote_addr, socket->port); - str = _lm_sock_addrinfo_get_error_str (err); - g_set_error (error, - LM_ERROR, - LM_ERROR_CONNECTION_FAILED, - str); - return NULL; - } - } else { - int err; + err = getaddrinfo (remote_addr, NULL, &req, &ans); + if (err != 0) { + const char *str; - /* Connect directly */ - g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, - "Going to connect to %s\n", - socket->server); - - err = getaddrinfo (socket->server, - NULL, &req, &ans); - if (err != 0) { - const char *str; - - str = _lm_sock_addrinfo_get_error_str (err); - g_set_error (error, - LM_ERROR, - LM_ERROR_CONNECTION_FAILED, - str); - return NULL; - } + str = _lm_sock_addrinfo_get_error_str (err); + g_set_error (error, + LM_ERROR, + LM_ERROR_CONNECTION_FAILED, + str); + return NULL; } if (ssl) {