Big change to make nmbd code more readable/understandable.
[metze/samba/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 = 0;
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                 DEBUG(3,("async DNS initialised\n"));
131                 return;
132         }
133
134         fd_in = fd2[0];
135         fd_out = fd1[1];
136
137         asyncdns_process();
138 }
139
140
141 /***************************************************************************
142 check if a particular name is already being queried
143   ****************************************************************************/
144 static BOOL query_in_queue(struct query_record *r)
145 {
146         struct packet_struct *p;
147         for (p = dns_queue; p; p = p->next) {
148                 struct nmb_packet *nmb = &p->packet.nmb;
149                 struct nmb_name *question = &nmb->question.question_name;
150
151                 if (name_equal(question, &r->name)) 
152                         return True;
153         }
154         return False;
155 }
156
157
158 /***************************************************************************
159   check the DNS queue
160   ****************************************************************************/
161 void run_dns_queue(void)
162 {
163         struct query_record r;
164         struct packet_struct *p, *p2;
165
166         if (fd_in == -1)
167                 return;
168
169         if (read_data(fd_in, (char *)&r, sizeof(r)) != sizeof(r)) {
170                 DEBUG(0,("Incomplete DNS answer from child!\n"));
171                 fd_in = -1;
172                 return;
173         }
174
175         add_dns_result(&r.name, r.result);
176
177         /* loop over the whole dns queue looking for entries that
178            match the result we just got */
179         for (p = dns_queue; p;) {
180                 struct nmb_packet *nmb = &p->packet.nmb;
181                 struct nmb_name *question = &nmb->question.question_name;
182
183                 if (name_equal(question, &r.name)) {
184                         DEBUG(3,("DNS calling reply_name_query\n"));
185                         in_dns = 1;
186                         reply_name_query(p);
187                         in_dns = 0;
188                         p->locked = False;
189
190                         if (p->prev)
191                                 p->prev->next = p->next;
192                         else
193                                 dns_queue = p->next;
194                         if (p->next)
195                                 p->next->prev = p->prev;
196                         p2 = p->next;
197                         free_packet(p);
198                         p = p2;
199                 } else {
200                         p = p->next;
201                 }
202         }
203
204 }
205
206 /***************************************************************************
207 queue a DNS query
208   ****************************************************************************/
209 BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
210                      struct name_record **n)
211 {
212         struct query_record r;
213         
214         if (in_dns || fd_in == -1)
215                 return False;
216
217         r.name = *question;
218
219         if (!query_in_queue(&r) && 
220             !write_data(fd_out, (char *)&r, sizeof(r))) {
221                 DEBUG(3,("failed to send DNS query to child!\n"));
222                 return False;
223         }
224
225         p->locked = True;
226         p->next = dns_queue;
227         p->prev = NULL;
228         if (p->next)
229                 p->next->prev = p;
230         dns_queue = p;
231
232
233         DEBUG(3,("added DNS query for %s\n", namestr(question)));
234         return True;
235 }
236
237 #else
238
239
240 /***************************************************************************
241   we use this then we can't do async DNS lookups
242   ****************************************************************************/
243 BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
244                      struct name_record **n)
245 {
246         int name_type = question->name_type;
247         char *qname = question->name;
248         struct in_addr dns_ip;
249
250         DEBUG(3,("DNS search for %s - ", namestr(question)));
251
252         dns_ip.s_addr = interpret_addr(qname);
253
254         *n = add_dns_result(question, dns_ip);
255         return False;
256 }
257 #endif