comparison libpurple/dnsquery.c @ 27711:7fbf964c6c6c

Move the IDN support into the DNS routines. This turned out to be cleaner than I first thought, so here we go. All libpurple DNS routines support IDN when built against GNU libidn.
author Paul Aurich <paul@darkrain42.org>
date Sun, 19 Jul 2009 23:45:13 +0000
parents 5345dfe48272
children 8b669aaa3ed7
comparison
equal deleted inserted replaced
27710:91333c6c16ef 27711:7fbf964c6c6c
26 */ 26 */
27 27
28 #include "internal.h" 28 #include "internal.h"
29 #include "debug.h" 29 #include "debug.h"
30 #include "dnsquery.h" 30 #include "dnsquery.h"
31 #include "network.h"
31 #include "notify.h" 32 #include "notify.h"
32 #include "prefs.h" 33 #include "prefs.h"
33 #include "util.h" 34 #include "util.h"
34 35
35 #ifndef _WIN32 36 #ifndef _WIN32
167 168
168 return TRUE; 169 return TRUE;
169 } 170 }
170 171
171 return FALSE; 172 return FALSE;
173 }
174
175 static gboolean
176 dns_str_is_ascii(const char *name)
177 {
178 guchar *c;
179 for (c = (guchar *)name; c && *c; ++c) {
180 if (*c > 0x7f)
181 return FALSE;
182 }
183
184 return TRUE;
172 } 185 }
173 186
174 #if defined(PURPLE_DNSQUERY_USE_FORK) 187 #if defined(PURPLE_DNSQUERY_USE_FORK)
175 188
176 /* 189 /*
228 char servname[20]; 241 char servname[20];
229 #else 242 #else
230 struct sockaddr_in sin; 243 struct sockaddr_in sin;
231 const size_t addrlen = sizeof(sin); 244 const size_t addrlen = sizeof(sin);
232 #endif 245 #endif
246 char *hostname;
233 247
234 #ifdef HAVE_SIGNAL_H 248 #ifdef HAVE_SIGNAL_H
235 purple_restore_default_signal_handlers(); 249 purple_restore_default_signal_handlers();
236 signal(SIGTRAP, trap_gdb_bug); 250 signal(SIGTRAP, trap_gdb_bug);
237 #endif 251 #endif
272 "of an empty hostname (port = %d)!!!\n", getpid(), 286 "of an empty hostname (port = %d)!!!\n", getpid(),
273 dns_params.port); 287 dns_params.port);
274 _exit(1); 288 _exit(1);
275 } 289 }
276 290
291 #ifdef USE_IDN
292 if (!dns_str_is_ascii(dns_params.hostname)) {
293 rc = purple_network_convert_idn_to_ascii(dns_params.hostname, &hostname);
294 if (rc != 0) {
295 write_to_parent(child_out, &rc, sizeof(rc));
296 close(child_out);
297 if (show_debug)
298 fprintf(stderr, "dns[%d] Error: IDN conversion returned "
299 "%d\n", getpid(), rc);
300 dns_params.hostname[0] = '\0';
301 continue;
302 }
303 } else /* intentional to execute the g_strdup */
304 #endif
305 hostname = g_strdup(dns_params.hostname);
306
277 /* We have the hostname and port, now resolve the IP */ 307 /* We have the hostname and port, now resolve the IP */
278 308
279 #ifdef HAVE_GETADDRINFO 309 #ifdef HAVE_GETADDRINFO
280 g_snprintf(servname, sizeof(servname), "%d", dns_params.port); 310 g_snprintf(servname, sizeof(servname), "%d", dns_params.port);
281 memset(&hints, 0, sizeof(hints)); 311 memset(&hints, 0, sizeof(hints));
288 */ 318 */
289 hints.ai_socktype = SOCK_STREAM; 319 hints.ai_socktype = SOCK_STREAM;
290 #ifdef AI_ADDRCONFIG 320 #ifdef AI_ADDRCONFIG
291 hints.ai_flags |= AI_ADDRCONFIG; 321 hints.ai_flags |= AI_ADDRCONFIG;
292 #endif /* AI_ADDRCONFIG */ 322 #endif /* AI_ADDRCONFIG */
293 rc = getaddrinfo(dns_params.hostname, servname, &hints, &res); 323 rc = getaddrinfo(hostname, servname, &hints, &res);
294 write_to_parent(child_out, &rc, sizeof(rc)); 324 write_to_parent(child_out, &rc, sizeof(rc));
295 if (rc != 0) { 325 if (rc != 0) {
296 close(child_out); 326 close(child_out);
297 if (show_debug) 327 if (show_debug)
298 printf("dns[%d] Error: getaddrinfo returned %d\n", 328 printf("dns[%d] Error: getaddrinfo returned %d\n",
307 write_to_parent(child_out, res->ai_addr, res->ai_addrlen); 337 write_to_parent(child_out, res->ai_addr, res->ai_addrlen);
308 res = res->ai_next; 338 res = res->ai_next;
309 } 339 }
310 freeaddrinfo(tmp); 340 freeaddrinfo(tmp);
311 #else 341 #else
312 if (!inet_aton(dns_params.hostname, &sin.sin_addr)) { 342 if (!inet_aton(hostname, &sin.sin_addr)) {
313 struct hostent *hp; 343 struct hostent *hp;
314 if (!(hp = gethostbyname(dns_params.hostname))) { 344 if (!(hp = gethostbyname(hostname))) {
315 write_to_parent(child_out, &h_errno, sizeof(int)); 345 write_to_parent(child_out, &h_errno, sizeof(int));
316 close(child_out); 346 close(child_out);
317 if (show_debug) 347 if (show_debug)
318 printf("DNS Error: %d\n", h_errno); 348 printf("DNS Error: %d\n", h_errno);
319 _exit(0); 349 _exit(0);
330 write_to_parent(child_out, &addrlen, sizeof(addrlen)); 360 write_to_parent(child_out, &addrlen, sizeof(addrlen));
331 write_to_parent(child_out, &sin, addrlen); 361 write_to_parent(child_out, &sin, addrlen);
332 #endif 362 #endif
333 write_to_parent(child_out, &zero, sizeof(zero)); 363 write_to_parent(child_out, &zero, sizeof(zero));
334 dns_params.hostname[0] = '\0'; 364 dns_params.hostname[0] = '\0';
365
366 g_free(hostname);
367 hostname = NULL;
335 } 368 }
336 369
337 close(child_out); 370 close(child_out);
338 close(child_in); 371 close(child_in);
339 372
731 char servname[20]; 764 char servname[20];
732 #else 765 #else
733 struct sockaddr_in sin; 766 struct sockaddr_in sin;
734 struct hostent *hp; 767 struct hostent *hp;
735 #endif 768 #endif
769 char *hostname;
736 770
737 query_data = data; 771 query_data = data;
772
773 #ifdef USE_IDN
774 if (!dns_str_is_ascii(dns_params.hostname)) {
775 rc = purple_network_convert_idn_to_ascii(dns_params.hostname, &hostname);
776 if (rc != 0) {
777 /* FIXME: Dirty 2.6.0 string freeze hack */
778 char tmp[8];
779 g_snprintf(tmp, sizeof(tmp), "%d", rc);
780 query_data->error_message = g_strdup_printf(_("Error resolving %s:\n%s"),
781 query_data->hostname, tmp);
782 /* back to main thread */
783 purple_timeout_add(0, dns_main_thread_cb, query_data);
784 return 0;
785 }
786 } else /* intentional fallthru */
787 #endif
788 hostname = g_strdup(dns_params.hostname);
738 789
739 #ifdef HAVE_GETADDRINFO 790 #ifdef HAVE_GETADDRINFO
740 g_snprintf(servname, sizeof(servname), "%d", query_data->port); 791 g_snprintf(servname, sizeof(servname), "%d", query_data->port);
741 memset(&hints,0,sizeof(hints)); 792 memset(&hints,0,sizeof(hints));
742 793
749 */ 800 */
750 hints.ai_socktype = SOCK_STREAM; 801 hints.ai_socktype = SOCK_STREAM;
751 #ifdef AI_ADDRCONFIG 802 #ifdef AI_ADDRCONFIG
752 hints.ai_flags |= AI_ADDRCONFIG; 803 hints.ai_flags |= AI_ADDRCONFIG;
753 #endif /* AI_ADDRCONFIG */ 804 #endif /* AI_ADDRCONFIG */
754 if ((rc = getaddrinfo(query_data->hostname, servname, &hints, &res)) == 0) { 805 if ((rc = getaddrinfo(hostname, servname, &hints, &res)) == 0) {
755 tmp = res; 806 tmp = res;
756 while(res) { 807 while(res) {
757 query_data->hosts = g_slist_append(query_data->hosts, 808 query_data->hosts = g_slist_append(query_data->hosts,
758 GSIZE_TO_POINTER(res->ai_addrlen)); 809 GSIZE_TO_POINTER(res->ai_addrlen));
759 query_data->hosts = g_slist_append(query_data->hosts, 810 query_data->hosts = g_slist_append(query_data->hosts,
763 freeaddrinfo(tmp); 814 freeaddrinfo(tmp);
764 } else { 815 } else {
765 query_data->error_message = g_strdup_printf(_("Error resolving %s:\n%s"), query_data->hostname, purple_gai_strerror(rc)); 816 query_data->error_message = g_strdup_printf(_("Error resolving %s:\n%s"), query_data->hostname, purple_gai_strerror(rc));
766 } 817 }
767 #else 818 #else
768 if ((hp = gethostbyname(query_data->hostname))) { 819 if ((hp = gethostbyname(hostname))) {
769 memset(&sin, 0, sizeof(struct sockaddr_in)); 820 memset(&sin, 0, sizeof(struct sockaddr_in));
770 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); 821 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
771 sin.sin_family = hp->h_addrtype; 822 sin.sin_family = hp->h_addrtype;
772 sin.sin_port = htons(query_data->port); 823 sin.sin_port = htons(query_data->port);
773 824
777 g_memdup(&sin, sizeof(sin))); 828 g_memdup(&sin, sizeof(sin)));
778 } else { 829 } else {
779 query_data->error_message = g_strdup_printf(_("Error resolving %s: %d"), query_data->hostname, h_errno); 830 query_data->error_message = g_strdup_printf(_("Error resolving %s: %d"), query_data->hostname, h_errno);
780 } 831 }
781 #endif 832 #endif
833 g_free(hostname);
782 834
783 /* back to main thread */ 835 /* back to main thread */
784 purple_timeout_add(0, dns_main_thread_cb, query_data); 836 purple_timeout_add(0, dns_main_thread_cb, query_data);
785 837
786 return 0; 838 return 0;
864 resolve_host(gpointer data) 916 resolve_host(gpointer data)
865 { 917 {
866 PurpleDnsQueryData *query_data; 918 PurpleDnsQueryData *query_data;
867 struct sockaddr_in sin; 919 struct sockaddr_in sin;
868 GSList *hosts = NULL; 920 GSList *hosts = NULL;
921 char *hostname;
869 922
870 query_data = data; 923 query_data = data;
871 query_data->timeout = 0; 924 query_data->timeout = 0;
872 925
873 if (purple_dnsquery_ui_resolve(query_data)) 926 if (purple_dnsquery_ui_resolve(query_data))
876 return FALSE; 929 return FALSE;
877 } 930 }
878 931
879 if (!inet_aton(query_data->hostname, &sin.sin_addr)) { 932 if (!inet_aton(query_data->hostname, &sin.sin_addr)) {
880 struct hostent *hp; 933 struct hostent *hp;
881 if(!(hp = gethostbyname(query_data->hostname))) { 934 #ifdef USE_IDN
935 if (!dns_str_is_ascii(query_data->hostname)) {
936 int ret = purple_network_convert_idn_to_ascii(query_data->hostname,
937 &hostname);
938 if (ret != 0) {
939 char message[1024];
940 g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
941 query_data->hostname, ret);
942 purple_dnsquery_failed(query_data, message);
943 return FALSE;
944 }
945 } else /* fallthrough is intentional to the g_strdup */
946 #endif
947 hostname = g_strdup(query_data->hostname);
948
949 if(!(hp = gethostbyname(hostname))) {
882 char message[1024]; 950 char message[1024];
883 g_snprintf(message, sizeof(message), _("Error resolving %s: %d"), 951 g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
884 query_data->hostname, h_errno); 952 query_data->hostname, h_errno);
885 purple_dnsquery_failed(query_data, message); 953 purple_dnsquery_failed(query_data, message);
886 return FALSE; 954 return FALSE;
890 sin.sin_family = hp->h_addrtype; 958 sin.sin_family = hp->h_addrtype;
891 } else 959 } else
892 sin.sin_family = AF_INET; 960 sin.sin_family = AF_INET;
893 sin.sin_port = htons(query_data->port); 961 sin.sin_port = htons(query_data->port);
894 962
963 g_free(hostname);
895 hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin))); 964 hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin)));
896 hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin))); 965 hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin)));
897 966
898 purple_dnsquery_resolved(query_data, hosts); 967 purple_dnsquery_resolved(query_data, hosts);
899 968