1 /*
2 * sc_pinger : scamper driver to probe destinations with various ping
3 * methods
4 *
5 * $Id: sc_pinger.c,v 1.5 2020/06/24 00:12:14 mjl Exp $
6 *
7 * Copyright (C) 2020 The University of Waikato
8 * Author: Matthew Luckie
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, version 2.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 #include "internal.h"
29
30 #include "scamper_addr.h"
31 #include "scamper_list.h"
32 #include "ping/scamper_ping.h"
33 #include "scamper_file.h"
34 #include "scamper_writebuf.h"
35 #include "scamper_linepoll.h"
36 #include "mjl_list.h"
37 #include "mjl_splaytree.h"
38 #include "utils.h"
39
40 static uint32_t options = 0;
41 static char *addrfile_name = NULL;
42 static int addrfile_fd = -1;
43 static char *addrfile_buf = NULL;
44 static size_t addrfile_len = 8192;
45 static size_t addrfile_off = 0;
46 static char *outfile_name = NULL;
47 static int outfile_fd = -1;
48 static char *logfile_name = NULL;
49 static FILE *logfile_fd = NULL;
50 static scamper_file_filter_t *ffilter = NULL;
51 static scamper_file_t *decode_in = NULL;
52 static int decode_in_fd = -1;
53 static int decode_out_fd = -1;
54 static scamper_writebuf_t *decode_wb = NULL;
55 static int scamper_fd = -1;
56 static scamper_linepoll_t *scamper_lp = NULL;
57 static scamper_writebuf_t *scamper_wb = NULL;
58 static int scamper_port = 0;
59 static char *scamper_unix = NULL;
60 static int data_left = 0;
61 static int more = 0;
62 static int completed = 0;
63 static int probe_count = 5;
64 static int reply_count = 3;
65 static splaytree_t *tree = NULL;
66 static slist_t *virgin = NULL;
67 static slist_t *waiting = NULL;
68 static char **methods = NULL;
69 static int methodc = 0;
70 static int error = 0;
71
72 #define OPT_HELP 0x0001
73 #define OPT_ADDRFILE 0x0002
74 #define OPT_OUTFILE 0x0004
75 #define OPT_PORT 0x0008
76 #define OPT_UNIX 0x0010
77 #define OPT_TEXT 0x0020
78 #define OPT_DAEMON 0x0040
79 #define OPT_COUNT 0x0080
80
81 /*
82 * sc_pingtest
83 *
84 * keep state about which method we are up to
85 */
86 typedef struct sc_pinger
87 {
88 scamper_addr_t *dst;
89 int step;
90 splaytree_node_t *node;
91 } sc_pinger_t;
92
usage(uint32_t opt_mask)93 static void usage(uint32_t opt_mask)
94 {
95 fprintf(stderr,
96 "usage: sc_pinger [-D?]\n"
97 " [-a infile] [-o outfile] [-p port] [-U unix]\n"
98 " [-c probec] [-m method] [-t logfile]\n");
99
100 if(opt_mask == 0)
101 {
102 fprintf(stderr, " sc_pinger -?\n\n");
103 return;
104 }
105
106 if(opt_mask & OPT_HELP)
107 fprintf(stderr, " -? give an overview of the usage of sc_pinger\n");
108
109 if(opt_mask & OPT_ADDRFILE)
110 fprintf(stderr, " -a input addressfile\n");
111
112 if(opt_mask & OPT_OUTFILE)
113 fprintf(stderr, " -o output warts file\n");
114
115 if(opt_mask & OPT_PORT)
116 fprintf(stderr, " -p port to find scamper on\n");
117
118 if(opt_mask & OPT_UNIX)
119 fprintf(stderr, " -U unix domain to find scamper on\n");
120
121 if(opt_mask & OPT_DAEMON)
122 fprintf(stderr, " -D start as daemon\n");
123
124 if(opt_mask & OPT_COUNT)
125 fprintf(stderr, " -c [replyc]/probec\n");
126
127 if(opt_mask & OPT_TEXT)
128 fprintf(stderr, " -t logfile\n");
129
130 return;
131 }
132
check_options(int argc,char * argv[])133 static int check_options(int argc, char *argv[])
134 {
135 char *opt_count = NULL, *opt_port = NULL;
136 char *opts = "a:c:Dm:o:p:t:U:?", *ptr, *dup = NULL;
137 slist_t *list = NULL;
138 long lo, lo_rc, lo_pc;
139 int i, ch, rc = -1;
140
141 if((list = slist_alloc()) == NULL)
142 goto done;
143
144 while((ch = getopt(argc, argv, opts)) != -1)
145 {
146 switch(ch)
147 {
148 case 'a':
149 addrfile_name = optarg;
150 break;
151
152 case 'c':
153 if((opt_count = strdup(optarg)) == NULL)
154 goto done;
155 break;
156
157 case 'D':
158 options |= OPT_DAEMON;
159 break;
160
161 case 'm':
162 if((dup = strdup(optarg)) == NULL ||
163 slist_tail_push(list, dup) == NULL)
164 goto done;
165 dup = NULL;
166 break;
167
168 case 'o':
169 outfile_name = optarg;
170 break;
171
172 case 'p':
173 opt_port = optarg;
174 break;
175
176 case 't':
177 logfile_name = optarg;
178 break;
179
180 case 'U':
181 scamper_unix = optarg;
182 break;
183
184 case '?':
185 default:
186 usage(0xffffffff);
187 goto done;
188 }
189 }
190
191 if(addrfile_name == NULL || outfile_name == NULL ||
192 (opt_port == NULL && scamper_unix == NULL) ||
193 (opt_port != NULL && scamper_unix != NULL))
194 {
195 usage(OPT_ADDRFILE | OPT_OUTFILE | OPT_UNIX | OPT_PORT);
196 goto done;
197 }
198
199 if(opt_port != NULL)
200 {
201 if(string_tolong(opt_port, &lo) != 0 || lo < 1 || lo > 65535)
202 {
203 usage(OPT_PORT);
204 return -1;
205 }
206 scamper_port = lo;
207 }
208
209 if(opt_count != NULL)
210 {
211 ptr = opt_count;
212 while(*ptr != '\0' && *ptr != '/')
213 ptr++;
214 if(*ptr == '/')
215 {
216 *ptr = '\0';
217 ptr++;
218
219 if(string_isdigit(ptr) == 0 || string_isdigit(opt_count) == 0 ||
220 string_tolong(opt_count, &lo_rc) != 0 ||
221 string_tolong(ptr, &lo_pc) != 0 ||
222 lo_rc > lo_pc || lo_pc > 30 || lo_rc < 1 || lo_pc < 1)
223 {
224 usage(OPT_COUNT);
225 goto done;
226 }
227 reply_count = lo_rc;
228 probe_count = lo_pc;
229 }
230 else
231 {
232 if(string_isdigit(opt_count) == 0 ||
233 string_tolong(opt_count, &lo_pc) != 0)
234 {
235 usage(OPT_COUNT);
236 goto done;
237 }
238 reply_count = lo_pc;
239 probe_count = lo_pc;
240 }
241 }
242
243 if((methodc = slist_count(list)) > 0)
244 {
245 if((methods = malloc_zero(sizeof(char *) * methodc)) == NULL)
246 goto done;
247 i = 0;
248 while((ptr = slist_head_pop(list)) != NULL)
249 methods[i++] = ptr;
250 }
251 else
252 {
253 methodc = 3;
254 if((methods = malloc_zero(sizeof(char *) * 3)) == NULL ||
255 (methods[0] = strdup("icmp-echo")) == NULL ||
256 (methods[1] = strdup("udp-dport")) == NULL ||
257 (methods[2] = strdup("tcp-ack-sport -d 80")) == NULL)
258 goto done;
259 }
260
261 rc = 0;
262
263 done:
264 if(list != NULL) slist_free_cb(list, free);
265 if(opt_count != NULL) free(opt_count);
266 return rc;
267 }
268
print(char * format,...)269 static void print(char *format, ...)
270 {
271 struct timeval tv;
272 va_list ap;
273 char msg[512];
274
275 if(logfile_fd == NULL && (options & OPT_DAEMON) != 0)
276 return;
277
278 va_start(ap, format);
279 vsnprintf(msg, sizeof(msg), format, ap);
280 va_end(ap);
281
282 gettimeofday_wrap(&tv);
283
284 if((options & OPT_DAEMON) == 0)
285 printf("%ld: %s", (long int)tv.tv_sec, msg);
286
287 if(logfile_fd != NULL)
288 {
289 fprintf(logfile_fd, "%ld: %s", (long int)tv.tv_sec, msg);
290 fflush(logfile_fd);
291 }
292
293 return;
294 }
295
sc_pinger_cmp(const sc_pinger_t * a,const sc_pinger_t * b)296 static int sc_pinger_cmp(const sc_pinger_t *a, const sc_pinger_t *b)
297 {
298 return scamper_addr_cmp(a->dst, b->dst);
299 }
300
sc_pinger_free(sc_pinger_t * pinger)301 static void sc_pinger_free(sc_pinger_t *pinger)
302 {
303 if(pinger->dst != NULL) scamper_addr_free(pinger->dst);
304 free(pinger);
305 return;
306 }
307
do_addrfile_line(char * buf)308 static int do_addrfile_line(char *buf)
309 {
310 static int line = 0;
311 sc_pinger_t *pinger = NULL;
312 scamper_addr_t *sa = NULL;
313
314 line++;
315
316 if(buf[0] == '\0' || buf[0] == '#')
317 return 0;
318
319 if((sa = scamper_addr_resolve(AF_UNSPEC, buf)) == NULL)
320 {
321 print("could not resolve %s on line %d\n", buf, line);
322 goto err;
323 }
324
325 if((pinger = malloc_zero(sizeof(sc_pinger_t))) == NULL)
326 {
327 print("could not malloc pinger\n");
328 goto err;
329 }
330 pinger->dst = sa; sa = NULL;
331 if(slist_tail_push(virgin, pinger) == NULL)
332 {
333 print("could not push %s onto list\n", buf);
334 goto err;
335 }
336
337 return 0;
338
339 err:
340 if(pinger != NULL) sc_pinger_free(pinger);
341 if(sa != NULL) scamper_addr_free(sa);
342 return -1;
343 }
344
do_addrfile(void)345 static int do_addrfile(void)
346 {
347 size_t start, end, off;
348 ssize_t ss;
349
350 if((ss = read(addrfile_fd, addrfile_buf + addrfile_off,
351 addrfile_len - addrfile_off - 1)) < 0)
352 goto err;
353
354 start = 0; off = 0;
355 end = addrfile_off + ss;
356
357 while(off <= end)
358 {
359 if(off == end && ss != 0)
360 break;
361 if(addrfile_buf[off] == '\n' || (off == end && start < off))
362 {
363 addrfile_buf[off] = '\0';
364 if(do_addrfile_line(addrfile_buf + start) != 0)
365 goto err;
366 start = ++off;
367 }
368 else
369 {
370 ++off;
371 }
372 }
373
374 if(ss == 0)
375 {
376 close(addrfile_fd); addrfile_fd = -1;
377 return 0;
378 }
379
380 if(start == 0)
381 {
382 addrfile_len += 8192;
383 addrfile_off = off;
384 if(realloc_wrap((void **)&addrfile_buf, addrfile_len) != 0)
385 {
386 print("%s: could not realloc %d bytes\n", __func__, addrfile_len);
387 goto err;
388 }
389 }
390 else
391 {
392 memmove(addrfile_buf, addrfile_buf+start, end - start);
393 addrfile_off = end - start;
394 }
395
396 return 0;
397
398 err:
399 close(addrfile_fd); addrfile_fd = -1;
400 return -1;
401 }
402
do_decoderead(void)403 static int do_decoderead(void)
404 {
405 scamper_ping_t *ping = NULL;
406 scamper_ping_reply_t *reply;
407 sc_pinger_t fm, *pinger;
408 void *data;
409 uint16_t type;
410 char buf[128];
411 int rc = -1;
412 int i, replyc = 0;
413
414 /* try and read a traceroute from the warts decoder */
415 if(scamper_file_read(decode_in, ffilter, &type, &data) != 0)
416 {
417 print("%s: scamper_file_read errno %d\n", __func__, errno);
418 goto done;
419 }
420
421 if(data == NULL)
422 {
423 if(scamper_file_geteof(decode_in) != 0)
424 {
425 scamper_file_close(decode_in);
426 decode_in = NULL;
427 decode_in_fd = -1;
428 }
429 rc = 0;
430 goto done;
431 }
432
433 if(type == SCAMPER_FILE_OBJ_PING)
434 ping = (scamper_ping_t *)data;
435 else
436 {
437 print("%s: unknown type %d\n", __func__, type);
438 goto done;
439 }
440
441 scamper_addr_tostr(ping->dst, buf, sizeof(buf));
442 fm.dst = ping->dst;
443 if((pinger = splaytree_find(tree, &fm)) == NULL)
444 {
445 print("%s: could not find dst %s\n", __func__, buf);
446 goto done;
447 }
448 if(splaytree_remove_node(tree, pinger->node) != 0)
449 {
450 print("%s: could not remove node %s\n", __func__, buf);
451 goto done;
452 }
453 pinger->node = NULL;
454 pinger->step++;
455
456 for(i=0; i<ping->ping_sent; i++)
457 {
458 if((reply = ping->ping_replies[i]) == NULL ||
459 (scamper_addr_cmp(ping->dst, reply->addr) != 0 &&
460 SCAMPER_PING_REPLY_FROM_TARGET(ping, reply) == 0))
461 continue;
462 replyc++;
463 }
464
465 /* try with the next method if necessary */
466 if(replyc < reply_count && pinger->step < methodc)
467 {
468 if(slist_tail_push(waiting, pinger) == NULL)
469 {
470 print("%s: could not try next method for %s\n", __func__, buf);
471 goto done;
472 }
473 }
474 else
475 {
476 completed++;
477 sc_pinger_free(pinger);
478 }
479 rc = 0;
480
481 done:
482 if(ping != NULL) scamper_ping_free(ping);
483 return rc;
484 }
485
do_method(void)486 static int do_method(void)
487 {
488 char cmd[512], addr[128];
489 sc_pinger_t *pinger;
490 size_t off = 0;
491
492 if(more < 1)
493 return 0;
494
495 if((pinger = slist_head_pop(waiting)) == NULL &&
496 (pinger = slist_head_pop(virgin)) == NULL)
497 {
498 if(addrfile_fd == -1)
499 return 0;
500 if(do_addrfile() != 0)
501 return -1;
502 if((pinger = slist_head_pop(virgin)) == NULL)
503 return 0;
504 }
505
506 scamper_addr_tostr(pinger->dst, addr, sizeof(addr));
507 string_concat(cmd, sizeof(cmd), &off, "ping -c %d -o %d -P %s %s\n",
508 probe_count, reply_count, methods[pinger->step], addr);
509
510 if((pinger->node = splaytree_insert(tree, pinger)) == NULL)
511 {
512 print("%s: could not add %s to tree\n", __func__, addr);
513 return -1;
514 }
515
516 /* got a command, send it */
517 if(scamper_writebuf_send(scamper_wb, cmd, off) != 0)
518 {
519 print("%s: could not send %s\n", __func__, cmd);
520 return -1;
521 }
522 more--;
523
524 print("p %d, c %d: %s", splaytree_count(tree), completed, cmd);
525
526 return 0;
527 }
528
529 /*
530 * do_files
531 *
532 * open a socketpair that can be used to feed warts data into one end and
533 * have the scamper_file routines decode it via the other end.
534 *
535 * also open a file to send the binary warts data file to.
536 */
do_files(void)537 static int do_files(void)
538 {
539 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
540 int fd_flags = O_WRONLY | O_CREAT | O_TRUNC;
541 int pair[2];
542
543 if((outfile_fd = open(outfile_name, fd_flags, mode)) == -1)
544 {
545 print("%s: could not open %s\n", __func__, outfile_name);
546 return -1;
547 }
548
549 /*
550 * setup a socketpair that is used to decode warts from a binary input.
551 * pair[0] is used to write to the file, while pair[1] is used by
552 * the scamper_file_t routines to parse the warts data.
553 */
554 if(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) != 0)
555 {
556 print("%s: could not socketpair\n", __func__);
557 return -1;
558 }
559
560 decode_in_fd = pair[0];
561 decode_out_fd = pair[1];
562 decode_in = scamper_file_openfd(decode_in_fd, NULL, 'r', "warts");
563 if(decode_in == NULL)
564 {
565 print("%s: could not open decode_in\n");
566 return -1;
567 }
568
569 if(fcntl_set(decode_in_fd, O_NONBLOCK) == -1 ||
570 fcntl_set(decode_out_fd, O_NONBLOCK) == -1 ||
571 (decode_wb = scamper_writebuf_alloc()) == NULL)
572 {
573 print("%s: could not open decode_wb\n");
574 return -1;
575 }
576
577 return 0;
578 }
579
580 /*
581 * do_scamperconnect
582 *
583 * allocate socket and connect to scamper process listening on the port
584 * specified.
585 */
do_scamperconnect(void)586 static int do_scamperconnect(void)
587 {
588 #ifdef HAVE_SOCKADDR_UN
589 struct sockaddr_un sn;
590 #endif
591
592 struct sockaddr_in sin;
593 struct in_addr in;
594
595 if(scamper_port != 0)
596 {
597 inet_aton("127.0.0.1", &in);
598 sockaddr_compose((struct sockaddr *)&sin, AF_INET, &in, scamper_port);
599 if((scamper_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
600 {
601 print("%s: could not allocate new socket\n", __func__);
602 return -1;
603 }
604 if(connect(scamper_fd, (const struct sockaddr *)&sin, sizeof(sin)) != 0)
605 {
606 print("%s: could not connect to scamper process on port %d\n",
607 __func__, scamper_port);
608 return -1;
609 }
610 return 0;
611 }
612 #ifdef HAVE_SOCKADDR_UN
613 else if(scamper_unix != NULL)
614 {
615 if(sockaddr_compose_un((struct sockaddr *)&sn, scamper_unix) != 0)
616 {
617 print("%s: could not build sockaddr_un\n", __func__);
618 return -1;
619 }
620 if((scamper_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
621 {
622 print("%s: could not allocate unix domain socket\n", __func__);
623 return -1;
624 }
625 if(connect(scamper_fd, (const struct sockaddr *)&sn, sizeof(sn)) != 0)
626 {
627 print("%s: could not connect to scamper process\n", __func__);
628 return -1;
629 }
630 return 0;
631 }
632 #endif
633
634 print("%s: :(\n", __func__);
635 return -1;
636 }
637
do_scamperread_line(void * param,uint8_t * buf,size_t linelen)638 static int do_scamperread_line(void *param, uint8_t *buf, size_t linelen)
639 {
640 char *head = (char *)buf;
641 uint8_t uu[64];
642 size_t uus;
643 long l;
644
645 /* skip empty lines */
646 if(head[0] == '\0')
647 return 0;
648
649 /* if currently decoding data, then pass it to uudecode */
650 if(data_left > 0)
651 {
652 uus = sizeof(uu);
653 if(uudecode_line(head, linelen, uu, &uus) != 0)
654 {
655 print("%s: could not uudecode_line\n", __func__);
656 error = 1;
657 return -1;
658 }
659
660 if(uus != 0)
661 {
662 scamper_writebuf_send(decode_wb, uu, uus);
663 write_wrap(outfile_fd, uu, NULL, uus);
664 }
665
666 data_left -= (linelen + 1);
667 return 0;
668 }
669
670 /* feedback letting us know that the command was accepted */
671 if(linelen >= 2 && strncasecmp(head, "OK", 2) == 0)
672 return 0;
673
674 /* if the scamper process is asking for more tasks, give it more */
675 if(linelen == 4 && strncasecmp(head, "MORE", linelen) == 0)
676 {
677 more++;
678 if(do_method() != 0)
679 return -1;
680 return 0;
681 }
682
683 /* new piece of data */
684 if(linelen > 5 && strncasecmp(head, "DATA ", 5) == 0)
685 {
686 if(string_isnumber(head+5) == 0 || string_tolong(head+5, &l) != 0)
687 {
688 print("%s: could not parse %s\n", __func__, head);
689 error = 1;
690 return -1;
691 }
692 data_left = l;
693 return 0;
694 }
695
696 /* feedback letting us know that the command was not accepted */
697 if(linelen >= 3 && strncasecmp(head, "ERR", 3) == 0)
698 {
699 error = 1;
700 return -1;
701 }
702
703 print("%s: unknown response '%s'\n", __func__, head);
704 error = 1;
705 return -1;
706 }
707
do_scamperread(void)708 static int do_scamperread(void)
709 {
710 ssize_t rc;
711 uint8_t buf[512];
712
713 if((rc = read(scamper_fd, buf, sizeof(buf))) > 0)
714 {
715 scamper_linepoll_handle(scamper_lp, buf, rc);
716 return 0;
717 }
718 else if(rc == 0)
719 {
720 print("%s: disconnected\n", __func__);
721 close(scamper_fd); scamper_fd = -1;
722 return 0;
723 }
724 else if(errno == EINTR || errno == EAGAIN)
725 {
726 return 0;
727 }
728
729 fprintf(stderr, "could not read: errno %d\n", errno);
730 return -1;
731 }
732
pinger_data(void)733 static int pinger_data(void)
734 {
735 uint16_t types[] = {SCAMPER_FILE_OBJ_PING};
736 int typec = sizeof(types) / sizeof(uint16_t);
737 struct timeval tv, *tv_ptr;
738 fd_set rfds, wfds, *wfdsp;
739 int nfds;
740
741 #ifdef HAVE_DAEMON
742 /* start a daemon if asked to */
743 if((options & OPT_DAEMON) != 0 && daemon(1, 0) != 0)
744 {
745 fprintf(stderr, "could not daemon\n");
746 return -1;
747 }
748 #endif
749
750 if((logfile_name != NULL && (logfile_fd=fopen(logfile_name, "w")) == NULL) ||
751 (addrfile_fd = open(addrfile_name, O_RDONLY)) < 0 ||
752 (addrfile_buf = malloc(addrfile_len)) == NULL ||
753 (ffilter = scamper_file_filter_alloc(types, typec)) == NULL ||
754 (tree = splaytree_alloc((splaytree_cmp_t)sc_pinger_cmp)) == NULL ||
755 (virgin = slist_alloc()) == NULL || (waiting = slist_alloc()) == NULL ||
756 do_scamperconnect() != 0 || do_files() != 0 ||
757 (scamper_lp = scamper_linepoll_alloc(do_scamperread_line, NULL)) == NULL ||
758 (scamper_wb = scamper_writebuf_alloc()) == NULL)
759 {
760 print("%s: could not init\n", __func__);
761 return -1;
762 }
763 scamper_writebuf_send(scamper_wb, "attach\n", 7);
764
765 while(error == 0)
766 {
767 /*
768 * need to set a timeout on select if scamper's processing window is
769 * not full and there is a trace in the waiting queue.
770 */
771 tv_ptr = NULL;
772 if(more > 0 &&
773 (slist_count(waiting) > 0 || slist_count(virgin) > 0 ||
774 addrfile_fd != -1))
775 {
776 memset(&tv, 0, sizeof(tv));
777 tv_ptr = &tv;
778 }
779
780 nfds = 0; FD_ZERO(&rfds); FD_ZERO(&wfds); wfdsp = NULL;
781 if(scamper_fd < 0 && decode_in_fd < 0)
782 break;
783
784 if(scamper_fd >= 0)
785 {
786 FD_SET(scamper_fd, &rfds);
787 if(nfds < scamper_fd) nfds = scamper_fd;
788 if(scamper_writebuf_len(scamper_wb) > 0)
789 {
790 FD_SET(scamper_fd, &wfds);
791 wfdsp = &wfds;
792 }
793 }
794
795 if(decode_in_fd >= 0)
796 {
797 FD_SET(decode_in_fd, &rfds);
798 if(nfds < decode_in_fd) nfds = decode_in_fd;
799 }
800
801 if(decode_out_fd >= 0 && scamper_writebuf_len(decode_wb) > 0)
802 {
803 FD_SET(decode_out_fd, &wfds);
804 wfdsp = &wfds;
805 if(nfds < decode_out_fd) nfds = decode_out_fd;
806 }
807
808 if(splaytree_count(tree) == 0 && slist_count(virgin) == 0 &&
809 slist_count(waiting) == 0 && addrfile_fd == -1)
810 {
811 print("%s: done\n", __func__);
812 break;
813 }
814
815 if(select(nfds+1, &rfds, wfdsp, NULL, tv_ptr) < 0)
816 {
817 if(errno == EINTR) continue;
818 print("%s: select error\n", __func__);
819 break;
820 }
821
822 if(more > 0)
823 {
824 if(do_method() != 0)
825 return -1;
826 }
827
828 if(scamper_fd >= 0)
829 {
830 if(FD_ISSET(scamper_fd, &rfds) && do_scamperread() != 0)
831 return -1;
832 if(wfdsp != NULL && FD_ISSET(scamper_fd, wfdsp) &&
833 scamper_writebuf_write(scamper_fd, scamper_wb) != 0)
834 return -1;
835 }
836
837 if(decode_in_fd >= 0)
838 {
839 if(FD_ISSET(decode_in_fd, &rfds) && do_decoderead() != 0)
840 return -1;
841 }
842
843 if(decode_out_fd >= 0)
844 {
845 if(wfdsp != NULL && FD_ISSET(decode_out_fd, wfdsp) &&
846 scamper_writebuf_write(decode_out_fd, decode_wb) != 0)
847 return -1;
848
849 if(scamper_fd < 0 && scamper_writebuf_len(decode_wb) == 0)
850 {
851 close(decode_out_fd);
852 decode_out_fd = -1;
853 }
854 }
855 }
856
857 return 0;
858 }
859
cleanup(void)860 static void cleanup(void)
861 {
862 int i;
863
864 if(methods != NULL)
865 {
866 for(i=0; i<methodc; i++)
867 if(methods[i] != NULL)
868 free(methods[i]);
869 free(methods);
870 methods = NULL;
871 }
872
873 if(virgin != NULL)
874 {
875 slist_free_cb(virgin, (slist_free_t)sc_pinger_free);
876 virgin = NULL;
877 }
878
879 if(waiting != NULL)
880 {
881 slist_free_cb(waiting, (slist_free_t)sc_pinger_free);
882 waiting = NULL;
883 }
884
885 if(tree != NULL)
886 {
887 splaytree_free(tree, (splaytree_free_t)sc_pinger_free);
888 tree = NULL;
889 }
890
891 if(decode_in != NULL)
892 {
893 scamper_file_close(decode_in);
894 decode_in = NULL;
895 }
896
897 if(ffilter != NULL)
898 {
899 scamper_file_filter_free(ffilter);
900 ffilter = NULL;
901 }
902
903 if(decode_wb != NULL)
904 {
905 scamper_writebuf_free(decode_wb);
906 decode_wb = NULL;
907 }
908
909 if(scamper_wb != NULL)
910 {
911 scamper_writebuf_free(scamper_wb);
912 scamper_wb = NULL;
913 }
914
915 if(scamper_lp != NULL)
916 {
917 scamper_linepoll_free(scamper_lp, 0);
918 scamper_lp = NULL;
919 }
920
921 if(logfile_fd != NULL)
922 {
923 fclose(logfile_fd);
924 logfile_fd = NULL;
925 }
926
927 if(addrfile_buf != NULL)
928 {
929 free(addrfile_buf);
930 addrfile_buf = NULL;
931 }
932
933 return;
934 }
935
main(int argc,char * argv[])936 int main(int argc, char *argv[])
937 {
938 #if defined(DMALLOC)
939 free(malloc(1));
940 #endif
941
942 atexit(cleanup);
943
944 if(check_options(argc, argv) != 0)
945 return -1;
946
947 return pinger_data();
948 }
949