From ffdf2e71d9e67980727aa994b77fca36ef5246c6 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 10 Aug 2010 12:18:09 +0100 Subject: 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. --- lib/misc.c | 80 +++++++++++++++++++++++++++++++++++++++----------------------- lib/misc.h | 3 ++- 2 files changed, 52 insertions(+), 31 deletions(-) (limited to 'lib') 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 ); -- cgit v1.2.3