chiark / gitweb /
Ignore more manpages
[mLib] / bres.c
CommitLineData
a759efa6 1/* -*-c-*-
2 *
364308dc 3 * $Id: bres.c,v 1.5 2001/02/03 16:21:08 mdw Exp $
a759efa6 4 *
5 * Background reverse name resolution
6 *
7 * (c) 1999 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of the mLib utilities library.
13 *
14 * mLib is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * mLib 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 Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with mLib; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30/*----- Revision history --------------------------------------------------*
31 *
32 * $Log: bres.c,v $
364308dc 33 * Revision 1.5 2001/02/03 16:21:08 mdw
34 * Bug fixes: restore signals to their default dispositions, and set up the
35 * addresses properly when unpacking @hostent@ structures.
36 *
d8fe3fc2 37 * Revision 1.4 2000/08/15 17:35:02 mdw
38 * (gethost, and others): Since @gethost@ actually uses @malloc@ rather
39 * than @xmalloc@, it's wrong to use @xfree@ on the result. Fixed the code
40 * to use the right freeing function on the right data.
41 *
e2a18bd0 42 * Revision 1.3 2000/06/17 10:38:35 mdw
43 * Track changes to selbuf interface.
44 *
6c3a7cf7 45 * Revision 1.2 1999/10/30 11:28:39 mdw
46 * Fix include error, pointed out by Chris Rutter.
47 *
a759efa6 48 * Revision 1.1 1999/10/04 21:40:42 mdw
49 * Added background resolver from `fw'.
50 *
51 */
52
53/*----- Header files ------------------------------------------------------*/
54
55#include <errno.h>
56#include <signal.h>
57#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60
61#include <sys/types.h>
62#include <sys/time.h>
63#include <unistd.h>
64#include <sys/wait.h>
65
66#include <sys/socket.h>
67#include <netinet/in.h>
68#include <arpa/inet.h>
69#include <netdb.h>
70
6c3a7cf7 71#include "alloc.h"
a759efa6 72#include "bres.h"
6c3a7cf7 73#include "report.h"
74#include "sel.h"
a759efa6 75
76/*----- Magic numbers -----------------------------------------------------*/
77
78#define BRES_MAX 15 /* Maximum number of resolvers */
79#define BRES_IDLE 60 /* Lifetime of an idle resolver */
80
81/*----- Static variables --------------------------------------------------*/
82
83#ifndef BRES_STANDALONE
84
85static bres_server servers[BRES_MAX]; /* Statically allocated servers */
86
87#define FREE ((bres_server *)&freelist)
88static struct { bres_server *next, *prev; } freelist = { FREE, FREE };
89
90#define QUEUE ((bres_client *)&queue)
91static struct { bres_client *next, *prev; } queue = { QUEUE, QUEUE };
92
93static sel_state *sel;
94
95static const char *server = 0;
96
97#endif
98
99/*----- Background resolver protocol --------------------------------------*/
100
101/* --- Requests and responses --- *
102 *
103 * There are two types of requests: name and addr, corresponding to the
104 * standard @gethostbyname@ and @gethostbyaddr@ calls. There are two types
105 * of responses too: a positive response consists of an encoded equivalent of
106 * a @struct hostent@ structure containing the requested information; a
107 * negative response consists of an @h_errno@ value explaining the problem.
108 */
109
110#define BRES_BYNAME 0 /* Request: resolve given name */
111#define BRES_BYADDR 1 /* Request: resolve given address */
112
113#define BRES_HOSTENT 0 /* Response: resolved ok */
114#define BRES_ERROR 1 /* Response: resolution failed */
115
116/* --- Encodings --- *
117 *
118 * A string is encoded as a @size_t@ length followed by the actual data. The
119 * null terminator is not transmitted.
120 *
121 * Addresses for resolution are transmitted as raw @struct in_addr@
122 * structures.
123 *
124 * A @hostent@ structure is transmitted as a header containing fixed-size
125 * information, followed by the official name, an array of aliases, and an
126 * array of addresses. The number of items in the arrays is specified in the
127 * header.
128 *
129 * The implementation assumes that a complete request or reply is always
130 * sent. Undesirable blocking will occur if this is not the case. Both ends
131 * are assumed to trust each other. A protocol failure results in the child
132 * in question being terminated.
133 */
134
135typedef struct hostskel {
136 size_t nalias;
137 int addrtype;
138 size_t addrsz;
139 size_t naddr;
140} hostskel;
141
142/* --- @doread@, @dowrite@ --- *
143 *
144 * Arguments: @int fd@ = file descriptor
145 * @void *buf@ = buffer for data
146 * @size_t sz@ = size of data
147 *
148 * Returns: Zero if successful, nonzero otherwise.
149 *
150 * Use: Reads or writes a chunk of data. @EINTR@ errors are retried;
151 * incomplete reads and writes are continued from where they
152 * left off. End-of-file is considered an I/O error.
153 */
154
155static int doread(int fd, void *buf, size_t sz)
156{
157 char *p = buf;
158 while (sz) {
159 int r = read(fd, p, sz);
160 if (r < 0) {
161 if (errno == EINTR)
162 continue;
163 return (-1);
164 } else if (r == 0) {
165 errno = EIO;
166 return (-1);
167 }
168 sz -= r;
169 p += r;
170 }
171 return (0);
172}
173
174static int dowrite(int fd, const void *buf, size_t sz)
175{
176 const char *p = buf;
177 while (sz) {
178 int r = write(fd, p, sz);
179 if (r < 0) {
180 if (errno == EINTR)
181 continue;
182 return (-1);
183 } else if (r == 0) {
184 errno = EIO;
185 return (-1);
186 }
187 sz -= r;
188 p += r;
189 }
190 return (0);
191}
192
193/* --- @getstring@ --- *
194 *
195 * Arguments: @int fd@ = file descriptor to read
196 *
197 * Returns: String in heap-allocated block, or a null pointer.
198 *
199 * Use: Decodes a string.
200 */
201
202static char *getstring(int fd)
203{
204 size_t sz;
205 char *p;
206
207 if (doread(fd, &sz, sizeof(sz)) || (p = malloc(sz + 1)) == 0)
208 return (0);
209 if (doread(fd, p, sz)) {
210 free(p);
211 return (0);
212 }
213 p[sz] = 0;
214 return (p);
215}
216
217/* --- @putstring@ --- *
218 *
219 * Arguments: @int fd@ = file descriptor to write on
220 * @const char *p@ = pointer to string to write
221 *
222 * Returns: Zero if successful.
223 *
224 * Use: Encodes a string.
225 */
226
227static int putstring(int fd, const char *p)
228{
229 size_t sz = strlen(p);
230 if (dowrite(fd, &sz, sizeof(sz)) || dowrite(fd, p, sz))
231 return (-1);
232 return (0);
233}
234
235/* --- @gethost@ --- *
236 *
237 * Arguments: @int fd@ = file descriptor to read
238 *
239 * Returns: Pointer to heap-allocated @struct hostent@, or null.
240 *
241 * Use: Decodes a host structure. The resulting structure is all in
242 * one big heap block.
243 */
244
245#ifndef BRES_STANDALONE
246
247static struct hostent *gethost(int fd)
248{
249 hostskel hsk;
250 struct hostent *h;
251 char *name;
252 char **alias = 0;
253
254 /* --- Read the skeleton structure --- */
255
256 if (doread(fd, &hsk, sizeof(hsk)))
257 goto tidy_0;
258
259 /* --- Read the hostname and alias strings --- *
260 *
261 * Count the length of the strings as we go.
262 */
263
264 {
265 size_t sz =
266 sizeof(struct hostent) +
267 hsk.naddr * hsk.addrsz +
268 (hsk.naddr + hsk.nalias + 2) * sizeof(char *);
269
270 /* --- Read the primary host name --- */
271
272 if ((name = getstring(fd)) == 0)
273 goto tidy_0;
274 sz += strlen(name) + 1;
275
276 /* --- Read in the alias names --- */
277
278 if (hsk.nalias) {
279 int i;
280 if ((alias = malloc(hsk.nalias * sizeof(char *))) == 0)
281 goto tidy_1;
282 for (i = 0; i < hsk.nalias; i++)
283 alias[i] = 0;
284 for (i = 0; i < hsk.nalias; i++) {
285 if ((alias[i] = getstring(fd)) == 0)
286 goto tidy_2;
287 sz += strlen(alias[i]) + 1;
288 }
289 }
290
291 /* --- Allocate the output structure --- */
292
293 if ((h = malloc(sz)) == 0)
294 goto tidy_2;
295 }
296
297 /* --- Fill in the base structure --- */
298
299 h->h_addrtype = hsk.addrtype;
300 h->h_length = hsk.addrsz;
301
302 /* --- Start putting everything else in --- */
303
304 {
305 char **p = (char **)(h + 1);
306 char *a = (char *)(p + hsk.nalias + hsk.naddr + 2);
307 int i;
308
309 /* --- Start with the address table --- */
310
311 h->h_addr_list = p;
312 if (doread(fd, a, hsk.naddr * hsk.addrsz))
313 goto tidy_2;
314 for (i = 0; i < hsk.naddr; i++) {
a759efa6 315 *p++ = a;
364308dc 316 a += hsk.addrsz;
a759efa6 317 }
318 *p++ = 0;
319
320 /* --- Finally copy the strings over --- */
321
322#define PUT(_p) do { \
323 size_t _len = strlen(_p) + 1; \
324 memcpy(a, (_p), _len); \
325 a += _len; \
326} while (0)
327
328 h->h_name = a;
329 PUT(name);
d8fe3fc2 330 free(name);
a759efa6 331 h->h_aliases = p;
332 for (i = 0; i < hsk.nalias; i++) {
333 *p++ = a;
334 PUT(alias[i]);
d8fe3fc2 335 free(alias[i]);
a759efa6 336 }
337 *p++ = 0;
d8fe3fc2 338 free(alias);
a759efa6 339
340#undef PUT
341 }
342
343 return (h);
344
345 /* --- Tidy up after various types of failure --- */
346
347tidy_2:
348 {
349 int i;
350 for (i = 0; i < hsk.nalias && alias[i]; i++)
d8fe3fc2 351 free(alias[i]);
352 free(alias);
a759efa6 353 }
354tidy_1:
d8fe3fc2 355 free(name);
a759efa6 356tidy_0:
357 return (0);
358}
359
360#endif
361
362/* --- @puthost@ --- *
363 *
364 * Arguments: @int fd@ = file descriptor
365 * @struct hostent *h@ = pointer to host structure
366 *
367 * Returns: Zero if successful.
368 *
369 * Use: Encodes a host structure.
370 */
371
372static int puthost(int fd, struct hostent *h)
373{
374 hostskel hsk;
375 int i;
376
377 /* --- Fill in and send the skeleton structure --- */
378
379 for (i = 0; h->h_aliases[i]; i++)
380 ;
381 hsk.nalias = i;
382 for (i = 0; h->h_addr_list[i]; i++)
383 ;
384 hsk.naddr = i;
385 hsk.addrtype = h->h_addrtype;
386 hsk.addrsz = h->h_length;
387 if (dowrite(fd, &hsk, sizeof(hsk)))
388 return (-1);
389
390 /* --- Send the name and alias strings --- */
391
392 if (putstring(fd, h->h_name))
393 return (-1);
394 for (i = 0; h->h_aliases[i]; i++) {
395 if (putstring(fd, h->h_aliases[i]))
396 return (-1);
397 }
398
399 /* --- Send the address data --- */
400
401 for (i = 0; h->h_addr_list[i]; i++) {
402 if (dowrite(fd, h->h_addr_list[i], hsk.addrsz))
403 return (-1);
404 }
405
406 /* --- OK, done --- */
407
408 return (0);
409}
410
411/*----- Resolver server ---------------------------------------------------*/
412
413/* --- @child@ --- *
414 *
415 * Arguments: @int rfd@ = output file descriptor for resolved hostnames
416 * @int cfd@ = input file descriptor for raw addresses
417 *
418 * Returns: Never.
419 *
420 * Use: Asynchronous name resolving process.
421 */
422
423static void child(int rfd, int cfd)
424{
425 /* --- Close other file descriptors --- */
426
427 {
428 int i;
429 int maxfd = sysconf(_SC_OPEN_MAX);
430
431 if (maxfd < 0)
432 maxfd = 256; /* Fingers crossed... */
433 for (i = 0; i < maxfd; i++) {
434 if (i != rfd && i != cfd && i != 1)
435 close(i);
436 }
437 }
438
364308dc 439 signal(SIGTERM, SIG_DFL);
440 signal(SIGHUP, SIG_DFL);
441 signal(SIGQUIT, SIG_DFL);
442 signal(SIGALRM, SIG_DFL);
443 signal(SIGINT, SIG_DFL);
444
a759efa6 445 /* --- Main request/response loop --- */
446
447 for (;;) {
448 int req, resp;
449 struct hostent *h;
450
451 /* --- Read the request --- */
452
453 if (doread(cfd, &req, sizeof(req)))
454 goto lose;
455
456 /* --- Process it into a host structure --- */
457
458 switch (req) {
459
460 /* --- Normal forward lookup --- */
461
462 case BRES_BYNAME: {
463 char *name = getstring(cfd);
464 if (!name)
465 goto lose;
466 h = gethostbyname(name);
467 free(name);
468 } break;
469
d8fe3fc2 470 /* --- Reverse lookup --- */
a759efa6 471
472 case BRES_BYADDR: {
473 struct in_addr addr;
474 char *p;
475 if (doread(cfd, &addr, sizeof(addr)))
476 goto lose;
477 if ((h = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET)) == 0)
478 goto fail;
479
480 /* --- Do a forward lookup to confirm --- */
481
482 {
483 size_t sz = strlen(h->h_name) + 1;
484 if ((p = malloc(sz)) == 0)
485 goto fail;
486 memcpy(p, h->h_name, sz);
487 }
488
489 h = gethostbyname(p);
490 free(p);
491 if (!h)
492 goto fail;
493 p = 0;
494 if (h) {
495 char **pp;
496 for (pp = h->h_addr_list; *pp; pp++) {
497 struct in_addr a;
498 memcpy(&a, *pp, sizeof(a));
499 if (a.s_addr == addr.s_addr) {
500 p = h->h_name;
501 break;
502 }
503 }
504 }
505 if (!p) {
506 h = 0;
507 h_errno = NO_RECOVERY;
508 }
509 fail:;
510 } break;
511
512 /* --- Unknown request -- may have lost sync --- */
513
514 default:
515 goto lose;
516 }
517
518 /* --- Transmit the response --- */
519
520 if (h) {
521 resp = BRES_HOSTENT;
522 if (dowrite(rfd, &resp, sizeof(resp)) || puthost(rfd, h))
523 goto lose;
524 } else {
525 resp = BRES_ERROR;
526 if (dowrite(rfd, &resp, sizeof(resp)) ||
527 dowrite(rfd, &h_errno, sizeof(h_errno)))
528 goto lose;
529 }
530 }
531
532lose:
533 _exit(1);
534}
535
536/* --- @main@ --- *
537 *
538 * Arguments: @int argc@ = number of command line arguments
539 * @char *argv[]@ = array of arguments
540 *
541 * Returns: Runs until killed or an error occurs.
542 *
543 * Use: A name resolver server process for mLib programs which need
544 * this sort of thing.
545 */
546
547#ifdef BRES_STANDALONE
548
549int main(int argc, char *argv[])
550{
551 if (isatty(STDIN_FILENO)) {
552 char *p = strrchr(argv[0], '/');
553 if (p)
554 p++;
555 else
556 p = argv[0];
557 fprintf(stderr,
558 "%s: don't run this program unless you know what you're doing.\n",
559 p);
560 exit(1);
561 }
562 child(STDOUT_FILENO, STDIN_FILENO);
563 return (1);
564}
565
566#endif
567
568/*----- Main code ---------------------------------------------------------*/
569
570#ifndef BRES_STANDALONE
571
572/* --- @zap@ --- *
573 *
574 * Arguments: @bres_server *rs@ = pointer to server block
575 *
576 * Returns: ---
577 *
578 * Use: Kills a server process, reaps the losing child and makes
579 * things generally clean again.
580 */
581
582static void zap(bres_server *rs)
583{
584 /* --- Close the pipes, kill the child, and reap it --- */
585
586 if (rs->kid != -1) {
587 close(rs->fd);
588 close(rs->f.fd);
589 kill(rs->kid, SIGTERM);
590 waitpid(rs->kid, 0, 0);
591 rs->kid = -1;
592 }
593
594 /* --- Move the server to the back of the list --- */
595
596 rs->next->prev = rs->prev;
597 rs->prev->next = rs->next;
598 rs->next = FREE;
599 rs->prev = FREE->prev;
600 FREE->prev->next = rs;
601 FREE->prev = rs;
602}
603
604/* --- @bres_abort@ --- *
605 *
606 * Arguments: @bres_client *rc@ = pointer to client block
607 *
608 * Returns: ---
609 *
610 * Use: Removes a queued job.
611 */
612
613void bres_abort(bres_client *rc)
614{
615 if (rc->q == BRES_BYNAME)
e2a18bd0 616 xfree(rc->u.name);
a759efa6 617 if (rc->rs) {
618 sel_rmfile(&rc->rs->f);
619 zap(rc->rs);
620 rc->rs = 0;
621 } else {
622 rc->next->prev = rc->prev;
623 rc->prev->next = rc->next;
624 }
625}
626
627/* --- @idle@ --- *
628 *
629 * Arguments: @struct timeval *tv@ = pointer to the current time
630 * @void *vp@ = pointer to a server block
631 *
632 * Returns: ---
633 *
634 * Use: Kills off a child which has been idle for too long.
635 */
636
637static void idle(struct timeval *tv, void *vp)
638{
639 bres_server *rs = vp;
640 zap(rs);
641}
642
643/* --- @answer@ --- *
644 *
645 * Arguments: @int fd@ = file descriptor which is ready
646 * @unsigned mode@ = what it's doing now
647 * @void *vp@ = pointer to server block
648 *
649 * Returns: ---
650 *
651 * Use: Retrieves an answer from a name resolver process.
652 */
653
654static void attach(bres_client */*rc*/);
655
656static void answer(int fd, unsigned mode, void *vp)
657{
658 bres_server *rs = vp;
659 bres_client *rc = rs->rc;
660 struct hostent *h = 0;
661 int resp;
662 int fail = 1;
663
664 /* --- Report the result to my client --- */
665
666 sel_rmfile(&rs->f);
667 h_errno = -1;
668 if (doread(fd, &resp, sizeof(resp)) == 0) {
669 switch (resp) {
670 case BRES_ERROR:
671 doread(fd, &h_errno, sizeof(h_errno));
672 fail = 0;
673 break;
674 case BRES_HOSTENT:
675 h = gethost(fd);
676 fail = 0;
677 break;
678 }
679 }
680 if (rc) {
681 rc->func(h, rc->p);
682 if (rc->q == BRES_BYNAME)
e2a18bd0 683 xfree(rc->u.name);
a759efa6 684 }
685 if (h)
d8fe3fc2 686 free(h);
a759efa6 687 if (fail)
688 zap(rs);
689 if (!rc)
690 return;
691
692 /* --- Wrap up the various structures --- */
693
694 rs->rc = 0;
695 rc->rs = 0;
696 rs->next = FREE->next;
697 rs->prev = FREE;
698 FREE->next->prev = rs;
699 FREE->next = rs;
700
701 /* --- Tie a timer onto the server block --- */
702
703 {
704 struct timeval tv;
705
706 gettimeofday(&tv, 0);
707 tv.tv_sec += BRES_IDLE;
708 sel_addtimer(sel, &rs->t, &tv, idle, rs);
709 }
710
711 /* --- If there are any clients waiting, attach one --- */
712
713 if (QUEUE->next != QUEUE) {
714 rc = QUEUE->next;
715 QUEUE->next = rc->next;
716 rc->next->prev = QUEUE;
717 attach(rc);
718 }
719}
720
721/* --- @start@ --- *
722 *
723 * Arguments: @bres_server *rs@ = pointer to a server block
724 *
725 * Returns: Zero if OK, nonzero if something failed.
726 *
727 * Use: Starts up a child resolver process.
728 */
729
730static int start(bres_server *rs)
731{
732 int rfd[2], cfd[2];
733 pid_t kid;
734
735 /* --- Make the pipes --- */
736
737 if (pipe(rfd))
738 goto fail_0;
739 if (pipe(cfd))
740 goto fail_1;
741
742 /* --- Start up the child process --- */
743
744 if ((kid = fork()) < 0)
745 goto fail_2;
746 if (kid == 0) {
747 close(cfd[1]);
748 close(rfd[0]);
749
750 if (server) {
751 dup2(cfd[0], STDIN_FILENO);
752 dup2(rfd[1], STDOUT_FILENO);
753 close(cfd[0]);
754 close(rfd[1]);
755 execlp(server, server, (char *)0);
756 child(STDOUT_FILENO, STDIN_FILENO);
757 } else
758 child(rfd[1], cfd[0]);
759 _exit(1);
760 }
761
762 /* --- Fix up everything in the server block --- */
763
764 close(cfd[0]);
765 close(rfd[1]);
766 rs->fd = cfd[1];
767 sel_initfile(sel, &rs->f, rfd[0], SEL_READ, answer, rs);
768 rs->kid = kid;
769 return (0);
770
771 /* --- Fix up after errors --- */
772
773fail_2:
774 close(cfd[0]);
775 close(cfd[1]);
776fail_1:
777 close(rfd[0]);
778 close(rfd[1]);
779fail_0:
780 return (-1);
781}
782
783/* --- @attach@ --- *
784 *
785 * Arguments: @bres_client *rc@ = pointer to a client block
786 *
787 * Returns: ---
788 *
789 * Use: Attaches a client to a spare server (which is assumed to
790 * exist).
791 */
792
793static void attach(bres_client *rc)
794{
795 bres_server *rs;
796 int lose = 0;
797
798 /* --- Fix up the server ready for the job --- *
799 *
800 * If the server has a process, remove its timer. Otherwise, fork off a
801 * new resolver process. This is also where I go if I find that the child
802 * resolver process has lost while I wasn't looking. Only one attempt at
803 * forking is performed.
804 */
805
806again:
807 rs = FREE->next;
808 if (rs->kid != -1)
809 sel_rmtimer(&rs->t);
810 else {
811 if (lose || start(rs))
812 goto lost;
813 lose = 1;
814 }
815
816 /* --- Submit the job to the resolver --- */
817
818 {
819 struct sigaction sa, osa;
820 int e;
821
822 /* --- Ignore @SIGPIPE@ for now --- *
823 *
824 * This way I can trap @EPIPE@ and reap a losing child, if there was one.
825 */
826
827 sa.sa_handler = SIG_IGN;
828 sa.sa_flags = 0;
829 sigemptyset(&sa.sa_mask);
830 sigaction(SIGPIPE, &sa, &osa);
831
832 /* --- Write the new job to the child --- */
833
834 e = 0;
835 if (dowrite(rs->fd, &rc->q, sizeof(rc->q)))
836 e = errno;
837 else switch (rc->q) {
838 case BRES_BYADDR:
839 if (dowrite(rs->fd, &rc->u.addr, sizeof(rc->u.addr)))
840 e = errno;
841 break;
842 case BRES_BYNAME:
843 if (putstring(rs->fd, rc->u.name))
844 e = errno;
845 break;
846 }
847 sigaction(SIGPIPE, &osa, 0);
848
849 /* --- Sort out various errors --- *
850 *
851 * This was once more complicated, handling @EPIPE@ separately from other
852 * errors. Now everything's handled the same way.
853 */
854
855 if (e) {
856 zap(rs);
857 goto again;
858 }
859 }
860
861 /* --- Fiddle with lists so that everything's OK --- */
862
863 sel_addfile(&rs->f);
864 rs->next->prev = FREE;
865 FREE->next = rs->next;
866 rs->next = rs->prev = rs;
867 rs->rc = rc;
868 rc->rs = rs;
869 return;
870
871lost:
872 rc->func(0, rc->p);
873 if (rc->q == BRES_BYNAME)
e2a18bd0 874 xfree(rc->u.name);
a759efa6 875}
876
877/* --- @resolve@ --- *
878 *
879 * Arguments: @bres_client *rc@ = pointer to filled-in client block
880 *
881 * Returns: ---
882 *
883 * Use: Dispatcher for incoming resolution jobs.
884 */
885
886static void resolve(bres_client *rc)
887{
888 /* --- If there's a free server, plug it in --- */
889
890 rc->rs = 0;
891 if (FREE->next == FREE) {
892 rc->next = QUEUE;
893 rc->prev = QUEUE->prev;
894 QUEUE->prev->next = rc;
895 QUEUE->prev = rc;
896 } else
897 attach(rc);
898}
899
900/* --- @bres_byaddr@ --- *
901 *
902 * Arguments: @bres_client *rc@ = pointer to client block
903 * @struct in_addr addr@ = address to resolve
904 * @void (*func)(struct hostent *h, void *p)@ = handler function
905 * @void *p@ = argument for handler function
906 *
907 * Returns: ---
908 *
909 * Use: Adds an address lookup job to the queue. The job will be
910 * processed when there's a spare resolver process to deal with
911 * it.
912 */
913
914void bres_byaddr(bres_client *rc, struct in_addr addr,
915 void (*func)(struct hostent */*h*/, void */*p*/),
916 void *p)
917{
918 rc->q = BRES_BYADDR;
919 rc->u.addr = addr;
920 rc->func = func;
921 rc->p = p;
922 resolve(rc);
923}
924
925/* --- @bres_byname@ --- *
926 *
927 * Arguments: @bres_client *rc@ = pointer to client block
928 * @const char *name@ = name to resolve
929 * @void (*func)(struct hostent *h, void *p)@ = handler function
930 * @void *p@ = argument for handler function
931 *
932 * Returns: ---
933 *
934 * Use: Adds a name lookup job to the queue. The job will be
935 * processed when there's a spare resolver process to deal with
936 * it.
937 */
938
939void bres_byname(bres_client *rc, const char *name,
940 void (*func)(struct hostent */*h*/, void */*p*/),
941 void *p)
942{
943 rc->q = BRES_BYNAME;
944 rc->u.name = xstrdup(name);
945 rc->func = func;
946 rc->p = p;
947 resolve(rc);
948}
949
950/* --- @bres_exec@ --- *
951 *
952 * Arguments: @const char *file@ = file containing server code or null
953 *
954 * Returns: ---
955 *
956 * Use: Makes `bres' use a standalone server rather than copies of
957 * the current process. This can reduce memory consumption for
958 * large processes, at the expense of startup time (which
959 * shouldn't be too bad anyway, because of the resolver design).
960 * If the filename is null, a default set up at install time is
961 * used. It's probably a good idea to leave it alone.
962 */
963
964void bres_exec(const char *file)
965{
966 if (file)
967 server = file;
968 else
969 server = BRES_SERVER;
970}
971
972/* --- @bres_init@ --- *
973 *
974 * Arguments: @sel_state *s@ = pointer to select multiplexor
975 *
976 * Returns: ---
977 *
978 * Use: Initializes the background resolver for use.
979 */
980
981void bres_init(sel_state *s)
982{
983 int i;
984
985 sel = s;
986 for (i = 0; i < BRES_MAX; i++) {
987 servers[i].next = FREE;
988 servers[i].prev = FREE->prev;
989 servers[i].kid = -1;
990 servers[i].rc = 0;
991 FREE->prev->next = &servers[i];
992 FREE->prev = &servers[i];
993 }
994}
995
996#endif
997
998/*----- That's all, folks -------------------------------------------------*/