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