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