diff options
author | Wilmer van der Gaast <wilmer@google.com> | 2010-08-10 12:18:09 +0100 |
---|---|---|
committer | Wilmer van der Gaast <wilmer@google.com> | 2010-08-10 12:18:09 +0100 |
commit | ffdf2e71d9e67980727aa994b77fca36ef5246c6 (patch) | |
tree | 59277a71581915c3203f879b4bf8276fdb001dbf | |
parent | f32c14c649e854fbfb7b8e495e2ebc8459ee5b6f (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.c | 80 | ||||
-rw-r--r-- | lib/misc.h | 3 | ||||
-rw-r--r-- | protocols/jabber/jabber.c | 18 |
3 files changed, 66 insertions, 35 deletions
@@ -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. */ @@ -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 ) { |