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