3671576ce1e14c20d1efcb6485705b4432a4f2dd
[profile/ivi/ecore.git] / src / lib / ecore_con / ecore_con_dns.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 /*
6  * This version of ecore_con_info uses dns.c to provide asynchronous dns lookup.
7  *
8  * dns.c is written by William Ahern:
9  * http://25thandclement.com/~william/projects/dns.c.html
10  */
11
12 #include <string.h>
13 #include <sys/types.h>
14
15 #ifdef HAVE_ERRNO_H
16 # include <errno.h> /* for EAGAIN */
17 #endif
18
19 #ifdef HAVE_NETINET_IN_H
20 # include <netinet/in.h>
21 #endif
22
23 #ifdef HAVE_ARPA_INET_H
24 # include <arpa/inet.h>
25 #endif
26
27 #ifdef HAVE_ERRNO_H
28 # include <errno.h>
29 #endif
30
31 #include "dns.h"
32
33 #include "Ecore.h"
34 #include "Ecore_Con.h"
35 #include "ecore_con_private.h"
36
37 typedef struct dns_addrinfo dns_addrinfo;
38 typedef struct dns_resolv_conf dns_resolv_conf;
39 typedef struct dns_resolver dns_resolver;
40 typedef struct dns_hosts       dns_hosts;
41
42 typedef struct _Ecore_Con_DNS Ecore_Con_DNS;
43
44 struct _Ecore_Con_DNS
45 {
46    Ecore_Con_Server *svr;
47    Ecore_Con_Info_Cb done_cb;
48    void             *data;
49    dns_addrinfo     *ai;
50    dns_resolver     *resolv;
51    struct addrinfo   hints;
52    Ecore_Fd_Handler *fdh;
53    Ecore_Timer      *timer;
54 };
55
56 static int _ecore_con_dns_init = 0;
57 static dns_resolv_conf *resconf = NULL;
58 static dns_hosts *hosts = NULL;
59
60 static void
61 _ecore_con_dns_free(Ecore_Con_DNS *dns)
62 {
63    if (dns->svr->infos) dns->svr->infos = eina_list_remove(dns->svr->infos, dns);
64    if (dns->timer) ecore_timer_del(dns->timer);
65    if (dns->fdh) ecore_main_fd_handler_del(dns->fdh);
66    dns_res_close(dns_res_mortal(dns->resolv));
67    free(dns);
68 }
69
70 static Eina_Bool
71 _dns_addrinfo_get(Ecore_Con_DNS *dns, const char *addr, int port)
72 {
73    int error = 0;
74    char service[NI_MAXSERV];
75
76    snprintf(service, sizeof(service), "%d", port);
77    dns->ai = dns_ai_open(addr, service, DNS_T_A, (const struct addrinfo *)&dns->hints, dns->resolv, &error);
78    return error;
79 }
80
81 static int
82 _ecore_con_dns_check(Ecore_Con_DNS *dns)
83 {
84    struct addrinfo *ent = NULL;
85    int error = 0;
86  
87    error = dns_ai_nextent(&ent, dns->ai);
88
89    switch (error)
90      {
91       case 0:
92         break;
93       case EAGAIN:
94         return 1;
95       default:
96         ERR("resolve failed: %s", dns_strerror(error));
97         goto error;
98      }
99
100    {
101       Ecore_Con_Info result = {0, .ip = {0}, .service = {0}};
102 #if 0
103       char pretty[512];
104       dns_ai_print(pretty, sizeof(pretty), ent, dns->ai);
105       printf("%s\n", pretty);
106 #endif
107       result.size = 0;
108       dns_inet_ntop(dns_sa_family(ent->ai_addr), dns_sa_addr(dns_sa_family(ent->ai_addr), ent->ai_addr), result.ip, sizeof(result.ip));
109       snprintf(result.service, sizeof(result.service), "%u", ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr)));
110       memcpy(&result.info, ent, sizeof(result.info));
111       if (dns->fdh) ecore_main_fd_handler_del(dns->fdh);
112       dns->fdh = NULL;
113       dns->done_cb(dns->data, &result);
114       free(ent);
115       _ecore_con_dns_free(dns);
116    }
117
118    return 0;
119 error:
120    dns->done_cb(dns->data, NULL);
121    _ecore_con_dns_free(dns);
122    return -1;
123 }
124
125 static Eina_Bool
126 _dns_fd_cb(Ecore_Con_DNS *dns, Ecore_Fd_Handler *fdh __UNUSED__)
127 {
128    if (_ecore_con_dns_check(dns) != 1) return ECORE_CALLBACK_RENEW;
129    if (ecore_main_fd_handler_fd_get(dns->fdh) != dns_ai_pollfd(dns->ai))
130      {
131         ecore_main_fd_handler_del(dns->fdh);
132         dns->fdh = ecore_main_fd_handler_add(dns_ai_pollfd(dns->ai), dns_ai_events(dns->ai), (Ecore_Fd_Cb)_dns_fd_cb, dns, NULL, NULL);
133      }
134    else
135      ecore_main_fd_handler_active_set(dns->fdh, dns_ai_events(dns->ai));
136    return ECORE_CALLBACK_RENEW;
137 }
138
139 static Eina_Bool
140 _dns_timer_cb(Ecore_Con_DNS *dns)
141 {
142    dns->done_cb(dns->data, NULL);
143    _ecore_con_dns_free(dns);
144    dns->timer = NULL;
145    return EINA_FALSE;
146 }
147
148 int
149 ecore_con_info_init(void)
150 {
151    int err;
152    if (_ecore_con_dns_init) return ++_ecore_con_dns_init;
153
154    resconf = dns_resconf_local(&err);
155    if (!resconf)
156      {
157         ERR("resconf_open: %s", dns_strerror(err));
158         return 0;
159      }
160    hosts = dns_hosts_local(&err);
161    if (!hosts)
162      {
163         ERR("hosts_open: %s", dns_strerror(err));
164         dns_resconf_close(resconf);
165         resconf = NULL;
166         return 0;
167      }
168    /* this is super slow don't do it */
169    //resconf->options.recurse = 1;
170    return ++_ecore_con_dns_init;
171 }
172
173 int
174 ecore_con_info_shutdown(void)
175 {
176    if (!_ecore_con_dns_init) return 0;
177    if (--_ecore_con_dns_init) return _ecore_con_dns_init;
178    dns_resconf_close(resconf);
179    resconf = NULL;
180    dns_hosts_close(hosts);
181    hosts = NULL;
182    return 0;
183 }
184
185 void
186 ecore_con_info_data_clear(void *info)
187 {
188    Ecore_Con_DNS *dns = info;
189    if (dns) dns->data = NULL;
190 }
191
192 int
193 ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
194                            Ecore_Con_Info_Cb done_cb,
195                            void *data)
196 {
197    struct addrinfo hints;
198
199    memset(&hints, 0, sizeof(struct addrinfo));
200 #ifdef HAVE_IPV6
201    hints.ai_family = AF_INET6;
202 #else
203    hints.ai_family = AF_INET;
204 #endif
205    hints.ai_socktype = SOCK_STREAM;
206    hints.ai_flags = AI_CANONNAME;
207    hints.ai_protocol = IPPROTO_TCP;
208
209    return ecore_con_info_get(svr, done_cb, data, &hints);
210 }
211
212 int
213 ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
214                           Ecore_Con_Info_Cb done_cb,
215                           void *data)
216 {
217    struct addrinfo hints;
218
219    memset(&hints, 0, sizeof(struct addrinfo));
220 #ifdef HAVE_IPV6
221    hints.ai_family = AF_INET6;
222 #else
223    hints.ai_family = AF_INET;
224 #endif
225    hints.ai_socktype = SOCK_STREAM;
226    hints.ai_flags = AI_PASSIVE;
227    hints.ai_protocol = IPPROTO_TCP;
228
229    return ecore_con_info_get(svr, done_cb, data, &hints);
230 }
231
232 int
233 ecore_con_info_udp_connect(Ecore_Con_Server *svr,
234                            Ecore_Con_Info_Cb done_cb,
235                            void *data)
236 {
237    struct addrinfo hints;
238
239    memset(&hints, 0, sizeof(struct addrinfo));
240 #ifdef HAVE_IPV6
241    hints.ai_family = AF_INET6;
242 #else
243    hints.ai_family = AF_INET;
244 #endif
245    hints.ai_socktype = SOCK_DGRAM;
246    hints.ai_flags = AI_CANONNAME;
247    hints.ai_protocol = IPPROTO_UDP;
248
249    return ecore_con_info_get(svr, done_cb, data, &hints);
250 }
251
252 int
253 ecore_con_info_udp_listen(Ecore_Con_Server *svr,
254                           Ecore_Con_Info_Cb done_cb,
255                           void *data)
256 {
257    struct addrinfo hints;
258
259    memset(&hints, 0, sizeof(struct addrinfo));
260 #ifdef HAVE_IPV6
261    hints.ai_family = AF_INET6;
262 #else
263    hints.ai_family = AF_INET;
264 #endif
265    hints.ai_socktype = SOCK_DGRAM;
266    hints.ai_flags = AI_PASSIVE;
267    hints.ai_protocol = IPPROTO_UDP;
268
269    return ecore_con_info_get(svr, done_cb, data, &hints);
270 }
271
272 int
273 ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
274                             Ecore_Con_Info_Cb done_cb,
275                             void *data)
276 {
277    struct addrinfo hints;
278
279    memset(&hints, 0, sizeof(struct addrinfo));
280 #ifdef HAVE_IPV6
281    hints.ai_family = AF_INET6;
282 #else
283    hints.ai_family = AF_INET;
284 #endif
285    hints.ai_socktype = SOCK_DGRAM;
286    hints.ai_protocol = IPPROTO_UDP;
287
288    return ecore_con_info_get(svr, done_cb, data, &hints);
289 }
290
291 EAPI int
292 ecore_con_info_get(Ecore_Con_Server *svr,
293                    Ecore_Con_Info_Cb done_cb,
294                    void *data,
295                    struct addrinfo *hints)
296 {
297    Ecore_Con_DNS *dns;
298    int error = 0;
299
300    dns = calloc(1, sizeof(Ecore_Con_DNS));
301    if (!dns) return 0;
302
303    dns->svr = svr;
304    dns->done_cb = done_cb;
305    dns->data = data;
306
307    if (hints)
308      memcpy(&dns->hints, hints, sizeof(struct addrinfo));
309
310    if (!(dns->resolv = dns_res_open(resconf, hosts, dns_hints_mortal(dns_hints_local(resconf, &error)), NULL, dns_opts(), &error)))
311      {
312         ERR("res_open: %s", dns_strerror(error));
313         goto reserr;
314
315      }
316
317    error = _dns_addrinfo_get(dns, svr->ecs ? svr->ecs->ip : svr->name, dns->svr->ecs ? dns->svr->ecs->port : dns->svr->port);
318    if (error && (error != EAGAIN))
319      {
320         ERR("resolver: %s", dns_strerror(error));
321         goto seterr;
322      }
323
324    switch (_ecore_con_dns_check(dns))
325      {
326       case 0:
327         break;
328       case 1:
329         dns->fdh = ecore_main_fd_handler_add(dns_ai_pollfd(dns->ai), dns_ai_events(dns->ai), (Ecore_Fd_Cb)_dns_fd_cb, dns, NULL, NULL);
330         svr->infos = eina_list_append(svr->infos, dns);
331         dns->timer = ecore_timer_add(5.0, (Ecore_Task_Cb)_dns_timer_cb, dns);
332         break;
333       default:
334         return 0;
335      }
336
337    return 1;
338 seterr:
339    if (dns->resolv) dns_res_close(dns_res_mortal(dns->resolv));
340 reserr:
341    free(dns);
342    return 0;
343 }
344