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