aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@google.com>2010-08-10 12:18:09 +0100
committerWilmer van der Gaast <wilmer@google.com>2010-08-10 12:18:09 +0100
commitffdf2e71d9e67980727aa994b77fca36ef5246c6 (patch)
tree59277a71581915c3203f879b4bf8276fdb001dbf
parentf32c14c649e854fbfb7b8e495e2ebc8459ee5b6f (diff)
When doing SRV lookups, return an array with all RRs instead of just the
first one. The first isn't always the best one and this is currently causing GTalk issues when talk2.l.google.com (which is currently dead) is first.
-rw-r--r--lib/misc.c80
-rw-r--r--lib/misc.h3
-rw-r--r--protocols/jabber/jabber.c18
3 files changed, 66 insertions, 35 deletions
diff --git a/lib/misc.c b/lib/misc.c
index fda19c19..b696b8c4 100644
--- a/lib/misc.c
+++ b/lib/misc.c
@@ -507,16 +507,17 @@ int bool2int( char *value )
return 0;
}
-struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain )
+struct ns_srv_reply **srv_lookup( char *service, char *protocol, char *domain )
{
- struct ns_srv_reply *reply = NULL;
+ struct ns_srv_reply **replies = NULL;
#ifdef HAVE_RESOLV_A
+ struct ns_srv_reply *reply = NULL;
char name[1024];
unsigned char querybuf[1024];
const unsigned char *buf;
ns_msg nsh;
ns_rr rr;
- int i, len, size;
+ int i, n, len, size;
g_snprintf( name, sizeof( name ), "_%s._%s.%s", service, protocol, domain );
@@ -526,37 +527,56 @@ struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain )
if( ns_initparse( querybuf, size, &nsh ) != 0 )
return NULL;
- if( ns_parserr( &nsh, ns_s_an, 0, &rr ) != 0 )
- return NULL;
-
- size = ns_rr_rdlen( rr );
- buf = ns_rr_rdata( rr );
-
- len = 0;
- for( i = 6; i < size && buf[i]; i += buf[i] + 1 )
- len += buf[i] + 1;
-
- if( i > size )
- return NULL;
-
- reply = g_malloc( sizeof( struct ns_srv_reply ) + len );
- memcpy( reply->name, buf + 7, len );
-
- for( i = buf[6]; i < len && buf[7+i]; i += buf[7+i] + 1 )
- reply->name[i] = '.';
-
- if( i > len )
+ n = 0;
+ while( ns_parserr( &nsh, ns_s_an, n, &rr ) == 0 )
{
- g_free( reply );
- return NULL;
+ size = ns_rr_rdlen( rr );
+ buf = ns_rr_rdata( rr );
+
+ len = 0;
+ for( i = 6; i < size && buf[i]; i += buf[i] + 1 )
+ len += buf[i] + 1;
+
+ if( i > size )
+ break;
+
+ reply = g_malloc( sizeof( struct ns_srv_reply ) + len );
+ memcpy( reply->name, buf + 7, len );
+
+ for( i = buf[6]; i < len && buf[7+i]; i += buf[7+i] + 1 )
+ reply->name[i] = '.';
+
+ if( i > len )
+ {
+ g_free( reply );
+ break;
+ }
+
+ reply->prio = ( buf[0] << 8 ) | buf[1];
+ reply->weight = ( buf[2] << 8 ) | buf[3];
+ reply->port = ( buf[4] << 8 ) | buf[5];
+
+ n ++;
+ replies = g_renew( struct ns_srv_reply *, replies, n + 1 );
+ replies[n-1] = reply;
}
-
- reply->prio = ( buf[0] << 8 ) | buf[1];
- reply->weight = ( buf[2] << 8 ) | buf[3];
- reply->port = ( buf[4] << 8 ) | buf[5];
+ if( replies )
+ replies[n] = NULL;
#endif
- return reply;
+ return replies;
+}
+
+void srv_free( struct ns_srv_reply **srv )
+{
+ int i;
+
+ if( srv == NULL )
+ return;
+
+ for( i = 0; srv[i]; i ++ )
+ g_free( srv[i] );
+ g_free( srv );
}
/* Word wrapping. Yes, I know this isn't UTF-8 clean. I'm willing to take the risk. */
diff --git a/lib/misc.h b/lib/misc.h
index 12a9edff..83ba9e67 100644
--- a/lib/misc.h
+++ b/lib/misc.h
@@ -60,7 +60,8 @@ G_MODULE_EXPORT void random_bytes( unsigned char *buf, int count );
G_MODULE_EXPORT int is_bool( char *value );
G_MODULE_EXPORT int bool2int( char *value );
-G_MODULE_EXPORT struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain );
+G_MODULE_EXPORT struct ns_srv_reply **srv_lookup( char *service, char *protocol, char *domain );
+G_MODULE_EXPORT void srv_free( struct ns_srv_reply **srv );
G_MODULE_EXPORT char *word_wrap( const char *msg, int line_len );
diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c
index 229e35bf..e3717526 100644
--- a/protocols/jabber/jabber.c
+++ b/protocols/jabber/jabber.c
@@ -95,7 +95,7 @@ static void jabber_login( account_t *acc )
{
struct im_connection *ic = imcb_new( acc );
struct jabber_data *jd = g_new0( struct jabber_data, 1 );
- struct ns_srv_reply *srv = NULL;
+ struct ns_srv_reply **srvl = NULL, *srv;
char *connect_to, *s;
int i;
@@ -195,9 +195,19 @@ static void jabber_login( account_t *acc )
/* Figure out the hostname to connect to. */
if( acc->server && *acc->server )
connect_to = acc->server;
- else if( ( srv = srv_lookup( "xmpp-client", "tcp", jd->server ) ) ||
- ( srv = srv_lookup( "jabber-client", "tcp", jd->server ) ) )
+ else if( ( srvl = srv_lookup( "xmpp-client", "tcp", jd->server ) ) ||
+ ( srvl = srv_lookup( "jabber-client", "tcp", jd->server ) ) )
+ {
+ /* Find the lowest-priority one. These usually come
+ back in random/shuffled order. Not looking at
+ weights etc for now. */
+ srv = *srvl;
+ for( i = 1; srvl[i]; i ++ )
+ if( srvl[i]->prio < srv->prio )
+ srv = srvl[i];
+
connect_to = srv->name;
+ }
else
connect_to = jd->server;
@@ -226,7 +236,7 @@ static void jabber_login( account_t *acc )
{
jd->fd = proxy_connect( connect_to, srv ? srv->port : set_getint( &acc->set, "port" ), jabber_connected_plain, ic );
}
- g_free( srv );
+ srv_free( srvl );
if( jd->fd == -1 )
{