e9c64deb48b6f936f3d9042960b6a78febe5cd4f
[framework/uifw/ecore.git] / src / lib / ecore_con / ecore_con_dns.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4 /* 
5  * Simple dns lookup
6  *
7  * http://www.faqs.org/rfcs/rfc1035.html
8  * man resolv.conf
9  *
10  * And a sneakpeek at ares, ftp://athena-dist.mit.edu/pub/ATHENA/ares/
11  */
12 /*
13  * TODO
14  * * Check env LOCALDOMAIN to override search
15  * * Check env RES_OPTIONS to override options
16  *
17  * * Read /etc/host.conf
18  * * host.conf env
19  *   RESOLV_HOST_CONF, RESOLV_SERV_ORDER
20  * * Check /etc/hosts
21  *
22  * * Caching
23  *   We should store all names returned when CNAME, might have different ttl.
24  *   Check against search and hostname when querying cache?
25  * * Remember all querys and delete them on shutdown
26  *
27  * * Need more buffer overflow checks.
28  */
29 #include "ecore_private.h"
30 #include "Ecore.h"
31 #include "ecore_con_private.h"
32
33 #include <ctype.h>
34 #include <netinet/in.h>
35 #include <sys/socket.h>
36 #include <arpa/inet.h>
37 #include <arpa/nameser.h>
38 #include <netdb.h>
39
40 typedef struct _CB_Data CB_Data;
41
42 struct _CB_Data
43 {
44    Ecore_List2 __list_data;
45    void (*cb_done) (void *data, struct hostent *hostent);
46    void *data;
47    Ecore_Fd_Handler *fdh;
48    pid_t pid;
49    Ecore_Event_Handler *handler;
50    int fd2;
51 };
52
53 static void _ecore_con_dns_readdata(CB_Data *cbdata);
54 static void _ecore_con_dns_slave_free(CB_Data *cbdata);
55 static int _ecore_con_dns_data_handler(void *data, Ecore_Fd_Handler *fd_handler);
56 static int _ecore_con_dns_exit_handler(void *data, int type __UNUSED__, void *event);
57
58 static int dns_init = 0;
59 static Ecore_List2 *dns_slaves = NULL;
60   
61 int
62 ecore_con_dns_init(void)
63 {
64    dns_init++;
65    return dns_init;
66 }
67
68 int
69 ecore_con_dns_shutdown(void)
70 {
71    dns_init--;
72    if (dns_init == 0)
73      {
74         while (dns_slaves) _ecore_con_dns_slave_free((CB_Data *)dns_slaves);
75      }
76    return dns_init;
77 }
78
79 int
80 ecore_con_dns_lookup(const char *name,
81                      void (*done_cb) (void *data, struct hostent *hostent),
82                      void *data)
83 {
84    CB_Data *cbdata;
85    int fd[2];
86    
87    if (pipe(fd) < 0) return 0;
88    cbdata = calloc(1, sizeof(CB_Data));
89    if (!cbdata)
90      {
91         close(fd[0]);
92         close(fd[1]);
93         return 0;
94      }
95    cbdata->cb_done = done_cb;
96    cbdata->data = data;
97    cbdata->fd2 = fd[1];
98    if (!(cbdata->fdh = ecore_main_fd_handler_add(fd[0], ECORE_FD_READ, 
99                                                  _ecore_con_dns_data_handler,
100                                                  cbdata,
101                                                  NULL, NULL)))
102      {
103         free(cbdata);
104         close(fd[0]);
105         close(fd[1]);
106         return 0;
107      }
108                              
109    if ((cbdata->pid = fork()) == 0)
110      {
111         struct hostent *he;
112         
113         /* CHILD */
114         he = gethostbyname(name);
115         if (he)
116           {
117              struct in_addr addr;
118              
119              memcpy((struct in_addr *)&addr, he->h_addr,
120                     sizeof(struct in_addr));
121              write(fd[1], &(addr.s_addr), sizeof(in_addr_t));
122           }
123         close(fd[1]);
124 # ifdef __USE_ISOC99
125         _Exit(0);
126 # else  
127         _exit(0);
128 # endif 
129      }
130    /* PARENT */
131    cbdata->handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _ecore_con_dns_exit_handler, cbdata);
132    if (!cbdata->handler)
133      {
134         ecore_main_fd_handler_del(cbdata->fdh);
135         free(cbdata);
136         close(fd[0]);
137         close(fd[1]);
138         return 0;
139      }
140    dns_slaves = _ecore_list2_append(dns_slaves, cbdata);
141    return 1;
142 }
143
144 static void
145 _ecore_con_dns_readdata(CB_Data *cbdata)
146 {
147    struct hostent he;
148    struct in_addr addr;
149    char *addr2;
150    ssize_t size;
151
152    size = read(ecore_main_fd_handler_fd_get(cbdata->fdh), &(addr.s_addr),
153                sizeof(in_addr_t));
154    if (size == sizeof(in_addr_t))
155      {
156         addr2 = (char *)&addr;
157         he.h_addrtype = AF_INET;
158         he.h_length = sizeof(in_addr_t);
159         he.h_addr_list = &addr2;
160         cbdata->cb_done(cbdata->data, &he);
161      }
162    else
163      cbdata->cb_done(cbdata->data, NULL);
164    cbdata->cb_done = NULL;
165 }
166
167 static void
168 _ecore_con_dns_slave_free(CB_Data *cbdata)
169 {
170    dns_slaves = _ecore_list2_remove(dns_slaves, cbdata);
171    close(ecore_main_fd_handler_fd_get(cbdata->fdh));
172    close(cbdata->fd2);
173    ecore_main_fd_handler_del(cbdata->fdh);
174    ecore_event_handler_del(cbdata->handler);
175    free(cbdata);
176 }
177
178 static int
179 _ecore_con_dns_data_handler(void *data, Ecore_Fd_Handler *fd_handler)
180 {
181    CB_Data *cbdata;
182
183    cbdata = data;
184    if (cbdata->cb_done)
185      {
186         if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
187           _ecore_con_dns_readdata(cbdata);
188         else
189           {
190              cbdata->cb_done(cbdata->data, NULL);
191              cbdata->cb_done = NULL;
192           }
193      }
194    _ecore_con_dns_slave_free(cbdata);
195    return 0;
196 }
197
198 static int
199 _ecore_con_dns_exit_handler(void *data, int type __UNUSED__, void *event)
200 {
201    CB_Data *cbdata;
202    Ecore_Exe_Event_Del *ev;
203    
204    ev = event;
205    cbdata = data;
206    if (cbdata->pid != ev->pid) return 1;
207    return 0;
208    _ecore_con_dns_slave_free(cbdata);
209    return 0;
210 }