| 27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA |
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA |
| 28 */ |
28 */ |
| 29 |
29 |
| 30 #include <internal.h> |
30 #include <internal.h> |
| 31 #include <debug.h> |
31 #include <debug.h> |
| 32 #include <dnsquery.h> |
|
| 33 |
32 |
| 34 #include <libgadu.h> |
33 #include <libgadu.h> |
| 35 #include "resolver-purple.h" |
34 #include "resolver-purple.h" |
| 36 |
35 |
| |
36 #include <gio/gio.h> |
| |
37 |
| 37 static int ggp_resolver_purple_start(int *fd, void **private_data, |
38 static int ggp_resolver_purple_start(int *fd, void **private_data, |
| 38 const char *hostname); |
39 const char *hostname); |
| 39 |
40 |
| 40 static void ggp_resolver_purple_cleanup(void **private_data, int force); |
41 static void ggp_resolver_purple_cleanup(void **private_data, int force); |
| 41 |
42 |
| 42 static void ggp_resolver_purple_cb(GSList *hosts, gpointer cbdata, |
43 static void ggp_resolver_purple_cb(GObject *sender, GAsyncResult *res, gpointer data); |
| 43 const char *error_message); |
|
| 44 |
44 |
| 45 typedef struct |
45 typedef struct |
| 46 { |
46 { |
| 47 PurpleDnsQueryData *purpleQuery; |
47 GCancellable *cancellable; |
| 48 |
48 |
| 49 /** |
49 /** |
| 50 * File descriptors: |
50 * File descriptors: |
| 51 * pipes[0] - for reading |
51 * pipes[0] - for reading |
| 52 * pipes[1] - for writing |
52 * pipes[1] - for writing |
| 62 { |
62 { |
| 63 purple_debug_error("gg", "failed to set custom resolver\n"); |
63 purple_debug_error("gg", "failed to set custom resolver\n"); |
| 64 } |
64 } |
| 65 } |
65 } |
| 66 |
66 |
| 67 void ggp_resolver_purple_cb(GSList *hosts, gpointer cbdata, |
67 void ggp_resolver_purple_cb(GObject *sender, GAsyncResult *res, gpointer cbdata) { |
| 68 const char *error_message) |
68 GList *addresses = NULL, *in_addrs = NULL, *l = NULL; |
| 69 { |
69 GError *error = NULL; |
| |
70 gsize native_size = 0; /* this is kind of dirty, but it'll be initialized before we use it */ |
| |
71 |
| 70 ggp_resolver_purple_data *data = (ggp_resolver_purple_data*)cbdata; |
72 ggp_resolver_purple_data *data = (ggp_resolver_purple_data*)cbdata; |
| 71 const int fd = data->pipes[1]; |
73 const int fd = data->pipes[1]; |
| 72 int ipv4_count, all_count, write_size; |
74 |
| 73 struct in_addr *addresses; |
75 addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), res, &error); |
| 74 |
76 if(addresses == NULL) { |
| 75 purple_debug_misc("gg", "ggp_resolver_purple_cb(%p, %p, \"%s\")\n", |
|
| 76 hosts, cbdata, error_message); |
|
| 77 |
|
| 78 data->purpleQuery = NULL; |
|
| 79 |
|
| 80 if (error_message) { |
|
| 81 purple_debug_error("gg", "ggp_resolver_purple_cb failed: %s\n", |
77 purple_debug_error("gg", "ggp_resolver_purple_cb failed: %s\n", |
| 82 error_message); |
78 error->message); |
| 83 } |
79 |
| 84 |
80 g_error_free(error); |
| 85 all_count = g_slist_length(hosts); |
81 } else { |
| 86 g_assert(all_count % 2 == 0); |
82 purple_debug_misc("gg", "ggp_resolver_purple_cb succeeded: (%p, %p)\n", |
| 87 all_count /= 2; |
83 addresses, cbdata); |
| 88 addresses = malloc((all_count + 1) * sizeof(struct in_addr)); |
84 } |
| 89 |
85 |
| 90 ipv4_count = 0; |
86 g_object_unref(G_OBJECT(data->cancellable)); |
| 91 while (hosts && (hosts = g_slist_delete_link(hosts, hosts))) { |
87 data->cancellable = NULL; |
| 92 common_sockaddr_t addr; |
88 |
| 93 char dst[INET6_ADDRSTRLEN]; |
89 for(l = addresses; l; l = l->next) { |
| 94 |
90 GInetAddress *inet_address = G_INET_ADDRESS(l->data); |
| 95 memcpy(&addr, hosts->data, sizeof(addr)); |
91 GSocketFamily family = G_SOCKET_FAMILY_INVALID; |
| 96 |
92 gchar *ip_address = g_inet_address_to_string(inet_address); |
| 97 if (addr.sa.sa_family == AF_INET6) { |
93 |
| 98 inet_ntop(addr.sa.sa_family, &addr.in6.sin6_addr, |
94 family = g_inet_address_get_family(inet_address); |
| 99 dst, sizeof(dst)); |
95 |
| 100 purple_debug_misc("gg", "ggp_resolver_purple_cb " |
96 switch(family) { |
| 101 "ipv6 (ignore): %s\n", dst); |
97 case G_SOCKET_FAMILY_IPV4: |
| 102 } else if (addr.sa.sa_family == AF_INET) { |
98 purple_debug_misc("gg", "ggp_resolver_purple_cb " |
| 103 inet_ntop(addr.sa.sa_family, &addr.in.sin_addr, |
99 "ipv4: %s\n", ip_address); |
| 104 dst, sizeof(dst)); |
100 |
| 105 purple_debug_misc("gg", "ggp_resolver_purple_cb " |
101 native_size = g_inet_address_get_native_size(inet_address); |
| 106 "ipv4: %s\n", dst); |
102 in_addrs = g_list_append(in_addrs, g_memdup(g_inet_address_to_bytes(inet_address), native_size)); |
| 107 |
103 |
| 108 g_assert(ipv4_count < all_count); |
104 break; |
| 109 addresses[ipv4_count++] = addr.in.sin_addr; |
105 case G_SOCKET_FAMILY_IPV6: |
| 110 } else { |
106 purple_debug_misc("gg", "ggp_resolver_purple_cb " |
| 111 purple_debug_warning("gg", "ggp_resolver_purple_cb " |
107 "ipv6 (ignore): %s\n", ip_address); |
| 112 "unexpected sa_family: %d\n", |
108 |
| 113 addr.sa.sa_family); |
109 break; |
| |
110 default: |
| |
111 purple_debug_warning("gg", "ggp_resolver_purple_cb " |
| |
112 "unexpected sa_family: %d\n", |
| |
113 family); |
| |
114 |
| |
115 break; |
| 114 } |
116 } |
| 115 |
117 |
| 116 g_free(hosts->data); |
118 g_free(ip_address); |
| 117 hosts = g_slist_delete_link(hosts, hosts); |
119 } |
| 118 } |
120 |
| 119 |
121 for(l = in_addrs; l; l = l->next) { |
| 120 addresses[ipv4_count].s_addr = INADDR_NONE; |
122 gint write_size = native_size; |
| 121 |
123 if(write(fd, l->data, write_size) != write_size) { |
| 122 write_size = (ipv4_count + 1) * sizeof(struct in_addr); |
124 purple_debug_error("gg", |
| 123 if (write(fd, addresses, write_size) != write_size) { |
125 "ggp_resolver_purple_cb write error on %p\n", l->data); |
| 124 purple_debug_error("gg", |
126 } |
| 125 "ggp_resolver_purple_cb write error\n"); |
127 |
| 126 } |
128 g_free(l->data); |
| 127 free(addresses); |
129 } |
| |
130 |
| |
131 g_list_free(in_addrs); |
| |
132 g_resolver_free_addresses(addresses); |
| 128 } |
133 } |
| 129 |
134 |
| 130 int ggp_resolver_purple_start(int *fd, void **private_data, |
135 int ggp_resolver_purple_start(int *fd, void **private_data, |
| 131 const char *hostname) |
136 const char *hostname) |
| 132 { |
137 { |
| 134 purple_debug_misc("gg", "ggp_resolver_purple_start(%p, %p, \"%s\")\n", |
139 purple_debug_misc("gg", "ggp_resolver_purple_start(%p, %p, \"%s\")\n", |
| 135 fd, private_data, hostname); |
140 fd, private_data, hostname); |
| 136 |
141 |
| 137 data = malloc(sizeof(ggp_resolver_purple_data)); |
142 data = malloc(sizeof(ggp_resolver_purple_data)); |
| 138 *private_data = (void*)data; |
143 *private_data = (void*)data; |
| 139 data->purpleQuery = NULL; |
144 data->cancellable = NULL; |
| 140 data->pipes[0] = 0; |
145 data->pipes[0] = 0; |
| 141 data->pipes[1] = 0; |
146 data->pipes[1] = 0; |
| 142 |
147 |
| 143 if (purple_input_pipe(data->pipes) != 0) { |
148 if (purple_input_pipe(data->pipes) != 0) { |
| 144 purple_debug_error("gg", "ggp_resolver_purple_start: " |
149 purple_debug_error("gg", "ggp_resolver_purple_start: " |
| 148 } |
153 } |
| 149 |
154 |
| 150 *fd = data->pipes[0]; |
155 *fd = data->pipes[0]; |
| 151 |
156 |
| 152 /* account and port is unknown in this context */ |
157 /* account and port is unknown in this context */ |
| 153 data->purpleQuery = purple_dnsquery_a(NULL, hostname, 80, |
158 data->cancellable = g_cancellable_new(); |
| 154 ggp_resolver_purple_cb, (gpointer)data); |
159 |
| 155 |
160 g_resolver_lookup_by_name_async(g_resolver_get_default(), |
| 156 if (!data->purpleQuery) { |
161 hostname, |
| |
162 data->cancellable, |
| |
163 ggp_resolver_purple_cb, |
| |
164 (gpointer)data); |
| |
165 |
| |
166 if (!data->cancellable) { |
| 157 purple_debug_error("gg", "ggp_resolver_purple_start: " |
167 purple_debug_error("gg", "ggp_resolver_purple_start: " |
| 158 "unable to call purple_dnsquery_a\n"); |
168 "unable to call purple_dnsquery_a\n"); |
| 159 ggp_resolver_purple_cleanup(private_data, 0); |
169 ggp_resolver_purple_cleanup(private_data, 0); |
| 160 return -1; |
170 return -1; |
| 161 } |
171 } |