1 /* XQF - Quake server browser and launcher
2  * Copyright (C) 1998-2000 Roman Pozlevich <roma@botik.ru>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
17  */
18 
19 #include <sys/types.h>
20 #include <stdio.h>      /* fprintf, fflush */
21 #include <stdlib.h>     /* malloc, free */
22 #include <signal.h>     /* kill, ... */
23 #include <unistd.h>     /* pipe, close, dup2, _exit, fcntl, select, alarm, pause */
24 #include <string.h>     /* memset, strdup, strlen, strcmp */
25 #include <sys/wait.h>   /* waitpid */
26 #include <errno.h>      /* errno */
27 #include <sys/time.h>   /* select */
28 #include <sys/socket.h> /* struct in_addr, inet_aton, inet_ntoa */
29 #include <netinet/in.h> /* struct in_addr, inet_aton, inet_ntoa */
30 #include <arpa/inet.h>  /* struct in_addr, inet_aton, inet_ntoa */
31 #include <netdb.h>      /* struct hostent, gethostbyaddr, gethostbyname */
32 #include <sys/param.h>  /* MAXHOSTNAMELEN */
33 #include <time.h>       /* time */
34 
35 #ifndef h_errno
36 extern int h_errno;     /* h_errno */
37 #endif
38 
39 #include <gtk/gtk.h>
40 
41 #include "xqf.h"
42 #include "dns.h"
43 #include "host.h"
44 #include "utils.h"
45 #include "debug.h"
46 
47 #ifndef MAXHOSTNAMELEN
48 # define MAXHOSTNAMELEN 64
49 #endif
50 
51 #define DNS_BUF_SIZE        (MAXHOSTNAMELEN * 2 + 32)
52 #define RESOLVE_DELIM       '|'
53 #define RESOLVE_TIMEOUT     10
54 #define DNS_MAX_CHILDREN    8
55 
56 #ifndef WAIT_ANY
57 # define WAIT_ANY       -1
58 #endif
59 
60 
61 struct dns_stream {
62 	int fd;
63 
64 	char buf[DNS_BUF_SIZE];
65 	int pos;
66 
67 	void (*parse) (char *str, void *data);
68 	void (*close) (int error, void *data);
69 	void *data;
70 };
71 
72 struct dns_helper_descr {
73 	int pid;
74 	int tag;            /* GDK tag */
75 	int output;         /* fd */
76 	struct dns_stream *input;
77 	void (*resolved) (char *str, struct host *h, enum dns_status status, void *user_data);
78 	void *user_data;
79 };
80 
81 struct dns_child_descr {
82 	struct dns_stream *input;
83 	pid_t pid;
84 };
85 
86 struct dns_queue_link {
87 	char *str;
88 	struct dns_queue_link *next;
89 };
90 
91 static struct dns_helper_descr dns_helper = { -1, -1, -1, NULL, NULL, NULL };
92 
93 static struct dns_stream *dns_master_input = NULL;
94 
95 static struct dns_child_descr dns_workers[DNS_MAX_CHILDREN];
96 static int dns_workers_num = 0;
97 
98 static struct dns_queue_link *q_head = NULL, *q_tail = NULL;
99 static struct dns_queue_link *q_free = NULL;
100 
101 static char *worker_arg = NULL;
102 
103 
104 static void dns_master_init (void);
105 static void dns_master_reset (void);
106 
107 
str_is_ip_address(char * str)108 int str_is_ip_address (char *str) {
109 	struct in_addr dummy;
110 
111 	return (str)? inet_aton (worker_arg, &dummy) : FALSE;
112 }
113 
114 
failed(char * name,char * arg)115 static int failed (char *name, char *arg) {
116 	fprintf (stderr, "%s(%s) failed: %s\n", name, (arg)? arg : "", g_strerror (errno));
117 	return TRUE;
118 }
119 
120 
master_sigchld_handler(int signum)121 static void master_sigchld_handler (int signum) {
122 	int pid;
123 	int status;
124 
125 	debug(3,"signal: ",signum);
126 
127 	while ((pid = waitpid (WAIT_ANY, &status, WNOHANG)) > 0);
128 }
129 
130 
master_sigterm_handler(int sig)131 static void master_sigterm_handler (int sig) {
132 	if (sig != SIGTERM && sig != SIGINT) {
133 		debug (3, "DNS Helper: %s(%d) signal", g_strsignal (sig), sig);
134 	}
135 	dns_master_reset ();
136 	_exit (1);
137 }
138 
139 
dns_queue_head(void)140 static char *dns_queue_head (void) {
141 	struct dns_queue_link *link;
142 	char *str = NULL;
143 
144 	if (q_head) {
145 		link = q_head;
146 		q_head = link->next;
147 		if (!q_head)
148 			q_tail = NULL;
149 		str = link->str;
150 
151 		link->next = q_free;
152 		q_free = link;
153 	}
154 
155 	return str;
156 }
157 
158 
dns_queue_add(char * str)159 static void dns_queue_add (char *str) {
160 	struct dns_queue_link *link;
161 
162 	if (q_free) {
163 		link = q_free;
164 		q_free = link->next;
165 	}
166 	else {
167 		link = malloc (sizeof (struct dns_queue_link));
168 	}
169 
170 	link->str = str;
171 	link->next = NULL;
172 
173 	if (q_tail)
174 		q_tail->next = link;
175 	else
176 		q_head = link;
177 
178 	q_tail = link;
179 }
180 
181 
dns_helper_shutdown(void)182 void dns_helper_shutdown (void) {
183 	if (dns_helper.pid > 0) {
184 		kill (dns_helper.pid, SIGTERM);
185 		dns_helper.pid = -1;
186 	}
187 
188 	if (dns_helper.output >= 0) {
189 		close (dns_helper.output);
190 		dns_helper.output = -1;
191 	}
192 
193 	if (dns_helper.input) {
194 		if (dns_helper.input->fd >= 0)
195 			close (dns_helper.input->fd);
196 		g_free (dns_helper.input);
197 		dns_helper.input = NULL;
198 	}
199 
200 	if (dns_helper.tag >= 0) {
201 		gdk_input_remove (dns_helper.tag);
202 		dns_helper.tag = -1;
203 	}
204 
205 	dns_helper.resolved = NULL;
206 	dns_helper.user_data = NULL;
207 }
208 
209 
helper_parse_callback(char * str,void * data)210 static void helper_parse_callback (char *str, void *data) {
211 	char *dnsmsg;
212 	struct host *h = NULL;
213 	enum dns_status status = DNS_STATUS_ERROR;
214 	char *token[3];
215 	int n;
216 
217 	/* id|address|hostname */
218 
219 	n = tokenize_bychar (str, token, 3, RESOLVE_DELIM);
220 
221 	if (n < 2)
222 		return;
223 
224 	if (n > 2) {
225 		status = DNS_STATUS_OK;
226 
227 		if (!strncmp (token[2], DNS_MSG_PREFIX, sizeof (DNS_MSG_PREFIX) - 1)) {
228 			dnsmsg = token[2] + sizeof (DNS_MSG_PREFIX) - 1;
229 
230 			if (!strcmp (dnsmsg, DNS_MSG_TIMEOUT))
231 				status = DNS_STATUS_TIMEOUT;
232 			else if (!strcmp (dnsmsg, DNS_MSG_NOTFOUND))
233 				status = DNS_STATUS_NOTFOUND;
234 			else
235 				status = DNS_STATUS_ERROR;
236 		}
237 	}
238 
239 	if ((h = host_add (token[1])) != NULL) {
240 
241 		switch (status) {
242 
243 			case DNS_STATUS_OK:
244 				if (n > 2) {
245 					if (h->name)
246 						g_free (h->name);
247 					h->name = g_strdup (token[2]);
248 				}
249 				h->refreshed = time (NULL); /* Success */
250 				break;
251 
252 			case DNS_STATUS_NOTFOUND:
253 				if (h->name) {
254 					g_free (h->name);
255 					h->name = NULL;
256 				}
257 				h->refreshed = time (NULL); /* Success */
258 				break;
259 
260 			default:
261 				h->refreshed = 0;           /* Try later */
262 				break;
263 
264 		}
265 
266 	}
267 
268 	if (h)
269 		host_ref (h);
270 
271 	if (dns_helper.resolved)
272 		(*dns_helper.resolved) (token[0], h, status, dns_helper.user_data);
273 
274 	if (h)
275 		host_unref (h);
276 }
277 
278 
helper_close_callback(int error,void * data)279 static void helper_close_callback (int error, void *data) {
280 	dns_helper_shutdown ();
281 }
282 
283 
worker_parse_callback(char * str,void * data)284 static void worker_parse_callback (char *str, void *data) {
285 	int len;
286 
287 #ifdef DEBUG
288 	fprintf (stderr, "DNS Master> got \"%s\" from worker %p\n", str, data);
289 #endif
290 
291 	len = strlen (str);
292 	str[len] = '\n';
293 	write (1, str, len + 1);    /* stdout */
294 }
295 
296 
worker_close_callback(int error,void * data)297 static void worker_close_callback (int error, void *data) {
298 	int n = GPOINTER_TO_INT(data);
299 
300 	dns_workers[n].pid = -1;
301 	dns_workers_num--;
302 
303 	close (dns_workers[n].input->fd);
304 	dns_workers[n].input->fd = -1;
305 }
306 
307 
print_resolved(char * str,char * addr,char * name)308 static void print_resolved (char *str, char *addr, char *name) {
309 	printf ("%s%c%s%c%s\n", (str)? str : "", RESOLVE_DELIM,
310 			(addr)? addr : "", RESOLVE_DELIM,
311 			(name)? name : "");
312 	fflush (stdout);
313 }
314 
315 
worker_sigalrm_handler(int signum)316 static void worker_sigalrm_handler (int signum) {
317 
318 	if (worker_arg) {
319 		print_resolved (worker_arg,
320 				(str_is_ip_address (worker_arg))? worker_arg : NULL,
321 				DNS_MSG_PREFIX DNS_MSG_TIMEOUT);
322 		debug (3, "<DNS> timeout: %s", worker_arg);
323 		worker_arg = NULL;
324 	}
325 
326 	_exit (0);
327 }
328 
329 
worker_sigterm_handler(int signum)330 static void worker_sigterm_handler (int signum) {
331 	if (worker_arg)
332 		debug(3, "<DNS> terminated: %s", worker_arg);
333 	_exit (0);
334 }
335 
sighandler_debug(int signum)336 static void sighandler_debug(int signum) {
337 	if (signum == SIGUSR1)
338 		set_debug_level(get_debug_level()+1);
339 	else if (signum == SIGUSR2)
340 		set_debug_level(get_debug_level()-1);
341 }
342 
herrno2msg(int err)343 static char *herrno2msg (int err) {
344 
345 	switch (err) {
346 
347 		case HOST_NOT_FOUND:
348 		case NO_ADDRESS:
349 			return DNS_MSG_PREFIX DNS_MSG_NOTFOUND;
350 
351 		case NO_RECOVERY:
352 			return DNS_MSG_PREFIX DNS_MSG_ERROR;
353 
354 		case TRY_AGAIN:
355 			return DNS_MSG_PREFIX DNS_MSG_TIMEOUT;
356 
357 		default:
358 			return NULL;
359 	}
360 }
361 
362 
worker_resolve(char * str)363 static void worker_resolve (char *str) {
364 	struct hostent *h = NULL;
365 	struct in_addr ip;
366 
367 	if (!str || !*str || strchr (str, '\n') || strchr (str, RESOLVE_DELIM)) {
368 		print_resolved ("BAD REQUEST", NULL, NULL);
369 		return;
370 	}
371 
372 	worker_arg = str;
373 
374 	if (!inet_aton (str, &ip)) {
375 		h = gethostbyname (str);
376 		if (!h) {
377 			worker_arg = NULL;
378 			alarm (0);
379 			print_resolved (str, NULL, herrno2msg (h_errno));
380 			return;
381 		}
382 		ip = *((struct in_addr *) h->h_addr_list[0]);
383 	}
384 	else {
385 		alarm (RESOLVE_TIMEOUT);
386 	}
387 
388 	h = gethostbyaddr ((char *) &ip.s_addr, sizeof (ip.s_addr), AF_INET);
389 	worker_arg = NULL;
390 
391 	alarm (0);
392 
393 	print_resolved (str, inet_ntoa (ip),
394 			(h)? h->h_name : DNS_MSG_PREFIX DNS_MSG_NOTFOUND);
395 }
396 
397 
fork_worker(int n,char * str)398 static int fork_worker (int n, char *str) {
399 	int fdset[2] = { -1, -1 };
400 	int pid;
401 
402 	if ((pipe (fdset) < 0 && failed ("pipe", NULL)) ||
403 			((pid = fork ()) < (pid_t) 0 && failed ("fork", NULL))) {
404 
405 		if (fdset[0] > 0) close (fdset[0]);
406 		if (fdset[1] > 0) close (fdset[1]);
407 
408 		return -1;
409 	}
410 
411 	if (pid) {  /* parent */
412 		close (fdset[1]);
413 
414 		dns_workers[n].pid = pid;
415 
416 		if (!dns_workers[n].input)
417 			dns_workers[n].input = malloc (sizeof (struct dns_stream));
418 
419 		dns_workers[n].input->fd = fdset[0];
420 		if (set_nonblock (dns_workers[n].input->fd) == -1)
421 			failed ("fcntl", NULL);
422 		dns_workers[n].input->pos = 0;
423 
424 		dns_workers[n].input->parse = worker_parse_callback;
425 		dns_workers[n].input->close = worker_close_callback;
426 		dns_workers[n].input->data  = GINT_TO_POINTER(n);
427 
428 		dns_workers_num++;
429 
430 		debug (7, "DNS Master> worker %d (str:%s) is forked", n, str);
431 	}
432 	else {  /* child */
433 		on_sig (SIGHUP,  _exit);
434 		on_sig (SIGINT,  _exit);
435 		on_sig (SIGQUIT, _exit);
436 		on_sig (SIGBUS,  _exit);
437 		on_sig (SIGSEGV, _exit);
438 		on_sig (SIGPIPE, _exit);
439 		on_sig (SIGCHLD, _exit);
440 		on_sig (SIGTERM, worker_sigterm_handler);
441 		on_sig (SIGALRM, worker_sigalrm_handler);
442 
443 		on_sig(SIGUSR1, sighandler_debug);
444 		on_sig(SIGUSR2, sighandler_debug);
445 
446 		dup2 (fdset[1], 1); /* stdout */
447 
448 		close (fdset[0]);
449 		close (fdset[1]);
450 
451 		debug (7, "DNS Worker [%s]> started", str);
452 
453 		alarm (60 * 10);    /* suicide after 10 min */
454 
455 		worker_resolve (str);
456 
457 		_exit (0);
458 	}
459 
460 	return 0;
461 }
462 
463 
dns_dispatch_to_worker(char * str)464 static int dns_dispatch_to_worker (char *str) {
465 	int i;
466 
467 	if (dns_workers_num < DNS_MAX_CHILDREN) {
468 		for (i = 0; i < DNS_MAX_CHILDREN; i++) {
469 			if (dns_workers[i].pid < 0) {
470 				debug (7, "DNS Master> \"%s\" is dispatched to worker %d",
471 						str, i);
472 				fork_worker (i, str);
473 				return TRUE;
474 			}
475 		}
476 	}
477 	return FALSE;
478 }
479 
480 
dns_move_queue(void)481 static int dns_move_queue (void) {
482 	int moved = FALSE;
483 
484 	while (q_head && dns_dispatch_to_worker (q_head->str)) {
485 		free (dns_queue_head ());
486 		moved = TRUE;
487 	}
488 	return moved;
489 }
490 
491 
dns_resolve(char * str)492 static void dns_resolve (char *str) {
493 
494 	dns_move_queue ();
495 
496 	if (dns_workers_num >= DNS_MAX_CHILDREN || !dns_dispatch_to_worker (str)) {
497 		debug (7, "DNS Master> \"%s\" is put to the waiting queue",
498 				str);
499 		dns_queue_add (strdup (str));
500 	}
501 }
502 
503 
dns_master_reset(void)504 static void dns_master_reset (void) {
505 	char *str;
506 	int i;
507 
508 	for (i = 0; i < DNS_MAX_CHILDREN; i++) {
509 		if (dns_workers[i].pid > 0) {
510 			kill (dns_workers[i].pid, SIGTERM);
511 			dns_workers[i].pid = -1;
512 		}
513 		if (dns_workers[i].input) {
514 			if (dns_workers[i].input->fd >= 0)
515 				close (dns_workers[i].input->fd);
516 			free (dns_workers[i].input);
517 			dns_workers[i].input = NULL;
518 		}
519 	}
520 	dns_workers_num = 0;
521 
522 	while ((str = dns_queue_head ()) != NULL) {
523 		free (str);
524 	}
525 }
526 
527 
master_parse_callback(char * str,void * data)528 static void master_parse_callback (char *str, void *data) {
529 	debug (7, "DNS Master> got \"%s\"", str);
530 	if (strcmp (str, DNS_CMD_RESET) == 0) {
531 		debug (7, "DNS Master> RESET");
532 		dns_master_reset ();
533 	}
534 	else {
535 		dns_resolve (str);
536 	}
537 }
538 
539 
master_close_callback(int error,void * data)540 static void master_close_callback (int error, void *data) {
541 	debug (3, "DNS Master> pipe closed, errors: %s",
542 			(error)? "yes" : "no");
543 	dns_master_reset ();
544 	_exit (0);
545 }
546 
547 
dns_master_init(void)548 static void dns_master_init (void) {
549 	int i;
550 
551 	for (i = 0; i < DNS_MAX_CHILDREN; i++) {
552 		dns_workers[i].pid = -1;
553 		dns_workers[i].input = NULL;
554 	}
555 
556 	dns_workers_num = 0;
557 
558 	dns_master_input = malloc (sizeof (struct dns_stream));
559 
560 	dns_master_input->fd = 0;   /* stdin */
561 	if (set_nonblock (dns_master_input->fd) == -1)
562 		failed ("fcntl", NULL);
563 
564 	dns_master_input->pos = 0;
565 	dns_master_input->parse = master_parse_callback;
566 	dns_master_input->close = master_close_callback;
567 	dns_master_input->data = NULL;
568 
569 	q_head = q_tail = q_free = NULL;
570 
571 	on_sig (SIGHUP,  master_sigterm_handler);
572 	on_sig (SIGINT,  master_sigterm_handler);
573 	on_sig (SIGQUIT, master_sigterm_handler);
574 	on_sig (SIGBUS,  master_sigterm_handler);
575 	on_sig (SIGSEGV, master_sigterm_handler);
576 	on_sig (SIGALRM, master_sigterm_handler);
577 	on_sig (SIGTERM, master_sigterm_handler);
578 
579 	on_sig(SIGUSR1, sighandler_debug);
580 	on_sig(SIGUSR2, sighandler_debug);
581 }
582 
583 
dns_input_callback(struct dns_stream * stream,int fd,GdkInputCondition condition)584 static void dns_input_callback (struct dns_stream *stream, int fd,
585 		GdkInputCondition condition) {
586 	char *tmp;
587 	int first_used = 0;
588 	int res;
589 
590 	res = read (fd, stream->buf + stream->pos, DNS_BUF_SIZE - stream->pos);
591 
592 	if (res < 0) {
593 		if (errno == EAGAIN || errno == EWOULDBLOCK)
594 			return;
595 		failed ("read", NULL);
596 		(*stream->close) (TRUE, stream->data);
597 		return;
598 	}
599 
600 	if (res == 0) { /* EOF */
601 		(*stream->close) (FALSE, stream->data);
602 		return;
603 	}
604 
605 	tmp = stream->buf + stream->pos;
606 	stream->pos += res;
607 
608 	while (res && (tmp = memchr (tmp, '\n', res)) != NULL) {
609 		*tmp++ = '\0';
610 
611 		(*stream->parse) (stream->buf + first_used, stream->data);
612 
613 		first_used = tmp - stream->buf;
614 		res = stream->buf + stream->pos - tmp;
615 	}
616 
617 	if (first_used > 0) {
618 		if (first_used != stream->pos) {
619 			g_memmove (stream->buf, stream->buf + first_used,
620 					stream->pos - first_used);
621 		}
622 		stream->pos -= first_used;
623 	}
624 }
625 
626 
dns_master_mainloop(void)627 static void dns_master_mainloop (void) {
628 	fd_set readfds;
629 	int n;
630 	int i;
631 
632 	on_sig (SIGCHLD, master_sigchld_handler);
633 	dns_master_init ();
634 
635 	while (1) {
636 		if (dns_workers_num < DNS_MAX_CHILDREN && q_head) {
637 			dns_move_queue ();
638 		}
639 
640 		debug (7, "DNS Master> %d workers, queue is %s",
641 				dns_workers_num,
642 				(q_head)? "not empty" : "empty");
643 
644 		FD_ZERO (&readfds);
645 		FD_SET (0, &readfds);
646 
647 		for (i = 0; i < DNS_MAX_CHILDREN; i++) {
648 			if (dns_workers[i].pid > 0)
649 				FD_SET (dns_workers[i].input->fd, &readfds);
650 		}
651 
652 		n = select (FD_SETSIZE, &readfds, NULL, NULL, NULL);
653 		if (n == -1 && errno == EINTR)
654 			continue;
655 
656 		if (n < 0) {
657 			failed ("select", NULL);
658 			dns_master_reset ();
659 			return;
660 		}
661 
662 		for (i = 0; i < DNS_MAX_CHILDREN; i++) {
663 			if (dns_workers[i].pid > 0 &&
664 					FD_ISSET (dns_workers[i].input->fd, &readfds)) {
665 				dns_input_callback (dns_workers[i].input,
666 						dns_workers[i].input->fd, GDK_INPUT_READ);
667 			}
668 		}
669 
670 		if (FD_ISSET (0, &readfds))
671 			dns_input_callback (dns_master_input, 0, GDK_INPUT_READ);
672 	}
673 
674 	/* NOT REACHED */
675 
676 	dns_master_reset ();
677 }
678 
679 
dns_spawn_helper(void)680 int dns_spawn_helper (void) {
681 	int fdset1[2] = { -1, -1 };
682 	int fdset2[2] = { -1, -1 };
683 	int pid;
684 
685 	dns_helper_shutdown ();
686 
687 	if ((pipe (fdset1) < 0 && failed ("pipe", NULL)) ||
688 			(pipe (fdset2) < 0 && failed ("pipe", NULL)) ||
689 			((pid = fork ()) < (pid_t) 0 && failed ("fork", NULL))) {
690 
691 		if (fdset1[0] > 0) close (fdset1[0]);
692 		if (fdset1[1] > 0) close (fdset1[1]);
693 		if (fdset2[0] > 0) close (fdset2[0]);
694 		if (fdset2[1] > 0) close (fdset2[1]);
695 
696 		return -1;
697 	}
698 
699 	if (pid) {  /* parent */
700 		close (fdset1[1]);
701 		close (fdset2[0]);
702 
703 		dns_helper.output = fdset2[1];
704 
705 		dns_helper.input = malloc (sizeof (struct dns_stream));
706 		dns_helper.input->fd  = fdset1[0];
707 		if (set_nonblock (dns_helper.input->fd) == -1)
708 			failed("fcntl", NULL);
709 
710 		dns_helper.pid = pid;
711 
712 		dns_helper.input->pos = 0;
713 		dns_helper.input->parse = helper_parse_callback;
714 		dns_helper.input->close = helper_close_callback;
715 		dns_helper.input->data = NULL;
716 	}
717 	else {  /* child */
718 		on_sig (SIGHUP,  _exit);
719 		on_sig (SIGINT,  _exit);
720 		on_sig (SIGQUIT, _exit);
721 		on_sig (SIGBUS,  _exit);
722 		on_sig (SIGSEGV, _exit);
723 		on_sig (SIGALRM, _exit);
724 		on_sig (SIGTERM, _exit);
725 
726 		on_sig (SIGPIPE, SIG_IGN);
727 		on_sig (SIGCHLD, SIG_IGN);
728 
729 		dup2 (fdset1[1], 1);    /* stdout */
730 		dup2 (fdset2[0], 0);    /* stdin */
731 
732 		close (fdset1[0]);
733 		close (fdset1[1]);
734 		close (fdset2[0]);
735 		close (fdset2[1]);
736 
737 		dns_master_mainloop ();
738 		_exit (0);
739 	}
740 
741 	return 0;
742 }
743 
744 
dns_gtk_init(void)745 void dns_gtk_init (void) {
746 	if (dns_helper.input && dns_helper.input->fd > 0) {
747 		dns_helper.tag = gdk_input_add (dns_helper.input->fd,
748 				GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
749 				(GdkInputFunction) dns_input_callback,
750 				dns_helper.input);
751 	}
752 }
753 
754 
dns_cancel_requests(void)755 void dns_cancel_requests (void) {
756 	const char cmd[] = DNS_CMD_RESET "\n";
757 
758 	dns_set_callback (NULL, NULL);
759 
760 	if (dns_helper.output >= 0) {
761 		write (dns_helper.output, cmd, sizeof (cmd) - 1);
762 	}
763 }
764 
765 
dns_lookup(const char * str)766 void dns_lookup (const char *str) {
767 	char host[MAXHOSTNAMELEN + 1];
768 	int len;
769 
770 	debug(8,"%s",str);
771 
772 	len = strlen (str);
773 	if (len <= MAXHOSTNAMELEN) {
774 		strcpy (host, str);
775 		host[len] = '\n';
776 		host[len + 1] = '\0';
777 		write (dns_helper.output, host, len + 1);
778 	}
779 }
780 
781 
dns_set_callback(void (* cb)(char * item,struct host * h,enum dns_status,void * data),void * data)782 void dns_set_callback (
783 		void (*cb) (char *item, struct host *h, enum dns_status, void *data),
784 		void *data) {
785 	dns_helper.resolved = cb;
786 	dns_helper.user_data = data;
787 }
788 
789 
dns_lookup_by_addr(char * ip)790 char *dns_lookup_by_addr (char *ip) {
791 	struct hostent *h;
792 	struct in_addr addr;
793 
794 	if (inet_aton (ip, &addr)) {
795 		h = gethostbyaddr ((char *) &addr.s_addr, sizeof (addr.s_addr), AF_INET);
796 		if (h)
797 			return g_strdup (h->h_name);
798 	}
799 	return NULL;
800 }
801 
802 
dns_lookup_by_name(char * name)803 char *dns_lookup_by_name (char *name) {
804 	struct hostent *h;
805 	char *ip;
806 
807 	h = gethostbyname (name);
808 	if (h) {
809 		ip = inet_ntoa (*((struct in_addr *) h->h_addr_list[0]));
810 		if (ip)
811 			return g_strdup (ip);
812 	}
813 	return NULL;
814 }
815 
816 
817 #ifdef DNS_STANDALONE
818 
main(int argc,char * argv[])819 int main (int argc, char *argv[]) {
820 	dns_master_mainloop ();
821 	return 0;
822 }
823 
824 #endif
825 
826