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 -------------------------------------------------*/