catch signals in the async dns daemon and allow it to auto-restart if
[Samba.git] / source3 / nmbd / asyncdns.c
blob57d0eda9b36601f3050e09f2b3384d048cbd2323
1 /*
2 Unix SMB/Netbios implementation.
3 a async DNS handler
4 Copyright (C) Andrew Tridgell 1997
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "includes.h"
23 extern int DEBUGLEVEL;
26 /***************************************************************************
27 add a DNS result to the name cache
28 ****************************************************************************/
29 static struct name_record *add_dns_result(struct nmb_name *question, struct in_addr addr)
31 int name_type = question->name_type;
32 char *qname = question->name;
34 if (!addr.s_addr) {
35 /* add the fail to WINS cache of names. give it 1 hour in the cache */
36 DEBUG(3,("Negative DNS answer for %s\n", qname));
37 add_netbios_entry(wins_client_subnet,qname,name_type,NB_ACTIVE,60*60,
38 DNSFAIL,addr,True);
39 return NULL;
42 /* add it to our WINS cache of names. give it 2 hours in the cache */
43 DEBUG(3,("DNS gave answer for %s of %s\n", qname, inet_ntoa(addr)));
45 return add_netbios_entry(wins_client_subnet,qname,name_type,NB_ACTIVE,
46 2*60*60,DNS,addr, True);
51 #ifndef SYNC_DNS
53 static int fd_in = -1, fd_out = -1;
54 static int child_pid = -1;
55 static int in_dns;
57 /* this is the structure that is passed between the parent and child */
58 struct query_record {
59 struct nmb_name name;
60 struct in_addr result;
63 /* a queue of pending requests waiting to be sent to the DNS child */
64 static struct packet_struct *dns_queue;
66 /* the packet currently being processed by the dns child */
67 static struct packet_struct *dns_current;
70 /***************************************************************************
71 return the fd used to gather async dns replies. This is added to the select
72 loop
73 ****************************************************************************/
74 int asyncdns_fd(void)
76 return fd_in;
79 /***************************************************************************
80 handle DNS queries arriving from the parent
81 ****************************************************************************/
82 static void asyncdns_process(void)
84 struct query_record r;
85 fstring qname;
87 DEBUGLEVEL = -1;
89 while (1) {
90 if (read_data(fd_in, (char *)&r, sizeof(r)) != sizeof(r))
91 break;
93 fstrcpy(qname, r.name.name);
95 r.result.s_addr = interpret_addr(qname);
97 if (write_data(fd_out, (char *)&r, sizeof(r)) != sizeof(r))
98 break;
101 _exit(0);
105 /***************************************************************************
106 create a child process to handle DNS lookups
107 ****************************************************************************/
108 void start_async_dns(void)
110 int fd1[2], fd2[2];
112 signal(SIGCLD, SIG_IGN);
114 if (pipe(fd1) || pipe(fd2)) {
115 return;
118 child_pid = fork();
120 if (child_pid) {
121 fd_in = fd1[0];
122 fd_out = fd2[1];
123 close(fd1[1]);
124 close(fd2[0]);
125 return;
128 fd_in = fd2[0];
129 fd_out = fd1[1];
131 signal(SIGUSR2, SIG_IGN);
132 signal(SIGUSR1, SIG_IGN);
133 signal(SIGHUP, SIG_IGN);
135 asyncdns_process();
139 /***************************************************************************
140 check if a particular name is already being queried
141 ****************************************************************************/
142 static BOOL query_current(struct query_record *r)
144 return dns_current &&
145 name_equal(&r->name,
146 &dns_current->packet.nmb.question.question_name);
150 /***************************************************************************
151 write a query to the child process
152 ****************************************************************************/
153 static BOOL write_child(struct packet_struct *p)
155 struct query_record r;
157 r.name = p->packet.nmb.question.question_name;
159 return write_data(fd_out, (char *)&r, sizeof(r)) == sizeof(r);
162 /***************************************************************************
163 check the DNS queue
164 ****************************************************************************/
165 void run_dns_queue(void)
167 struct query_record r;
168 struct packet_struct *p, *p2;
169 int size;
171 if (fd_in == -1)
172 return;
174 if (!process_exists(child_pid)) {
175 close(fd_in);
176 start_async_dns();
179 if ((size=read_data(fd_in, (char *)&r, sizeof(r))) != sizeof(r)) {
180 if (size) {
181 DEBUG(0,("Incomplete DNS answer from child!\n"));
182 fd_in = -1;
184 return;
187 add_dns_result(&r.name, r.result);
189 if (dns_current) {
190 if (query_current(&r)) {
191 DEBUG(3,("DNS calling reply_name_query\n"));
192 in_dns = 1;
193 reply_name_query(dns_current);
194 in_dns = 0;
197 dns_current->locked = False;
198 free_packet(dns_current);
199 dns_current = NULL;
202 /* loop over the whole dns queue looking for entries that
203 match the result we just got */
204 for (p = dns_queue; p;) {
205 struct nmb_packet *nmb = &p->packet.nmb;
206 struct nmb_name *question = &nmb->question.question_name;
208 if (name_equal(question, &r.name)) {
209 DEBUG(3,("DNS calling reply_name_query\n"));
210 in_dns = 1;
211 reply_name_query(p);
212 in_dns = 0;
213 p->locked = False;
215 if (p->prev)
216 p->prev->next = p->next;
217 else
218 dns_queue = p->next;
219 if (p->next)
220 p->next->prev = p->prev;
221 p2 = p->next;
222 free_packet(p);
223 p = p2;
224 } else {
225 p = p->next;
229 if (dns_queue) {
230 dns_current = dns_queue;
231 dns_queue = dns_queue->next;
232 if (dns_queue) dns_queue->prev = NULL;
233 dns_current->next = NULL;
235 if (!write_child(dns_current)) {
236 DEBUG(3,("failed to send DNS query to child!\n"));
237 return;
243 /***************************************************************************
244 queue a DNS query
245 ****************************************************************************/
246 BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
247 struct name_record **n)
249 if (in_dns || fd_in == -1)
250 return False;
252 if (!dns_current) {
253 if (!write_child(p)) {
254 DEBUG(3,("failed to send DNS query to child!\n"));
255 return False;
257 dns_current = p;
258 p->locked = True;
259 } else {
260 p->locked = True;
261 p->next = dns_queue;
262 p->prev = NULL;
263 if (p->next)
264 p->next->prev = p;
265 dns_queue = p;
268 DEBUG(3,("added DNS query for %s\n", namestr(question)));
269 return True;
272 #else
275 /***************************************************************************
276 we use this then we can't do async DNS lookups
277 ****************************************************************************/
278 BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
279 struct name_record **n)
281 char *qname = question->name;
282 struct in_addr dns_ip;
284 DEBUG(3,("DNS search for %s - ", namestr(question)));
286 dns_ip.s_addr = interpret_addr(qname);
288 *n = add_dns_result(question, dns_ip);
289 return False;
291 #endif