3 * $Id: bres.c,v 1.2 1999/07/03 13:56:04 mdw Exp $
5 * Background reverse name resolution
7 * (c) 1999 Mark Wooding
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of the `fw' port forwarder.
14 * `fw' is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * `fw' is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with `fw'; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 /*----- Revision history --------------------------------------------------*
32 * Revision 1.2 1999/07/03 13:56:04 mdw
33 * Perform a forward resolution to verify result of reverse lookup.
35 * Revision 1.1.1.1 1999/07/01 08:56:23 mdw
40 /*----- Header files ------------------------------------------------------*/
48 #include <sys/types.h>
53 #include <sys/socket.h>
54 #include <netinet/in.h>
55 #include <arpa/inet.h>
58 #include <mLib/alloc.h>
59 #include <mLib/report.h>
61 #include <mLib/selbuf.h>
65 /*----- Magic numbers -----------------------------------------------------*/
67 #define BRES_MAX 5 /* Maximum number of resolvers */
68 #define BRES_IDLE 60 /* Lifetime of an idle resolver */
70 /*----- Static variables --------------------------------------------------*/
72 static bres_server servers[BRES_MAX]; /* Statically allocated servers */
74 #define FREE ((bres_server *)&freelist)
75 static struct { bres_server *next, *prev; } freelist = { FREE, FREE };
77 #define QUEUE ((bres_client *)&queue)
78 static struct { bres_client *next, *prev; } queue = { QUEUE, QUEUE };
80 static sel_state *sel;
82 /*----- Main code ---------------------------------------------------------*/
86 * Arguments: @bres_server *rs@ = pointer to server block
90 * Use: Kills a server process, reaps the losing child and makes
91 * things generally clean again.
94 static void zap(bres_server *rs)
96 /* --- Close the pipes, kill the child, and reap it --- */
99 selbuf_disable(&rs->b);
101 close(rs->b.reader.fd);
102 kill(rs->kid, SIGTERM);
103 waitpid(rs->kid, 0, 0);
107 /* --- Move the server to the back of the list --- */
109 rs->next->prev = rs->prev;
110 rs->prev->next = rs->next;
112 rs->prev = FREE->prev;
113 FREE->prev->next = rs;
117 /* --- @bres_abort@ --- *
119 * Arguments: @bres_client *rc@ = pointer to client block
123 * Use: Removes a queued job.
126 void bres_abort(bres_client *rc)
132 rc->next->prev = rc->prev;
133 rc->prev->next = rc->next;
139 * Arguments: @int rfd@ = output file descriptor for resolved hostnames
140 * @int cfd@ = input file descriptor for raw addresses
144 * Use: Asynchronous name resolving process.
147 static void child(int rfd, int cfd)
150 FILE *fp = fdopen(rfd, "w");
154 int maxfd = sysconf(_SC_OPEN_MAX);
156 for (i = 0; i < maxfd; i++) {
157 if (i != rfd && i != cfd)
163 int r = read(cfd, &addr, sizeof(addr));
169 else if (r != sizeof(addr))
172 h = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
176 p = xstrdup(h->h_name);
177 h = gethostbyname(p);
181 for (pp = h->h_addr_list; *pp; pp++) {
183 memcpy(&a, *pp, sizeof(a));
184 if (a.s_addr == addr.s_addr) {
194 fprintf(fp, "%s\n", p);
202 * Arguments: @struct timeval *tv@ = pointer to the current time
203 * @void *vp@ = pointer to a server block
207 * Use: Kills off a child which has been idle for too long.
210 static void idle(struct timeval *tv, void *vp)
212 bres_server *rs = vp;
216 /* --- @answer@ --- *
218 * Arguments: @char *p@ = pointer to string read
219 * @void *vp@ = pointer to server block
223 * Use: Retrieves an answer from a name resolver process.
226 static void attach(bres_client */*rc*/);
228 static void answer(char *p, void *vp)
230 bres_server *rs = vp;
231 bres_client *rc = rs->rc;
233 /* --- Report the result to my client --- */
242 /* --- Wrap up the various structures --- */
246 rs->next = FREE->next;
248 FREE->next->prev = rs;
251 /* --- Tie a timer onto the server block --- */
256 gettimeofday(&tv, 0);
257 tv.tv_sec += BRES_IDLE;
258 sel_addtimer(sel, &rs->t, &tv, idle, rs);
261 /* --- If there are any clients waiting, attach one --- */
263 if (QUEUE->next != QUEUE) {
265 QUEUE->next = rc->next;
266 rc->next->prev = QUEUE;
273 * Arguments: @bres_server *rs@ = pointer to a server block
275 * Returns: Zero if OK, nonzero if something failed.
277 * Use: Starts up a child resolver process.
280 static int start(bres_server *rs)
285 /* --- Make the pipes --- */
292 /* --- Start up the child process --- */
294 if ((kid = fork()) < 0)
299 child(rfd[1], cfd[0]);
303 /* --- Fix up everything in the server block --- */
308 selbuf_init(&rs->b, sel, rfd[0], answer, rs);
312 /* --- Fix up after errors --- */
324 /* --- @attach@ --- *
326 * Arguments: @bres_client *rc@ = pointer to a client block
330 * Use: Attaches a client to a spare server (which is assumed to
334 static void attach(bres_client *rc)
339 /* --- Fix up the server ready for the job --- *
341 * If the server has a process, remove its timer. Otherwise, fork off a
342 * new resolver process. This is also where I go if I find that the child
343 * resolver process has lost while I wasn't looking. Only one attempt at
344 * forking is performed.
352 if (lose || start(rs))
357 /* --- Submit the job to the resolver --- */
360 struct sigaction sa, osa;
363 /* --- Ignore @SIGPIPE@ for now --- *
365 * This way I can trap @EPIPE@ and reap a losing child, if there was one.
368 sa.sa_handler = SIG_IGN;
370 sigemptyset(&sa.sa_mask);
371 sigaction(SIGPIPE, &sa, &osa);
373 /* --- Write the new job to the child --- */
376 if (write(rs->fd, &rc->addr, sizeof(rc->addr)) < 0)
378 sigaction(SIGPIPE, &osa, 0);
380 /* --- Sort out various errors --- */
389 /* --- Fiddle with lists so that everything's OK --- */
391 rs->next->prev = FREE;
392 FREE->next = rs->next;
393 rs->next = rs->prev = rs;
402 /* --- @bres_resolve@ --- *
404 * Arguments: @bres_client *rc@ = pointer to client block
405 * @struct in_addr addr@ = address to resolve
406 * @void (*func)(const char *host, void *p)@ = handler function
407 * @void *p@ = argument for handler function
411 * Use: Adds a resolver job to the queue. The job will be processed
412 * when there's a spare resolver process to deal with it.
415 void bres_resolve(bres_client *rc, struct in_addr addr,
416 void (*func)(const char */*host*/, void */*p*/), void *p)
418 /* --- Fill in the structure --- */
425 /* --- If there's a free server, plug it in --- */
427 if (FREE->next == FREE) {
429 rc->prev = QUEUE->prev;
430 QUEUE->prev->next = rc;
436 /* --- @bres_init@ --- *
438 * Arguments: @sel_state *s@ = pointer to select multiplexor
442 * Use: Initializes the background resolver for use.
445 void bres_init(sel_state *s)
450 for (i = 0; i < BRES_MAX; i++) {
451 servers[i].next = FREE;
452 servers[i].prev = FREE->prev;
455 FREE->prev->next = &servers[i];
456 FREE->prev = &servers[i];
460 /*----- That's all, folks -------------------------------------------------*/