comparison libpurple/dnssrv.c @ 32010:ce968e115c95

propagate from branch 'im.pidgin.cpw.masca.p2p' (head 33ca865dacb9e5bcf763d06f6a42cbaca337cc64) to branch 'im.pidgin.pidgin' (head 92f47f4e8b0cbb107fd97e1ab814d1cedbf109ad)
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Fri, 06 May 2011 06:25:14 +0000
parents 92f3d821653f
children ad79fa168cee
comparison
equal deleted inserted replaced
32009:f021d93a1f9b 32010:ce968e115c95
18 * 18 *
19 * You should have received a copy of the GNU General Public License 19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
22 */ 22 */
23 #define _PURPLE_DNSSRV_C_
23 24
24 #include "internal.h" 25 #include "internal.h"
25 #include "util.h" 26 #include "util.h"
26 27
27 #ifndef _WIN32 28 #ifndef _WIN32
28 #include <arpa/nameser.h> 29 #include <arpa/nameser.h>
29 #include <resolv.h> 30 #include <resolv.h>
30 #ifdef HAVE_ARPA_NAMESER_COMPAT_H 31 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
31 #include <arpa/nameser_compat.h> 32 #include <arpa/nameser_compat.h>
32 #endif 33 #endif
33 #ifndef T_SRV
34 #define T_SRV 33
35 #endif
36 #ifndef T_TXT
37 #define T_TXT 16
38 #endif
39 #else /* WIN32 */ 34 #else /* WIN32 */
40 #include <windns.h> 35 #include <windns.h>
41 /* Missing from the mingw headers */ 36 /* Missing from the mingw headers */
42 #ifndef DNS_TYPE_SRV 37 #ifndef DNS_TYPE_SRV
43 # define DNS_TYPE_SRV 33 38 # define DNS_TYPE_SRV PurpleDnsTypeSrv
44 #endif 39 #endif
45 #ifndef DNS_TYPE_TXT 40 #ifndef DNS_TYPE_TXT
46 # define DNS_TYPE_TXT 16 41 # define DNS_TYPE_TXT PurpleDnsTypeTxt
47 #endif 42 #endif
43 #endif
44
45 #ifndef T_SRV
46 #define T_SRV PurpleDnsTypeSrv
47 #endif
48 #ifndef T_TXT
49 #define T_TXT PurpleDnsTypeTxt
48 #endif 50 #endif
49 51
50 #include "debug.h" 52 #include "debug.h"
51 #include "dnssrv.h" 53 #include "dnssrv.h"
52 #include "eventloop.h" 54 #include "eventloop.h"
53 #include "network.h" 55 #include "network.h"
56
57 static PurpleSrvTxtQueryUiOps *srv_txt_query_ui_ops = NULL;
54 58
55 #ifndef _WIN32 59 #ifndef _WIN32
56 typedef union { 60 typedef union {
57 HEADER hdr; 61 HEADER hdr;
58 u_char buf[1024]; 62 u_char buf[1024];
64 PVOID* pReserved) = NULL; 68 PVOID* pReserved) = NULL;
65 static void (WINAPI *MyDnsRecordListFree) (PDNS_RECORD pRecordList, 69 static void (WINAPI *MyDnsRecordListFree) (PDNS_RECORD pRecordList,
66 DNS_FREE_TYPE FreeType) = NULL; 70 DNS_FREE_TYPE FreeType) = NULL;
67 #endif 71 #endif
68 72
69 struct _PurpleTxtResponse { 73 struct _PurpleSrvTxtQueryData {
70 char *content;
71 };
72
73 struct _PurpleSrvQueryData {
74 union { 74 union {
75 PurpleSrvCallback srv; 75 PurpleSrvCallback srv;
76 PurpleTxtCallback txt; 76 PurpleTxtCallback txt;
77 } cb; 77 } cb;
78 78
79 gpointer extradata; 79 gpointer extradata;
80 guint handle; 80 guint handle;
81 int type; 81 int type;
82 char *query;
82 #ifdef _WIN32 83 #ifdef _WIN32
83 GThread *resolver; 84 GThread *resolver;
84 char *query;
85 char *error_message; 85 char *error_message;
86 GList *results; 86 GList *results;
87 #else 87 #else
88 int fd_in, fd_out; 88 int fd_in, fd_out;
89 pid_t pid; 89 pid_t pid;
97 97
98 typedef struct _PurpleSrvResponseContainer { 98 typedef struct _PurpleSrvResponseContainer {
99 PurpleSrvResponse *response; 99 PurpleSrvResponse *response;
100 int sum; 100 int sum;
101 } PurpleSrvResponseContainer; 101 } PurpleSrvResponseContainer;
102
103 static gboolean purple_srv_txt_query_ui_resolve(PurpleSrvTxtQueryData *query_data);
102 104
103 /** 105 /**
104 * Sort by priority, then by weight. Strictly numerically--no 106 * Sort by priority, then by weight. Strictly numerically--no
105 * randomness. Technically we only need to sort by pref and then 107 * randomness. Technically we only need to sort by pref and then
106 * make sure any records with weight 0 are at the beginning of 108 * make sure any records with weight 0 are at the beginning of
428 static void 430 static void
429 resolved(gpointer data, gint source, PurpleInputCondition cond) 431 resolved(gpointer data, gint source, PurpleInputCondition cond)
430 { 432 {
431 int size; 433 int size;
432 int type; 434 int type;
433 PurpleSrvQueryData *query_data = (PurpleSrvQueryData*)data; 435 PurpleSrvTxtQueryData *query_data = (PurpleSrvTxtQueryData*)data;
434 int i; 436 int i;
435 int status; 437 int status;
436 438
437 if (read(source, &type, sizeof(type)) == sizeof(type)) { 439 if (read(source, &type, sizeof(type)) == sizeof(type)) {
438 if (read(source, &size, sizeof(size)) == sizeof(size)) { 440 if (read(source, &size, sizeof(size)) == sizeof(size)) {
530 532
531 static gboolean 533 static gboolean
532 res_main_thread_cb(gpointer data) 534 res_main_thread_cb(gpointer data)
533 { 535 {
534 PurpleSrvResponse *srvres = NULL; 536 PurpleSrvResponse *srvres = NULL;
535 PurpleSrvQueryData *query_data = data; 537 PurpleSrvTxtQueryData *query_data = data;
536 if(query_data->error_message != NULL) { 538 if(query_data->error_message != NULL) {
537 purple_debug_error("dnssrv", "%s", query_data->error_message); 539 purple_debug_error("dnssrv", "%s", query_data->error_message);
538 if (query_data->type == DNS_TYPE_SRV) { 540 if (query_data->type == DNS_TYPE_SRV) {
539 if (query_data->cb.srv) 541 if (query_data->cb.srv)
540 query_data->cb.srv(srvres, 0, query_data->extradata); 542 query_data->cb.srv(srvres, 0, query_data->extradata);
590 res_thread(gpointer data) 592 res_thread(gpointer data)
591 { 593 {
592 PDNS_RECORD dr = NULL; 594 PDNS_RECORD dr = NULL;
593 int type; 595 int type;
594 DNS_STATUS ds; 596 DNS_STATUS ds;
595 PurpleSrvQueryData *query_data = data; 597 PurpleSrvTxtQueryData *query_data = data;
596 type = query_data->type; 598 type = query_data->type;
597 ds = MyDnsQuery_UTF8(query_data->query, type, DNS_QUERY_STANDARD, NULL, &dr, NULL); 599 ds = MyDnsQuery_UTF8(query_data->query, type, DNS_QUERY_STANDARD, NULL, &dr, NULL);
598 if (ds != ERROR_SUCCESS) { 600 if (ds != ERROR_SUCCESS) {
599 gchar *msg = g_win32_error_message(ds); 601 gchar *msg = g_win32_error_message(ds);
600 if (type == DNS_TYPE_SRV) { 602 if (type == DNS_TYPE_SRV) {
670 return NULL; 672 return NULL;
671 } 673 }
672 674
673 #endif 675 #endif
674 676
675 PurpleSrvQueryData * 677 PurpleSrvTxtQueryData *
676 purple_srv_resolve(const char *protocol, const char *transport, const char *domain, PurpleSrvCallback cb, gpointer extradata) 678 purple_srv_resolve(const char *protocol, const char *transport,
679 const char *domain, PurpleSrvCallback cb, gpointer extradata)
680 {
681 return purple_srv_resolve_account(NULL, protocol, transport, domain,
682 cb, extradata);
683 }
684
685 PurpleSrvTxtQueryData *
686 purple_srv_resolve_account(PurpleAccount *account, const char *protocol,
687 const char *transport, const char *domain, PurpleSrvCallback cb,
688 gpointer extradata)
677 { 689 {
678 char *query; 690 char *query;
679 char *hostname; 691 char *hostname;
680 PurpleSrvQueryData *query_data; 692 PurpleSrvTxtQueryData *query_data;
693 PurpleProxyType proxy_type;
681 #ifndef _WIN32 694 #ifndef _WIN32
682 PurpleSrvInternalQuery internal_query; 695 PurpleSrvInternalQuery internal_query;
683 int in[2], out[2]; 696 int in[2], out[2];
684 int pid; 697 int pid;
685 #else 698 #else
691 purple_debug_error("dnssrv", "Wrong arguments\n"); 704 purple_debug_error("dnssrv", "Wrong arguments\n");
692 cb(NULL, 0, extradata); 705 cb(NULL, 0, extradata);
693 g_return_val_if_reached(NULL); 706 g_return_val_if_reached(NULL);
694 } 707 }
695 708
709 proxy_type = purple_proxy_info_get_type(
710 purple_proxy_get_setup(account));
711 if (proxy_type == PURPLE_PROXY_TOR) {
712 purple_debug_info("dnssrv", "Aborting SRV lookup in Tor Proxy mode.");
713 cb(NULL, 0, extradata);
714 return NULL;
715 }
716
696 #ifdef USE_IDN 717 #ifdef USE_IDN
697 if (!dns_str_is_ascii(domain)) { 718 if (!dns_str_is_ascii(domain)) {
698 int ret = purple_network_convert_idn_to_ascii(domain, &hostname); 719 int ret = purple_network_convert_idn_to_ascii(domain, &hostname);
699 if (ret != 0) { 720 if (ret != 0) {
700 purple_debug_error("dnssrv", "IDNA ToASCII failed\n"); 721 purple_debug_error("dnssrv", "IDNA ToASCII failed\n");
707 728
708 query = g_strdup_printf("_%s._%s.%s", protocol, transport, hostname); 729 query = g_strdup_printf("_%s._%s.%s", protocol, transport, hostname);
709 purple_debug_info("dnssrv","querying SRV record for %s: %s\n", domain, 730 purple_debug_info("dnssrv","querying SRV record for %s: %s\n", domain,
710 query); 731 query);
711 g_free(hostname); 732 g_free(hostname);
733
734 query_data = g_new0(PurpleSrvTxtQueryData, 1);
735 query_data->type = PurpleDnsTypeSrv;
736 query_data->cb.srv = cb;
737 query_data->extradata = extradata;
738 query_data->query = query;
739
740 if (purple_srv_txt_query_ui_resolve(query_data))
741 {
742 return query_data;
743 }
712 744
713 #ifndef _WIN32 745 #ifndef _WIN32
714 if(pipe(in) || pipe(out)) { 746 if(pipe(in) || pipe(out)) {
715 purple_debug_error("dnssrv", "Could not create pipe\n"); 747 purple_debug_error("dnssrv", "Could not create pipe\n");
716 g_free(query); 748 g_free(query);
745 internal_query.query[255] = '\0'; 777 internal_query.query[255] = '\0';
746 778
747 if (write(in[1], &internal_query, sizeof(internal_query)) < 0) 779 if (write(in[1], &internal_query, sizeof(internal_query)) < 0)
748 purple_debug_error("dnssrv", "Could not write to SRV resolver\n"); 780 purple_debug_error("dnssrv", "Could not write to SRV resolver\n");
749 781
750 query_data = g_new0(PurpleSrvQueryData, 1);
751 query_data->type = T_SRV;
752 query_data->cb.srv = cb;
753 query_data->extradata = extradata;
754 query_data->pid = pid; 782 query_data->pid = pid;
755 query_data->fd_out = out[0]; 783 query_data->fd_out = out[0];
756 query_data->fd_in = in[1]; 784 query_data->fd_in = in[1];
757 query_data->handle = purple_input_add(out[0], PURPLE_INPUT_READ, resolved, query_data); 785 query_data->handle = purple_input_add(out[0], PURPLE_INPUT_READ, resolved, query_data);
758 786
765 MyDnsRecordListFree = (void*) wpurple_find_and_loadproc( 793 MyDnsRecordListFree = (void*) wpurple_find_and_loadproc(
766 "dnsapi.dll", "DnsRecordListFree"); 794 "dnsapi.dll", "DnsRecordListFree");
767 initialized = TRUE; 795 initialized = TRUE;
768 } 796 }
769 797
770 query_data = g_new0(PurpleSrvQueryData, 1);
771 query_data->type = DNS_TYPE_SRV;
772 query_data->cb.srv = cb;
773 query_data->query = query;
774 query_data->extradata = extradata;
775
776 if (!MyDnsQuery_UTF8 || !MyDnsRecordListFree) 798 if (!MyDnsQuery_UTF8 || !MyDnsRecordListFree)
777 query_data->error_message = g_strdup("System missing DNS API (Requires W2K+)\n"); 799 query_data->error_message = g_strdup("System missing DNS API (Requires W2K+)\n");
778 else { 800 else {
779 query_data->resolver = g_thread_create(res_thread, query_data, FALSE, &err); 801 query_data->resolver = g_thread_create(res_thread, query_data, FALSE, &err);
780 if (query_data->resolver == NULL) { 802 if (query_data->resolver == NULL) {
791 813
792 return query_data; 814 return query_data;
793 #endif 815 #endif
794 } 816 }
795 817
796 PurpleSrvQueryData *purple_txt_resolve(const char *owner, const char *domain, PurpleTxtCallback cb, gpointer extradata) 818 PurpleSrvTxtQueryData *purple_txt_resolve(const char *owner,
819 const char *domain, PurpleTxtCallback cb, gpointer extradata)
820 {
821 return purple_txt_resolve_account(NULL, owner, domain, cb, extradata);
822 }
823
824 PurpleSrvTxtQueryData *purple_txt_resolve_account(PurpleAccount *account,
825 const char *owner, const char *domain, PurpleTxtCallback cb,
826 gpointer extradata)
797 { 827 {
798 char *query; 828 char *query;
799 char *hostname; 829 char *hostname;
800 PurpleSrvQueryData *query_data; 830 PurpleSrvTxtQueryData *query_data;
831 PurpleProxyType proxy_type;
801 #ifndef _WIN32 832 #ifndef _WIN32
802 PurpleSrvInternalQuery internal_query; 833 PurpleSrvInternalQuery internal_query;
803 int in[2], out[2]; 834 int in[2], out[2];
804 int pid; 835 int pid;
805 #else 836 #else
806 GError* err = NULL; 837 GError* err = NULL;
807 static gboolean initialized = FALSE; 838 static gboolean initialized = FALSE;
808 #endif 839 #endif
809 840
841 proxy_type = purple_proxy_info_get_type(
842 purple_proxy_get_setup(account));
843 if (proxy_type == PURPLE_PROXY_TOR) {
844 purple_debug_info("dnssrv", "Aborting TXT lookup in Tor Proxy mode.");
845 cb(NULL, extradata);
846 return NULL;
847 }
848
810 #ifdef USE_IDN 849 #ifdef USE_IDN
811 if (!dns_str_is_ascii(domain)) { 850 if (!dns_str_is_ascii(domain)) {
812 int ret = purple_network_convert_idn_to_ascii(domain, &hostname); 851 int ret = purple_network_convert_idn_to_ascii(domain, &hostname);
813 if (ret != 0) { 852 if (ret != 0) {
814 purple_debug_error("dnssrv", "IDNA ToASCII failed\n"); 853 purple_debug_error("dnssrv", "IDNA ToASCII failed\n");
821 860
822 query = g_strdup_printf("%s.%s", owner, hostname); 861 query = g_strdup_printf("%s.%s", owner, hostname);
823 purple_debug_info("dnssrv","querying TXT record for %s: %s\n", domain, 862 purple_debug_info("dnssrv","querying TXT record for %s: %s\n", domain,
824 query); 863 query);
825 g_free(hostname); 864 g_free(hostname);
865
866 query_data = g_new0(PurpleSrvTxtQueryData, 1);
867 query_data->type = PurpleDnsTypeTxt;
868 query_data->cb.txt = cb;
869 query_data->extradata = extradata;
870 query_data->query = query;
871
872 if (purple_srv_txt_query_ui_resolve(query_data)) {
873 /* query intentionally not freed
874 */
875 return query_data;
876 }
826 877
827 #ifndef _WIN32 878 #ifndef _WIN32
828 if(pipe(in) || pipe(out)) { 879 if(pipe(in) || pipe(out)) {
829 purple_debug_error("dnssrv", "Could not create pipe\n"); 880 purple_debug_error("dnssrv", "Could not create pipe\n");
830 g_free(query); 881 g_free(query);
858 strncpy(internal_query.query, query, 255); 909 strncpy(internal_query.query, query, 255);
859 internal_query.query[255] = '\0'; 910 internal_query.query[255] = '\0';
860 911
861 if (write(in[1], &internal_query, sizeof(internal_query)) < 0) 912 if (write(in[1], &internal_query, sizeof(internal_query)) < 0)
862 purple_debug_error("dnssrv", "Could not write to TXT resolver\n"); 913 purple_debug_error("dnssrv", "Could not write to TXT resolver\n");
863 914
864 query_data = g_new0(PurpleSrvQueryData, 1);
865 query_data->type = T_TXT;
866 query_data->cb.txt = cb;
867 query_data->extradata = extradata;
868 query_data->pid = pid; 915 query_data->pid = pid;
869 query_data->fd_out = out[0]; 916 query_data->fd_out = out[0];
870 query_data->fd_in = in[1]; 917 query_data->fd_in = in[1];
871 query_data->handle = purple_input_add(out[0], PURPLE_INPUT_READ, resolved, query_data); 918 query_data->handle = purple_input_add(out[0], PURPLE_INPUT_READ, resolved, query_data);
872 919
879 MyDnsRecordListFree = (void*) wpurple_find_and_loadproc( 926 MyDnsRecordListFree = (void*) wpurple_find_and_loadproc(
880 "dnsapi.dll", "DnsRecordListFree"); 927 "dnsapi.dll", "DnsRecordListFree");
881 initialized = TRUE; 928 initialized = TRUE;
882 } 929 }
883 930
884 query_data = g_new0(PurpleSrvQueryData, 1);
885 query_data->type = DNS_TYPE_TXT;
886 query_data->cb.txt = cb;
887 query_data->query = query;
888 query_data->extradata = extradata;
889
890 if (!MyDnsQuery_UTF8 || !MyDnsRecordListFree) 931 if (!MyDnsQuery_UTF8 || !MyDnsRecordListFree)
891 query_data->error_message = g_strdup("System missing DNS API (Requires W2K+)\n"); 932 query_data->error_message = g_strdup("System missing DNS API (Requires W2K+)\n");
892 else { 933 else {
893 query_data->resolver = g_thread_create(res_thread, query_data, FALSE, &err); 934 query_data->resolver = g_thread_create(res_thread, query_data, FALSE, &err);
894 if (query_data->resolver == NULL) { 935 if (query_data->resolver == NULL) {
906 return query_data; 947 return query_data;
907 #endif 948 #endif
908 } 949 }
909 950
910 void 951 void
911 purple_srv_cancel(PurpleSrvQueryData *query_data) 952 purple_srv_cancel(PurpleSrvTxtQueryData *query_data)
912 { 953 {
954 PurpleSrvTxtQueryUiOps *ops = purple_srv_txt_query_get_ui_ops();
955
956 if (ops && ops->destroy)
957 ops->destroy(query_data);
958
913 if (query_data->handle > 0) 959 if (query_data->handle > 0)
914 purple_input_remove(query_data->handle); 960 purple_input_remove(query_data->handle);
915 #ifdef _WIN32 961 #ifdef _WIN32
916 if (query_data->resolver != NULL) 962 if (query_data->resolver != NULL)
917 { 963 {
931 #endif 977 #endif
932 g_free(query_data); 978 g_free(query_data);
933 } 979 }
934 980
935 void 981 void
936 purple_txt_cancel(PurpleSrvQueryData *query_data) 982 purple_txt_cancel(PurpleSrvTxtQueryData *query_data)
937 { 983 {
938 purple_srv_cancel(query_data); 984 purple_srv_cancel(query_data);
939 } 985 }
940 986
941 const gchar * 987 const gchar *
951 g_return_if_fail(resp != NULL); 997 g_return_if_fail(resp != NULL);
952 998
953 g_free(resp->content); 999 g_free(resp->content);
954 g_free(resp); 1000 g_free(resp);
955 } 1001 }
1002
1003 /*
1004 * Only used as the callback for the ui ops.
1005 */
1006 static void
1007 purple_srv_query_resolved(PurpleSrvTxtQueryData *query_data, GList *records)
1008 {
1009 g_return_if_fail(records != NULL);
1010
1011 purple_debug_info("dnssrv", "SRV records resolved for %s, count: %d\n", query_data->query, g_list_length(records));
1012
1013 if (query_data->cb.srv != NULL)
1014 query_data->cb.srv(purple_srv_sort(records)->data, g_list_length(records), query_data->extradata);
1015 }
1016
1017 /*
1018 * Only used as the callback for the ui ops.
1019 */
1020 static void
1021 purple_txt_query_resolved(PurpleSrvTxtQueryData *query_data, GList *entries)
1022 {
1023 g_return_if_fail(entries != NULL);
1024
1025 purple_debug_info("dnssrv", "TXT entries resolved for %s, count: %d\n", query_data->query, g_list_length(entries));
1026
1027 if (query_data->cb.txt != NULL)
1028 query_data->cb.txt(entries, query_data->extradata);
1029 }
1030
1031 static void
1032 purple_srv_query_failed(PurpleSrvTxtQueryData *query_data, const gchar *error_message)
1033 {
1034 purple_debug_error("dnssrv", "%s\n", error_message);
1035
1036 if (query_data->cb.srv != NULL)
1037 query_data->cb.srv(NULL, 0, query_data->extradata);
1038
1039 purple_srv_cancel(query_data);
1040 }
1041
1042 static gboolean
1043 purple_srv_txt_query_ui_resolve(PurpleSrvTxtQueryData *query_data)
1044 {
1045 PurpleSrvTxtQueryUiOps *ops = purple_srv_txt_query_get_ui_ops();
1046
1047 if (ops && ops->resolve)
1048 return ops->resolve(query_data, (query_data->type == T_SRV ? purple_srv_query_resolved : purple_txt_query_resolved), purple_srv_query_failed);
1049
1050 return FALSE;
1051 }
1052
1053 void
1054 purple_srv_txt_query_set_ui_ops(PurpleSrvTxtQueryUiOps *ops)
1055 {
1056 srv_txt_query_ui_ops = ops;
1057 }
1058
1059 PurpleSrvTxtQueryUiOps *
1060 purple_srv_txt_query_get_ui_ops(void)
1061 {
1062 /* It is perfectly acceptable for srv_txt_query_ui_ops to be NULL; this just
1063 * means that the default platform-specific implementation will be used.
1064 */
1065 return srv_txt_query_ui_ops;
1066 }
1067
1068 char *
1069 purple_srv_txt_query_get_query(PurpleSrvTxtQueryData *query_data)
1070 {
1071 g_return_val_if_fail(query_data != NULL, NULL);
1072
1073 return query_data->query;
1074 }
1075
1076
1077 int
1078 purple_srv_txt_query_get_type(PurpleSrvTxtQueryData *query_data)
1079 {
1080 g_return_val_if_fail(query_data != NULL, 0);
1081
1082 return query_data->type;
1083 }