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