minor async DNS cleanups
[ira/wip.git] / source3 / nmbd / asyncdns.c
1 /*
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    a async DNS handler
5    Copyright (C) Andrew Tridgell 1994-1997
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21    Revision History:
22
23    14 jan 96: lkcl@pires.co.uk
24    added multiple workgroup domain master support
25
26 */
27
28 #include "includes.h"
29
30 extern int DEBUGLEVEL;
31
32
33 /***************************************************************************
34   add a DNS result to the name cache
35   ****************************************************************************/
36 static struct name_record *add_dns_result(struct nmb_name *question, struct in_addr addr)
37 {
38   int name_type = question->name_type;
39   char *qname = question->name;
40
41   if (!addr.s_addr) {
42     /* add the fail to WINS cache of names. give it 1 hour in the cache */
43     DEBUG(3,("Negative DNS answer for %s\n", qname));
44     add_netbios_entry(wins_client_subnet,qname,name_type,NB_ACTIVE,60*60,
45                       DNSFAIL,addr,True);
46     return NULL;
47   }
48
49   /* add it to our WINS cache of names. give it 2 hours in the cache */
50   DEBUG(3,("DNS gave answer for %s of %s\n", qname, inet_ntoa(addr)));
51
52   return add_netbios_entry(wins_client_subnet,qname,name_type,NB_ACTIVE,
53                            2*60*60,DNS,addr, True);
54 }
55
56
57
58 #ifndef SYNC_DNS
59
60 static int fd_in = -1, fd_out = -1;
61 static int child_pid = -1;
62 static int in_dns;
63
64 /* this is the structure that is passed between the parent and child */
65 struct query_record {
66         struct nmb_name name;
67         struct in_addr result;
68 };
69
70 /* a queue of pending requests waiting for DNS responses */
71 static struct packet_struct *dns_queue;
72
73
74
75 /***************************************************************************
76   return the fd used to gather async dns replies. This is added to the select
77   loop
78   ****************************************************************************/
79 int asyncdns_fd(void)
80 {
81         return fd_in;
82 }
83
84 /***************************************************************************
85   handle DNS queries arriving from the parent
86   ****************************************************************************/
87 static void asyncdns_process(void)
88 {
89         struct query_record r;
90         fstring qname;
91
92         DEBUGLEVEL = -1;
93
94         while (1) {
95                 if (read_data(fd_in, (char *)&r, sizeof(r)) != sizeof(r)) 
96                         break;
97
98                 fstrcpy(qname, r.name.name);
99
100                 r.result.s_addr = interpret_addr(qname);
101
102                 if (write_data(fd_out, (char *)&r, sizeof(r)) != sizeof(r))
103                         break;
104         }
105
106         _exit(0);
107 }
108
109
110 /***************************************************************************
111   create a child process to handle DNS lookups
112   ****************************************************************************/
113 void start_async_dns(void)
114 {
115         int fd1[2], fd2[2];
116
117         signal(SIGCLD, SIG_IGN);
118
119         if (pipe(fd1) || pipe(fd2)) {
120                 return;
121         }
122
123         child_pid = fork();
124
125         if (child_pid) {
126                 fd_in = fd1[0];
127                 fd_out = fd2[1];
128                 close(fd1[1]);
129                 close(fd2[0]);
130                 return;
131         }
132
133         fd_in = fd2[0];
134         fd_out = fd1[1];
135
136         asyncdns_process();
137 }
138
139
140 /***************************************************************************
141 check if a particular name is already being queried
142   ****************************************************************************/
143 static BOOL query_in_queue(struct query_record *r)
144 {
145         struct packet_struct *p;
146         for (p = dns_queue; p; p = p->next) {
147                 struct nmb_packet *nmb = &p->packet.nmb;
148                 struct nmb_name *question = &nmb->question.question_name;
149
150                 if (name_equal(question, &r->name)) 
151                         return True;
152         }
153         return False;
154 }
155
156
157 /***************************************************************************
158   check the DNS queue
159   ****************************************************************************/
160 void run_dns_queue(void)
161 {
162         struct query_record r;
163         struct packet_struct *p, *p2;
164
165         if (fd_in == -1)
166                 return;
167
168         if (read_data(fd_in, (char *)&r, sizeof(r)) != sizeof(r)) {
169                 DEBUG(0,("Incomplete DNS answer from child!\n"));
170                 fd_in = -1;
171                 return;
172         }
173
174         add_dns_result(&r.name, r.result);
175
176         /* loop over the whole dns queue looking for entries that
177            match the result we just got */
178         for (p = dns_queue; p;) {
179                 struct nmb_packet *nmb = &p->packet.nmb;
180                 struct nmb_name *question = &nmb->question.question_name;
181
182                 if (name_equal(question, &r.name)) {
183                         DEBUG(3,("DNS calling reply_name_query\n"));
184                         in_dns = 1;
185                         reply_name_query(p);
186                         in_dns = 0;
187                         p->locked = False;
188
189                         if (p->prev)
190                                 p->prev->next = p->next;
191                         else
192                                 dns_queue = p->next;
193                         if (p->next)
194                                 p->next->prev = p->prev;
195                         p2 = p->next;
196                         free_packet(p);
197                         p = p2;
198                 } else {
199                         p = p->next;
200                 }
201         }
202
203 }
204
205 /***************************************************************************
206 queue a DNS query
207   ****************************************************************************/
208 BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
209                      struct name_record **n)
210 {
211         struct query_record r;
212         
213         if (in_dns || fd_in == -1)
214                 return False;
215
216         r.name = *question;
217
218         if (!query_in_queue(&r) && 
219             !write_data(fd_out, (char *)&r, sizeof(r))) {
220                 DEBUG(3,("failed to send DNS query to child!\n"));
221                 return False;
222         }
223
224         p->locked = True;
225         p->next = dns_queue;
226         p->prev = NULL;
227         if (p->next)
228                 p->next->prev = p;
229         dns_queue = p;
230
231
232         DEBUG(3,("added DNS query for %s\n", namestr(question)));
233         return True;
234 }
235
236 #else
237
238
239 /***************************************************************************
240   we use this then we can't do async DNS lookups
241   ****************************************************************************/
242 BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
243                      struct name_record **n)
244 {
245         int name_type = question->name_type;
246         char *qname = question->name;
247         struct in_addr dns_ip;
248
249         DEBUG(3,("DNS search for %s - ", namestr(question)));
250
251         dns_ip.s_addr = interpret_addr(qname);
252
253         *n = add_dns_result(question, dns_ip);
254         return False;
255 }
256 #endif