Infrastructure: Split the files into subdirectories.
[mLib] / sel / bres.c
1 /* -*-c-*-
2 *
3 * Background reverse name resolution
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the mLib utilities library.
11 *
12 * mLib is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * mLib is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with mLib; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include "config.h"
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
48 #include "alloc.h"
49 #include "bres.h"
50 #include "mdup.h"
51 #include "report.h"
52 #include "sel.h"
53
54 /*----- Magic numbers -----------------------------------------------------*/
55
56 #define BRES_MAX 15 /* Maximum number of resolvers */
57 #define BRES_IDLE 60 /* Lifetime of an idle resolver */
58
59 /*----- Static variables --------------------------------------------------*/
60
61 #ifndef BRES_STANDALONE
62
63 static bres_server servers[BRES_MAX]; /* Statically allocated servers */
64
65 #define FREE ((bres_server *)&freelist)
66 static struct { bres_server *next, *prev; } freelist = { FREE, FREE };
67
68 #define QUEUE ((bres_client *)&queue)
69 static struct { bres_client *next, *prev; } queue = { QUEUE, QUEUE };
70
71 static sel_state *sel;
72
73 static const char *server = 0;
74
75 #endif
76
77 /*----- Background resolver protocol --------------------------------------*/
78
79 /* --- Requests and responses --- *
80 *
81 * There are two types of requests: name and addr, corresponding to the
82 * standard @gethostbyname@ and @gethostbyaddr@ calls. There are two types
83 * of responses too: a positive response consists of an encoded equivalent of
84 * a @struct hostent@ structure containing the requested information; a
85 * negative response consists of an @h_errno@ value explaining the problem.
86 */
87
88 #define BRES_BYNAME 0 /* Request: resolve given name */
89 #define BRES_BYADDR 1 /* Request: resolve given address */
90
91 #define BRES_HOSTENT 0 /* Response: resolved ok */
92 #define BRES_ERROR 1 /* Response: resolution failed */
93
94 /* --- Encodings --- *
95 *
96 * A string is encoded as a @size_t@ length followed by the actual data. The
97 * null terminator is not transmitted.
98 *
99 * Addresses for resolution are transmitted as raw @struct in_addr@
100 * structures.
101 *
102 * A @hostent@ structure is transmitted as a header containing fixed-size
103 * information, followed by the official name, an array of aliases, and an
104 * array of addresses. The number of items in the arrays is specified in the
105 * header.
106 *
107 * The implementation assumes that a complete request or reply is always
108 * sent. Undesirable blocking will occur if this is not the case. Both ends
109 * are assumed to trust each other. A protocol failure results in the child
110 * in question being terminated.
111 */
112
113 typedef struct hostskel {
114 size_t nalias;
115 int addrtype;
116 size_t addrsz;
117 size_t naddr;
118 } hostskel;
119
120 /* --- @doread@, @dowrite@ --- *
121 *
122 * Arguments: @int fd@ = file descriptor
123 * @void *buf@ = buffer for data
124 * @size_t sz@ = size of data
125 *
126 * Returns: Zero if successful, nonzero otherwise.
127 *
128 * Use: Reads or writes a chunk of data. @EINTR@ errors are retried;
129 * incomplete reads and writes are continued from where they
130 * left off. End-of-file is considered an I/O error.
131 */
132
133 static int doread(int fd, void *buf, size_t sz)
134 {
135 char *p = buf;
136 while (sz) {
137 int r = read(fd, p, sz);
138 if (r < 0) {
139 if (errno == EINTR)
140 continue;
141 return (-1);
142 } else if (r == 0) {
143 errno = EIO;
144 return (-1);
145 }
146 sz -= r;
147 p += r;
148 }
149 return (0);
150 }
151
152 static int dowrite(int fd, const void *buf, size_t sz)
153 {
154 const char *p = buf;
155 while (sz) {
156 int r = write(fd, p, sz);
157 if (r < 0) {
158 if (errno == EINTR)
159 continue;
160 return (-1);
161 } else if (r == 0) {
162 errno = EIO;
163 return (-1);
164 }
165 sz -= r;
166 p += r;
167 }
168 return (0);
169 }
170
171 /* --- @getstring@ --- *
172 *
173 * Arguments: @int fd@ = file descriptor to read
174 *
175 * Returns: String in heap-allocated block, or a null pointer.
176 *
177 * Use: Decodes a string.
178 */
179
180 static char *getstring(int fd)
181 {
182 size_t sz;
183 char *p;
184
185 if (doread(fd, &sz, sizeof(sz)) || (p = malloc(sz + 1)) == 0)
186 return (0);
187 if (doread(fd, p, sz)) {
188 free(p);
189 return (0);
190 }
191 p[sz] = 0;
192 return (p);
193 }
194
195 /* --- @putstring@ --- *
196 *
197 * Arguments: @int fd@ = file descriptor to write on
198 * @const char *p@ = pointer to string to write
199 *
200 * Returns: Zero if successful.
201 *
202 * Use: Encodes a string.
203 */
204
205 static int putstring(int fd, const char *p)
206 {
207 size_t sz = strlen(p);
208 if (dowrite(fd, &sz, sizeof(sz)) || dowrite(fd, p, sz))
209 return (-1);
210 return (0);
211 }
212
213 /* --- @gethost@ --- *
214 *
215 * Arguments: @int fd@ = file descriptor to read
216 *
217 * Returns: Pointer to heap-allocated @struct hostent@, or null.
218 *
219 * Use: Decodes a host structure. The resulting structure is all in
220 * one big heap block.
221 */
222
223 #ifndef BRES_STANDALONE
224
225 static struct hostent *gethost(int fd)
226 {
227 hostskel hsk;
228 struct hostent *h;
229 char *name;
230 char **alias = 0;
231
232 /* --- Read the skeleton structure --- */
233
234 if (doread(fd, &hsk, sizeof(hsk)))
235 goto tidy_0;
236
237 /* --- Read the hostname and alias strings --- *
238 *
239 * Count the length of the strings as we go.
240 */
241
242 {
243 size_t sz =
244 sizeof(struct hostent) +
245 hsk.naddr * hsk.addrsz +
246 (hsk.naddr + hsk.nalias + 2) * sizeof(char *);
247
248 /* --- Read the primary host name --- */
249
250 if ((name = getstring(fd)) == 0)
251 goto tidy_0;
252 sz += strlen(name) + 1;
253
254 /* --- Read in the alias names --- */
255
256 if (hsk.nalias) {
257 int i;
258 if ((alias = malloc(hsk.nalias * sizeof(char *))) == 0)
259 goto tidy_1;
260 for (i = 0; i < hsk.nalias; i++)
261 alias[i] = 0;
262 for (i = 0; i < hsk.nalias; i++) {
263 if ((alias[i] = getstring(fd)) == 0)
264 goto tidy_2;
265 sz += strlen(alias[i]) + 1;
266 }
267 }
268
269 /* --- Allocate the output structure --- */
270
271 if ((h = malloc(sz)) == 0)
272 goto tidy_2;
273 }
274
275 /* --- Fill in the base structure --- */
276
277 h->h_addrtype = hsk.addrtype;
278 h->h_length = hsk.addrsz;
279
280 /* --- Start putting everything else in --- */
281
282 {
283 char **p = (char **)(h + 1);
284 char *a = (char *)(p + hsk.nalias + hsk.naddr + 2);
285 int i;
286
287 /* --- Start with the address table --- */
288
289 h->h_addr_list = p;
290 if (doread(fd, a, hsk.naddr * hsk.addrsz))
291 goto tidy_2;
292 for (i = 0; i < hsk.naddr; i++) {
293 *p++ = a;
294 a += hsk.addrsz;
295 }
296 *p++ = 0;
297
298 /* --- Finally copy the strings over --- */
299
300 #define PUT(_p) do { \
301 size_t _len = strlen(_p) + 1; \
302 memcpy(a, (_p), _len); \
303 a += _len; \
304 } while (0)
305
306 h->h_name = a;
307 PUT(name);
308 free(name);
309 h->h_aliases = p;
310 for (i = 0; i < hsk.nalias; i++) {
311 *p++ = a;
312 PUT(alias[i]);
313 free(alias[i]);
314 }
315 *p++ = 0;
316 free(alias);
317
318 #undef PUT
319 }
320
321 return (h);
322
323 /* --- Tidy up after various types of failure --- */
324
325 tidy_2:
326 {
327 int i;
328 for (i = 0; i < hsk.nalias && alias[i]; i++)
329 free(alias[i]);
330 free(alias);
331 }
332 tidy_1:
333 free(name);
334 tidy_0:
335 return (0);
336 }
337
338 #endif
339
340 /* --- @puthost@ --- *
341 *
342 * Arguments: @int fd@ = file descriptor
343 * @struct hostent *h@ = pointer to host structure
344 *
345 * Returns: Zero if successful.
346 *
347 * Use: Encodes a host structure.
348 */
349
350 static int puthost(int fd, struct hostent *h)
351 {
352 hostskel hsk;
353 int i;
354
355 /* --- Fill in and send the skeleton structure --- */
356
357 for (i = 0; h->h_aliases[i]; i++)
358 ;
359 hsk.nalias = i;
360 for (i = 0; h->h_addr_list[i]; i++)
361 ;
362 hsk.naddr = i;
363 hsk.addrtype = h->h_addrtype;
364 hsk.addrsz = h->h_length;
365 if (dowrite(fd, &hsk, sizeof(hsk)))
366 return (-1);
367
368 /* --- Send the name and alias strings --- */
369
370 if (putstring(fd, h->h_name))
371 return (-1);
372 for (i = 0; h->h_aliases[i]; i++) {
373 if (putstring(fd, h->h_aliases[i]))
374 return (-1);
375 }
376
377 /* --- Send the address data --- */
378
379 for (i = 0; h->h_addr_list[i]; i++) {
380 if (dowrite(fd, h->h_addr_list[i], hsk.addrsz))
381 return (-1);
382 }
383
384 /* --- OK, done --- */
385
386 return (0);
387 }
388
389 /*----- Resolver server ---------------------------------------------------*/
390
391 /* --- @child@ --- *
392 *
393 * Arguments: @int rfd@ = output file descriptor for resolved hostnames
394 * @int cfd@ = input file descriptor for raw addresses
395 *
396 * Returns: Never.
397 *
398 * Use: Asynchronous name resolving process.
399 */
400
401 static void child(int rfd, int cfd)
402 {
403 /* --- Close other file descriptors --- */
404
405 {
406 int i;
407 #if defined(_SC_OPEN_MAX)
408 int maxfd = sysconf(_SC_OPEN_MAX);
409 #elif defined(OPEN_MAX)
410 int maxfd = OPEN_MAX;
411 #else
412 int maxfd = -1;
413 #endif
414
415 if (maxfd < 0)
416 maxfd = 256; /* Fingers crossed... */
417 for (i = 0; i < maxfd; i++) {
418 if (i != rfd && i != cfd && i != 1)
419 close(i);
420 }
421 }
422
423 signal(SIGTERM, SIG_DFL);
424 signal(SIGHUP, SIG_DFL);
425 signal(SIGQUIT, SIG_DFL);
426 signal(SIGALRM, SIG_DFL);
427 signal(SIGINT, SIG_DFL);
428
429 /* --- Main request/response loop --- */
430
431 for (;;) {
432 int req, resp;
433 struct hostent *h;
434
435 /* --- Read the request --- */
436
437 if (doread(cfd, &req, sizeof(req)))
438 goto lose;
439
440 /* --- Process it into a host structure --- */
441
442 switch (req) {
443
444 /* --- Normal forward lookup --- */
445
446 case BRES_BYNAME: {
447 char *name = getstring(cfd);
448 if (!name)
449 goto lose;
450 h = gethostbyname(name);
451 free(name);
452 } break;
453
454 /* --- Reverse lookup --- */
455
456 case BRES_BYADDR: {
457 struct in_addr addr;
458 char *p;
459 if (doread(cfd, &addr, sizeof(addr)))
460 goto lose;
461 if ((h = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET)) == 0)
462 goto fail;
463
464 /* --- Do a forward lookup to confirm --- */
465
466 {
467 size_t sz = strlen(h->h_name) + 1;
468 if ((p = malloc(sz)) == 0)
469 goto fail;
470 memcpy(p, h->h_name, sz);
471 }
472
473 h = gethostbyname(p);
474 free(p);
475 if (!h)
476 goto fail;
477 p = 0;
478 if (h) {
479 char **pp;
480 for (pp = h->h_addr_list; *pp; pp++) {
481 struct in_addr a;
482 memcpy(&a, *pp, sizeof(a));
483 if (a.s_addr == addr.s_addr) {
484 p = h->h_name;
485 break;
486 }
487 }
488 }
489 if (!p) {
490 h = 0;
491 h_errno = NO_RECOVERY;
492 }
493 fail:;
494 } break;
495
496 /* --- Unknown request -- may have lost sync --- */
497
498 default:
499 goto lose;
500 }
501
502 /* --- Transmit the response --- */
503
504 if (h) {
505 resp = BRES_HOSTENT;
506 if (dowrite(rfd, &resp, sizeof(resp)) || puthost(rfd, h))
507 goto lose;
508 } else {
509 resp = BRES_ERROR;
510 if (dowrite(rfd, &resp, sizeof(resp)) ||
511 dowrite(rfd, &h_errno, sizeof(h_errno)))
512 goto lose;
513 }
514 }
515
516 lose:
517 _exit(1);
518 }
519
520 /* --- @main@ --- *
521 *
522 * Arguments: @int argc@ = number of command line arguments
523 * @char *argv[]@ = array of arguments
524 *
525 * Returns: Runs until killed or an error occurs.
526 *
527 * Use: A name resolver server process for mLib programs which need
528 * this sort of thing.
529 */
530
531 #ifdef BRES_STANDALONE
532
533 int main(int argc, char *argv[])
534 {
535 if (isatty(STDIN_FILENO)) {
536 char *p = strrchr(argv[0], '/');
537 if (p)
538 p++;
539 else
540 p = argv[0];
541 fprintf(stderr,
542 "%s: don't run this program unless you know what you're doing.\n",
543 p);
544 exit(1);
545 }
546 child(STDOUT_FILENO, STDIN_FILENO);
547 return (1);
548 }
549
550 #endif
551
552 /*----- Main code ---------------------------------------------------------*/
553
554 #ifndef BRES_STANDALONE
555
556 /* --- @zap@ --- *
557 *
558 * Arguments: @bres_server *rs@ = pointer to server block
559 *
560 * Returns: ---
561 *
562 * Use: Kills a server process, reaps the losing child and makes
563 * things generally clean again.
564 */
565
566 static void zap(bres_server *rs)
567 {
568 /* --- Close the pipes, kill the child, and reap it --- */
569
570 if (rs->kid != -1) {
571 close(rs->fd);
572 close(rs->f.fd);
573 kill(rs->kid, SIGTERM);
574 waitpid(rs->kid, 0, 0);
575 rs->kid = -1;
576 }
577
578 /* --- Move the server to the back of the list --- */
579
580 rs->next->prev = rs->prev;
581 rs->prev->next = rs->next;
582 rs->next = FREE;
583 rs->prev = FREE->prev;
584 FREE->prev->next = rs;
585 FREE->prev = rs;
586 }
587
588 /* --- @bres_abort@ --- *
589 *
590 * Arguments: @bres_client *rc@ = pointer to client block
591 *
592 * Returns: ---
593 *
594 * Use: Removes a queued job.
595 */
596
597 void bres_abort(bres_client *rc)
598 {
599 if (rc->q == BRES_BYNAME)
600 xfree(rc->u.name);
601 if (rc->rs) {
602 sel_rmfile(&rc->rs->f);
603 zap(rc->rs);
604 rc->rs = 0;
605 } else {
606 rc->next->prev = rc->prev;
607 rc->prev->next = rc->next;
608 }
609 }
610
611 /* --- @idle@ --- *
612 *
613 * Arguments: @struct timeval *tv@ = pointer to the current time
614 * @void *vp@ = pointer to a server block
615 *
616 * Returns: ---
617 *
618 * Use: Kills off a child which has been idle for too long.
619 */
620
621 static void idle(struct timeval *tv, void *vp)
622 {
623 bres_server *rs = vp;
624 zap(rs);
625 }
626
627 /* --- @answer@ --- *
628 *
629 * Arguments: @int fd@ = file descriptor which is ready
630 * @unsigned mode@ = what it's doing now
631 * @void *vp@ = pointer to server block
632 *
633 * Returns: ---
634 *
635 * Use: Retrieves an answer from a name resolver process.
636 */
637
638 static void attach(bres_client */*rc*/);
639
640 static void answer(int fd, unsigned mode, void *vp)
641 {
642 bres_server *rs = vp;
643 bres_client *rc = rs->rc;
644 struct hostent *h = 0;
645 int resp;
646 int fail = 1;
647
648 /* --- Report the result to my client --- */
649
650 sel_rmfile(&rs->f);
651 h_errno = -1;
652 if (doread(fd, &resp, sizeof(resp)) == 0) {
653 switch (resp) {
654 case BRES_ERROR:
655 doread(fd, &h_errno, sizeof(h_errno));
656 fail = 0;
657 break;
658 case BRES_HOSTENT:
659 h = gethost(fd);
660 fail = 0;
661 break;
662 }
663 }
664 if (rc) {
665 rc->func(h, rc->p);
666 if (rc->q == BRES_BYNAME)
667 xfree(rc->u.name);
668 }
669 if (h)
670 free(h);
671 if (fail)
672 zap(rs);
673 if (!rc)
674 return;
675
676 /* --- Wrap up the various structures --- */
677
678 rs->rc = 0;
679 rc->rs = 0;
680 rs->next = FREE->next;
681 rs->prev = FREE;
682 FREE->next->prev = rs;
683 FREE->next = rs;
684
685 /* --- Tie a timer onto the server block --- */
686
687 {
688 struct timeval tv;
689
690 gettimeofday(&tv, 0);
691 tv.tv_sec += BRES_IDLE;
692 sel_addtimer(sel, &rs->t, &tv, idle, rs);
693 }
694
695 /* --- If there are any clients waiting, attach one --- */
696
697 if (QUEUE->next != QUEUE) {
698 rc = QUEUE->next;
699 QUEUE->next = rc->next;
700 rc->next->prev = QUEUE;
701 attach(rc);
702 }
703 }
704
705 /* --- @start@ --- *
706 *
707 * Arguments: @bres_server *rs@ = pointer to a server block
708 *
709 * Returns: Zero if OK, nonzero if something failed.
710 *
711 * Use: Starts up a child resolver process.
712 */
713
714 static int start(bres_server *rs)
715 {
716 int rfd[2], cfd[2];
717 pid_t kid;
718 mdup_fd md[2];
719
720 /* --- Make the pipes --- */
721
722 if (pipe(rfd))
723 goto fail_0;
724 if (pipe(cfd))
725 goto fail_1;
726
727 /* --- Start up the child process --- */
728
729 if ((kid = fork()) < 0)
730 goto fail_2;
731 if (kid == 0) {
732 close(cfd[1]);
733 close(rfd[0]);
734
735 if (server) {
736 md[0].cur = cfd[0]; md[0].want = STDIN_FILENO;
737 md[1].cur = rfd[1]; md[1].want = STDOUT_FILENO;
738 if (mdup(md, 2) || 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
756 fail_2:
757 close(cfd[0]);
758 close(cfd[1]);
759 fail_1:
760 close(rfd[0]);
761 close(rfd[1]);
762 fail_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
776 static 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
789 again:
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
854 lost:
855 rc->func(0, rc->p);
856 if (rc->q == BRES_BYNAME)
857 xfree(rc->u.name);
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
869 static 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
897 void 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
922 void 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
947 void 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
964 void 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 -------------------------------------------------*/