1 /*
2 * scamper_task.c
3 *
4 * $Id: scamper_task.c,v 1.71 2020/03/28 20:45:52 mjl Exp $
5 *
6 * Copyright (C) 2005-2006 Matthew Luckie
7 * Copyright (C) 2006-2011 The University of Waikato
8 * Copyright (C) 2012-2015 The Regents of the University of California
9 * Copyright (C) 2016-2020 Matthew Luckie
10 * Author: Matthew Luckie
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, version 2.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 #include "internal.h"
31
32 #include "scamper.h"
33 #include "scamper_addr.h"
34 #include "scamper_icmp_resp.h"
35 #include "scamper_fds.h"
36 #include "scamper_task.h"
37 #include "scamper_queue.h"
38 #include "scamper_debug.h"
39 #include "scamper_list.h"
40 #include "scamper_cyclemon.h"
41 #include "scamper_outfiles.h"
42 #include "scamper_sources.h"
43 #include "scamper_file.h"
44 #include "scamper_rtsock.h"
45 #include "scamper_dl.h"
46 #include "mjl_list.h"
47 #include "mjl_splaytree.h"
48 #include "mjl_patricia.h"
49 #include "utils.h"
50
51 struct scamper_task
52 {
53 /* the data pointer points to the collected data */
54 void *data;
55
56 /* any state kept during the data collection is kept here */
57 void *state;
58
59 /* state / details kept internally to the task */
60 dlist_t *onhold;
61
62 /* various callbacks that scamper uses to handle this task */
63 scamper_task_funcs_t *funcs;
64
65 /* pointer to a queue structure that manages this task in the queues */
66 scamper_queue_t *queue;
67
68 /* pointer to where the task came from */
69 scamper_sourcetask_t *sourcetask;
70
71 /* pointer to cycle monitor structure, if used */
72 struct scamper_cyclemon *cyclemon;
73
74 /* signature of probes sent by this task */
75 slist_t *siglist;
76
77 /* list of ancillary data */
78 dlist_t *ancillary;
79
80 /* file descriptors held by the task */
81 scamper_fd_t **fds;
82 int fdc;
83 };
84
85 struct scamper_task_anc
86 {
87 void *data;
88 void (*freedata)(void *);
89 dlist_node_t *node;
90 };
91
92 typedef struct s2t
93 {
94 scamper_task_sig_t *sig;
95 scamper_task_t *task;
96 void *node;
97 } s2t_t;
98
99 typedef struct task_onhold
100 {
101 void (*unhold)(void *param);
102 void *param;
103 } task_onhold_t;
104
105 static patricia_t *tx_ip4 = NULL;
106 static patricia_t *tx_ip6 = NULL;
107 static patricia_t *tx_nd4 = NULL;
108 static patricia_t *tx_nd6 = NULL;
109 static dlist_t *sniff = NULL;
110 static splaytree_t *host = NULL;
111
tx_ip_cmp(const s2t_t * a,const s2t_t * b)112 static int tx_ip_cmp(const s2t_t *a, const s2t_t *b)
113 {
114 assert(a->sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_IP);
115 assert(b->sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_IP);
116 return scamper_addr_cmp(a->sig->sig_tx_ip_dst, b->sig->sig_tx_ip_dst);
117 }
118
tx_ip_bit(const s2t_t * s2t,int bit)119 static int tx_ip_bit(const s2t_t *s2t, int bit)
120 {
121 assert(s2t->sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_IP);
122 return scamper_addr_bit(s2t->sig->sig_tx_ip_dst, bit);
123 }
124
tx_ip_fbd(const s2t_t * a,const s2t_t * b)125 static int tx_ip_fbd(const s2t_t *a, const s2t_t *b)
126 {
127 assert(a->sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_IP);
128 assert(b->sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_IP);
129 return scamper_addr_fbd(a->sig->sig_tx_ip_dst, b->sig->sig_tx_ip_dst);
130 }
131
tx_nd_cmp(const s2t_t * a,const s2t_t * b)132 static int tx_nd_cmp(const s2t_t *a, const s2t_t *b)
133 {
134 assert(a->sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_ND);
135 assert(b->sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_ND);
136 return scamper_addr_cmp(a->sig->sig_tx_nd_ip, b->sig->sig_tx_nd_ip);
137 }
138
tx_nd_bit(const s2t_t * s2t,int bit)139 static int tx_nd_bit(const s2t_t *s2t, int bit)
140 {
141 assert(s2t->sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_ND);
142 return scamper_addr_bit(s2t->sig->sig_tx_nd_ip, bit);
143 }
144
tx_nd_fbd(const s2t_t * a,const s2t_t * b)145 static int tx_nd_fbd(const s2t_t *a, const s2t_t *b)
146 {
147 assert(a->sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_ND);
148 assert(b->sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_ND);
149 return scamper_addr_fbd(a->sig->sig_tx_nd_ip, b->sig->sig_tx_nd_ip);
150 }
151
host_cmp(const s2t_t * a,const s2t_t * b)152 static int host_cmp(const s2t_t *a, const s2t_t *b)
153 {
154 int i;
155 assert(a->sig->sig_type == SCAMPER_TASK_SIG_TYPE_HOST);
156 assert(b->sig->sig_type == SCAMPER_TASK_SIG_TYPE_HOST);
157 if((i = strcasecmp(a->sig->sig_host_name, b->sig->sig_host_name)) != 0)
158 return i;
159 if(a->sig->sig_host_type < b->sig->sig_host_type)
160 return -1;
161 if(a->sig->sig_host_type > b->sig->sig_host_type)
162 return 1;
163 return 0;
164 }
165
tx_ip_check(scamper_dl_rec_t * dl)166 static void tx_ip_check(scamper_dl_rec_t *dl)
167 {
168 scamper_task_sig_t sig;
169 scamper_addr_t addr, addr2buf, *addr2 = NULL;
170 patricia_t *pt;
171 s2t_t fm, *s2t;
172
173 if(SCAMPER_DL_IS_IPV4(dl))
174 {
175 addr.type = SCAMPER_ADDR_TYPE_IPV4;
176 pt = tx_ip4;
177 }
178 else if(SCAMPER_DL_IS_IPV6(dl))
179 {
180 addr.type = SCAMPER_ADDR_TYPE_IPV6;
181 pt = tx_ip6;
182 }
183 else return;
184
185 if(dl->dl_ip_off != 0)
186 {
187 addr.addr = dl->dl_ip_src;
188 }
189 else if(SCAMPER_DL_IS_TCP(dl))
190 {
191 if((dl->dl_tcp_flags & TH_SYN) && (dl->dl_tcp_flags & TH_ACK) == 0)
192 addr.addr = dl->dl_ip_dst;
193 else
194 addr.addr = dl->dl_ip_src;
195 }
196 else if(SCAMPER_DL_IS_ICMP(dl))
197 {
198 if(SCAMPER_DL_IS_ICMP_ECHO_REQUEST(dl))
199 addr.addr = dl->dl_ip_dst;
200 else if(SCAMPER_DL_IS_ICMP_ECHO_REPLY(dl))
201 addr.addr = dl->dl_ip_src;
202 else if(SCAMPER_DL_IS_ICMP_TTL_EXP(dl))
203 addr.addr = dl->dl_icmp_ip_dst;
204 else if(SCAMPER_DL_IS_ICMP_UNREACH(dl))
205 addr.addr = dl->dl_icmp_ip_dst;
206 else if(SCAMPER_DL_IS_ICMP_PACKET_TOO_BIG(dl))
207 addr.addr = dl->dl_icmp_ip_dst;
208 else
209 return;
210 }
211 else if(SCAMPER_DL_IS_UDP(dl))
212 {
213 addr.addr = dl->dl_ip_dst;
214 addr2buf.type = addr.type;
215 addr2buf.addr = dl->dl_ip_src; addr2 = &addr2buf;
216 }
217 else
218 {
219 addr.addr = dl->dl_ip_dst;
220 }
221
222 fm.sig = &sig;
223 sig.sig_type = SCAMPER_TASK_SIG_TYPE_TX_IP;
224 sig.sig_tx_ip_dst = &addr;
225
226 if((s2t = patricia_find(pt, &fm)) != NULL &&
227 s2t->task->funcs->handle_dl != NULL)
228 {
229 s2t->task->funcs->handle_dl(s2t->task, dl);
230 }
231 else if(addr2 != NULL)
232 {
233 sig.sig_tx_ip_dst = addr2;
234 if((s2t = patricia_find(pt, &fm)) != NULL &&
235 s2t->task->funcs->handle_dl != NULL)
236 {
237 s2t->task->funcs->handle_dl(s2t->task, dl);
238 }
239 }
240
241 return;
242 }
243
tx_nd_check(scamper_dl_rec_t * dl)244 static void tx_nd_check(scamper_dl_rec_t *dl)
245 {
246 scamper_task_sig_t sig;
247 scamper_addr_t ip;
248 struct in_addr ip4;
249 struct in6_addr ip6;
250 patricia_t *pt;
251 s2t_t fm, *s2t;
252
253 if(SCAMPER_DL_IS_ARP_OP_REPLY(dl) && SCAMPER_DL_IS_ARP_PRO_IPV4(dl))
254 {
255 if(patricia_count(tx_nd4) <= 0)
256 return;
257 ip.type = SCAMPER_ADDR_TYPE_IPV4;
258 memcpy(&ip4, dl->dl_arp_spa, sizeof(ip4));
259 ip.addr = &ip4;
260 pt = tx_nd4;
261 }
262 else if(SCAMPER_DL_IS_ICMP6_ND_NADV(dl))
263 {
264 if(patricia_count(tx_nd6) <= 0)
265 return;
266 ip.type = SCAMPER_ADDR_TYPE_IPV6;
267 memcpy(&ip6, dl->dl_icmp6_nd_target, sizeof(ip6));
268 ip.addr = &ip6;
269 pt = tx_nd6;
270 }
271 else return;
272
273 sig.sig_type = SCAMPER_TASK_SIG_TYPE_TX_ND;
274 sig.sig_tx_nd_ip = &ip;
275 fm.sig = &sig;
276 if((s2t = patricia_find(pt, &fm)) == NULL)
277 return;
278
279 if(s2t->task->funcs->handle_dl != NULL)
280 s2t->task->funcs->handle_dl(s2t->task, dl);
281
282 return;
283 }
284
sniff_check(scamper_dl_rec_t * dl)285 static void sniff_check(scamper_dl_rec_t *dl)
286 {
287 scamper_task_sig_t *sig;
288 s2t_t *s2t;
289 dlist_node_t *n;
290 scamper_addr_t src;
291 uint16_t id;
292
293 if(dlist_count(sniff) <= 0)
294 return;
295
296 if(SCAMPER_DL_IS_ICMP_ECHO_REPLY(dl))
297 id = dl->dl_icmp_id;
298 else if(SCAMPER_DL_IS_ICMP_Q_ICMP_ECHO(dl))
299 id = dl->dl_icmp_icmp_id;
300 else
301 return;
302
303 if(SCAMPER_DL_IS_IPV4(dl))
304 src.type = SCAMPER_ADDR_TYPE_IPV4;
305 else if(SCAMPER_DL_IS_IPV6(dl))
306 src.type = SCAMPER_ADDR_TYPE_IPV6;
307 else
308 return;
309 src.addr = dl->dl_ip_dst;
310
311 for(n = dlist_head_node(sniff); n != NULL; n = dlist_node_next(n))
312 {
313 s2t = dlist_node_item(n); sig = s2t->sig;
314 if(sig->sig_sniff_icmp_id != id)
315 continue;
316 if(scamper_addr_cmp(sig->sig_sniff_src, &src) != 0)
317 continue;
318
319 if(s2t->task->funcs->handle_dl != NULL)
320 s2t->task->funcs->handle_dl(s2t->task, dl);
321 }
322
323 return;
324 }
325
s2t_free(s2t_t * s2t)326 static void s2t_free(s2t_t *s2t)
327 {
328 scamper_task_sig_t *sig = s2t->sig;
329
330 if(s2t == NULL)
331 return;
332
333 if(s2t->node != NULL)
334 {
335 if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_IP)
336 {
337 if(sig->sig_tx_ip_dst->type == SCAMPER_ADDR_TYPE_IPV4)
338 patricia_remove_node(tx_ip4, s2t->node);
339 else
340 patricia_remove_node(tx_ip6, s2t->node);
341 }
342 else if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_ND)
343 {
344 if(sig->sig_tx_nd_ip->type == SCAMPER_ADDR_TYPE_IPV4)
345 patricia_remove_node(tx_nd4, s2t->node);
346 else
347 patricia_remove_node(tx_nd6, s2t->node);
348 }
349 else if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_SNIFF)
350 dlist_node_pop(sniff, s2t->node);
351 else if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_HOST)
352 splaytree_remove_node(host, s2t->node);
353 }
354
355 free(s2t);
356 return;
357 }
358
scamper_task_sig_tostr(scamper_task_sig_t * sig,char * buf,size_t len)359 char *scamper_task_sig_tostr(scamper_task_sig_t *sig, char *buf, size_t len)
360 {
361 char tmp[64];
362 size_t off = 0;
363
364 if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_IP)
365 string_concat(buf, len, &off, "ip %s",
366 scamper_addr_tostr(sig->sig_tx_ip_dst, tmp, sizeof(tmp)));
367 else if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_ND)
368 string_concat(buf, len, &off, "nd %s",
369 scamper_addr_tostr(sig->sig_tx_nd_ip, tmp, sizeof(tmp)));
370 else if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_SNIFF)
371 string_concat(buf, len, &off, "sniff %s icmp-id %04x",
372 scamper_addr_tostr(sig->sig_sniff_src, tmp, sizeof(tmp)),
373 sig->sig_sniff_icmp_id);
374 else if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_HOST)
375 string_concat(buf, len, &off, "host %s %u",
376 sig->sig_host_name, sig->sig_host_type);
377 else
378 return NULL;
379
380 return buf;
381 }
382
scamper_task_sig_alloc(uint8_t type)383 scamper_task_sig_t *scamper_task_sig_alloc(uint8_t type)
384 {
385 scamper_task_sig_t *sig;
386 if((sig = malloc_zero(sizeof(scamper_task_sig_t))) != NULL)
387 sig->sig_type = type;
388 return sig;
389 }
390
scamper_task_sig_free(scamper_task_sig_t * sig)391 void scamper_task_sig_free(scamper_task_sig_t *sig)
392 {
393 if(sig == NULL)
394 return;
395
396 switch(sig->sig_type)
397 {
398 case SCAMPER_TASK_SIG_TYPE_TX_IP:
399 if(sig->sig_tx_ip_dst != NULL) scamper_addr_free(sig->sig_tx_ip_dst);
400 if(sig->sig_tx_ip_src != NULL) scamper_addr_free(sig->sig_tx_ip_src);
401 break;
402
403 case SCAMPER_TASK_SIG_TYPE_TX_ND:
404 if(sig->sig_tx_nd_ip != NULL) scamper_addr_free(sig->sig_tx_nd_ip);
405 break;
406
407 case SCAMPER_TASK_SIG_TYPE_SNIFF:
408 if(sig->sig_sniff_src != NULL) scamper_addr_free(sig->sig_sniff_src);
409 break;
410
411 case SCAMPER_TASK_SIG_TYPE_HOST:
412 if(sig->sig_host_name != NULL) free(sig->sig_host_name);
413 break;
414 }
415
416 free(sig);
417 return;
418 }
419
scamper_task_anc_add(scamper_task_t * task,void * data,void (* freedata)(void *))420 scamper_task_anc_t *scamper_task_anc_add(scamper_task_t *task, void *data,
421 void (*freedata)(void *))
422 {
423 scamper_task_anc_t *anc = NULL;
424 if(task->ancillary == NULL && (task->ancillary = dlist_alloc()) == NULL)
425 return NULL;
426 if((anc = malloc_zero(sizeof(scamper_task_anc_t))) == NULL)
427 return NULL;
428 anc->data = data;
429 anc->freedata = freedata;
430 if((anc->node = dlist_tail_push(task->ancillary, anc)) == NULL)
431 {
432 free(anc);
433 return NULL;
434 }
435 return anc;
436 }
437
scamper_task_anc_del(scamper_task_t * task,scamper_task_anc_t * anc)438 void scamper_task_anc_del(scamper_task_t *task, scamper_task_anc_t *anc)
439 {
440 if(anc == NULL)
441 return;
442 dlist_node_pop(task->ancillary, anc->node);
443 free(anc);
444 return;
445 }
446
scamper_task_sig_add(scamper_task_t * task,scamper_task_sig_t * sig)447 int scamper_task_sig_add(scamper_task_t *task, scamper_task_sig_t *sig)
448 {
449 s2t_t *s2t;
450 if((s2t = malloc_zero(sizeof(s2t_t))) == NULL)
451 return -1;
452 s2t->sig = sig;
453 s2t->task = task;
454 if(slist_tail_push(task->siglist, s2t) == NULL)
455 {
456 free(s2t);
457 return -1;
458 }
459 return 0;
460 }
461
scamper_task_find(scamper_task_sig_t * sig)462 scamper_task_t *scamper_task_find(scamper_task_sig_t *sig)
463 {
464 s2t_t fm, *s2t;
465
466 fm.sig = sig;
467 if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_IP)
468 {
469 if(sig->sig_tx_ip_dst->type == SCAMPER_ADDR_TYPE_IPV4)
470 s2t = patricia_find(tx_ip4, &fm);
471 else
472 s2t = patricia_find(tx_ip6, &fm);
473 }
474 else if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_ND)
475 {
476 if(sig->sig_tx_nd_ip->type == SCAMPER_ADDR_TYPE_IPV4)
477 s2t = patricia_find(tx_nd4, &fm);
478 else
479 s2t = patricia_find(tx_nd6, &fm);
480 }
481 else
482 return NULL;
483
484 if(s2t != NULL)
485 return s2t->task;
486 return NULL;
487 }
488
scamper_task_sig_deinstall(scamper_task_t * task)489 void scamper_task_sig_deinstall(scamper_task_t *task)
490 {
491 s2t_t *s2t;
492 scamper_task_sig_t *sig;
493 slist_node_t *n;
494
495 for(n=slist_head_node(task->siglist); n != NULL; n = slist_node_next(n))
496 {
497 s2t = slist_node_item(n); sig = s2t->sig;
498 s2t_free(s2t);
499 scamper_task_sig_free(sig);
500 }
501
502 return;
503 }
504
scamper_task_sig_install(scamper_task_t * task)505 int scamper_task_sig_install(scamper_task_t *task)
506 {
507 scamper_task_sig_t *sig;
508 scamper_task_t *tf;
509 s2t_t *s2t;
510 slist_node_t *n;
511
512 if(slist_count(task->siglist) < 1)
513 {
514 printerror(__func__, "no signatures for task");
515 return -1;
516 }
517
518 for(n=slist_head_node(task->siglist); n != NULL; n = slist_node_next(n))
519 {
520 s2t = slist_node_item(n); sig = s2t->sig;
521
522 /* check if another task has this signature already */
523 if((tf = scamper_task_find(sig)) != NULL)
524 {
525 if(tf != task)
526 goto err;
527 continue;
528 }
529
530 if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_IP)
531 {
532 if(sig->sig_tx_ip_dst->type == SCAMPER_ADDR_TYPE_IPV4)
533 s2t->node = patricia_insert(tx_ip4, s2t);
534 else
535 s2t->node = patricia_insert(tx_ip6, s2t);
536 }
537 else if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_ND)
538 {
539 if(sig->sig_tx_nd_ip->type == SCAMPER_ADDR_TYPE_IPV4)
540 s2t->node = patricia_insert(tx_nd4, s2t);
541 else
542 s2t->node = patricia_insert(tx_nd6, s2t);
543 }
544 else if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_SNIFF)
545 s2t->node = dlist_tail_push(sniff, s2t);
546 else if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_HOST)
547 s2t->node = splaytree_insert(host, s2t);
548
549 if(s2t->node == NULL)
550 {
551 scamper_debug(__func__, "could not install sig");
552 goto err;
553 }
554 }
555
556 return 0;
557
558 err:
559 scamper_task_sig_deinstall(task);
560 return -1;
561 }
562
563 /*
564 * scamper_task_sig_block
565 *
566 * go through the signatures and see if any conflict with other tasks.
567 * if there is a conflict, return the task, otherwise return NULL.
568 * scamper_task_sig_install assumes that this function has been called.
569 */
scamper_task_sig_block(scamper_task_t * task)570 scamper_task_t *scamper_task_sig_block(scamper_task_t *task)
571 {
572 scamper_task_sig_t *sig;
573 scamper_task_t *tf;
574 slist_node_t *n;
575 s2t_t *s2t;
576
577 for(n=slist_head_node(task->siglist); n != NULL; n = slist_node_next(n))
578 {
579 s2t = slist_node_item(n); sig = s2t->sig;
580 if((tf = scamper_task_find(sig)) != NULL && tf != task)
581 return tf;
582 }
583
584 return NULL;
585 }
586
scamper_task_onhold(scamper_task_t * task,void * param,void (* unhold)(void * param))587 void *scamper_task_onhold(scamper_task_t *task, void *param,
588 void (*unhold)(void *param))
589 {
590 task_onhold_t *toh = NULL;
591 dlist_node_t *cookie;
592
593 if(task->onhold == NULL && (task->onhold = dlist_alloc()) == NULL)
594 goto err;
595 if((toh = malloc_zero(sizeof(task_onhold_t))) == NULL)
596 goto err;
597 if((cookie = dlist_tail_push(task->onhold, toh)) == NULL)
598 goto err;
599
600 toh->param = param;
601 toh->unhold = unhold;
602
603 return cookie;
604
605 err:
606 if(toh != NULL) free(toh);
607 return NULL;
608 }
609
scamper_task_dehold(scamper_task_t * task,void * cookie)610 int scamper_task_dehold(scamper_task_t *task, void *cookie)
611 {
612 task_onhold_t *toh;
613 assert(task->onhold != NULL);
614 if((toh = dlist_node_pop(task->onhold, cookie)) == NULL)
615 return -1;
616 free(toh);
617 return 0;
618 }
619
620 /*
621 * scamper_task_alloc
622 *
623 * allocate and initialise a task object.
624 */
scamper_task_alloc(void * data,scamper_task_funcs_t * funcs)625 scamper_task_t *scamper_task_alloc(void *data, scamper_task_funcs_t *funcs)
626 {
627 scamper_task_t *task;
628
629 assert(data != NULL);
630 assert(funcs != NULL);
631
632 if((task = malloc_zero(sizeof(scamper_task_t))) == NULL)
633 {
634 printerror(__func__, "could not malloc task");
635 goto err;
636 }
637
638 if((task->queue = scamper_queue_alloc(task)) == NULL)
639 goto err;
640
641 if((task->siglist = slist_alloc()) == NULL)
642 goto err;
643
644 task->funcs = funcs;
645 task->data = data;
646
647 return task;
648
649 err:
650 scamper_task_free(task);
651 return NULL;
652 }
653
654 /*
655 * scamper_task_free
656 *
657 * free a task structure.
658 * this involves freeing the task using the free pointer provided,
659 * freeing the queue data structure, unholding any tasks blocked, and
660 * finally freeing the task structure itself.
661 */
scamper_task_free(scamper_task_t * task)662 void scamper_task_free(scamper_task_t *task)
663 {
664 scamper_task_anc_t *anc;
665 task_onhold_t *toh;
666 int i;
667
668 if(task->funcs != NULL)
669 task->funcs->task_free(task);
670
671 if(task->queue != NULL)
672 {
673 scamper_queue_free(task->queue);
674 task->queue = NULL;
675 }
676
677 if(task->onhold != NULL)
678 {
679 while((toh = dlist_head_pop(task->onhold)) != NULL)
680 {
681 toh->unhold(toh->param);
682 free(toh);
683 }
684 dlist_free(task->onhold);
685 }
686
687 if(task->cyclemon != NULL)
688 {
689 scamper_cyclemon_unuse(task->cyclemon);
690 task->cyclemon = NULL;
691 }
692
693 if(task->sourcetask != NULL)
694 {
695 scamper_sourcetask_free(task->sourcetask);
696 task->sourcetask = NULL;
697 }
698
699 if(task->siglist != NULL)
700 {
701 scamper_task_sig_deinstall(task);
702 slist_free(task->siglist);
703 }
704
705 if(task->ancillary != NULL)
706 {
707 while((anc = dlist_head_pop(task->ancillary)) != NULL)
708 {
709 anc->node = NULL;
710 anc->freedata(anc->data);
711 free(anc);
712 }
713 dlist_free(task->ancillary);
714 }
715
716 if(task->fds != NULL)
717 {
718 for(i=0; i<task->fdc; i++)
719 scamper_fd_free(task->fds[i]);
720 free(task->fds);
721 }
722
723 free(task);
724 return;
725 }
726
scamper_task_getdata(const scamper_task_t * task)727 void *scamper_task_getdata(const scamper_task_t *task)
728 {
729 return task->data;
730 }
731
scamper_task_getstate(const scamper_task_t * task)732 void *scamper_task_getstate(const scamper_task_t *task)
733 {
734 return task->state;
735 }
736
scamper_task_setdatanull(scamper_task_t * task)737 void scamper_task_setdatanull(scamper_task_t *task)
738 {
739 task->data = NULL;
740 return;
741 }
742
scamper_task_setstate(scamper_task_t * task,void * state)743 void scamper_task_setstate(scamper_task_t *task, void *state)
744 {
745 task->state = state;
746 return;
747 }
748
scamper_task_getsource(scamper_task_t * task)749 scamper_source_t *scamper_task_getsource(scamper_task_t *task)
750 {
751 if(task->sourcetask == NULL) return NULL;
752 return scamper_sourcetask_getsource(task->sourcetask);
753 }
754
scamper_task_setsourcetask(scamper_task_t * task,scamper_sourcetask_t * st)755 void scamper_task_setsourcetask(scamper_task_t *task, scamper_sourcetask_t *st)
756 {
757 assert(task->sourcetask == NULL);
758 task->sourcetask = st;
759 return;
760 }
761
scamper_task_setcyclemon(scamper_task_t * task,scamper_cyclemon_t * cm)762 void scamper_task_setcyclemon(scamper_task_t *task, scamper_cyclemon_t *cm)
763 {
764 task->cyclemon = scamper_cyclemon_use(cm);
765 return;
766 }
767
scamper_task_write(scamper_task_t * task,scamper_file_t * file)768 void scamper_task_write(scamper_task_t *task, scamper_file_t *file)
769 {
770 task->funcs->write(file, task);
771 return;
772 }
773
scamper_task_probe(scamper_task_t * task)774 void scamper_task_probe(scamper_task_t *task)
775 {
776 task->funcs->probe(task);
777 return;
778 }
779
scamper_task_halt(scamper_task_t * task)780 void scamper_task_halt(scamper_task_t *task)
781 {
782 task->funcs->halt(task);
783 return;
784 }
785
scamper_task_handleicmp(scamper_task_t * task,scamper_icmp_resp_t * resp)786 void scamper_task_handleicmp(scamper_task_t *task, scamper_icmp_resp_t *resp)
787 {
788 if(task->funcs->handle_icmp != NULL)
789 task->funcs->handle_icmp(task, resp);
790 return;
791 }
792
scamper_task_handledl(scamper_dl_rec_t * dl)793 void scamper_task_handledl(scamper_dl_rec_t *dl)
794 {
795 tx_ip_check(dl);
796 tx_nd_check(dl);
797 sniff_check(dl);
798 return;
799 }
800
scamper_task_handletimeout(scamper_task_t * task)801 void scamper_task_handletimeout(scamper_task_t *task)
802 {
803 if(task->funcs->handle_timeout != NULL)
804 task->funcs->handle_timeout(task);
805 return;
806 }
807
scamper_task_queue_probe(scamper_task_t * task)808 int scamper_task_queue_probe(scamper_task_t *task)
809 {
810 return scamper_queue_probe(task->queue);
811 }
812
scamper_task_queue_probe_head(scamper_task_t * task)813 int scamper_task_queue_probe_head(scamper_task_t *task)
814 {
815 return scamper_queue_probe_head(task->queue);
816 }
817
scamper_task_queue_wait(scamper_task_t * task,int ms)818 int scamper_task_queue_wait(scamper_task_t *task, int ms)
819 {
820 return scamper_queue_wait(task->queue, ms);
821 }
822
scamper_task_queue_wait_tv(scamper_task_t * task,struct timeval * tv)823 int scamper_task_queue_wait_tv(scamper_task_t *task, struct timeval *tv)
824 {
825 return scamper_queue_wait_tv(task->queue, tv);
826 }
827
scamper_task_queue_done(scamper_task_t * task,int ms)828 int scamper_task_queue_done(scamper_task_t *task, int ms)
829 {
830 return scamper_queue_done(task->queue, ms);
831 }
832
scamper_task_queue_isprobe(scamper_task_t * task)833 int scamper_task_queue_isprobe(scamper_task_t *task)
834 {
835 return scamper_queue_isprobe(task->queue);
836 }
837
scamper_task_queue_isdone(scamper_task_t * task)838 int scamper_task_queue_isdone(scamper_task_t *task)
839 {
840 return scamper_queue_isdone(task->queue);
841 }
842
task_fd_cmp(const scamper_fd_t * a,const scamper_fd_t * b)843 static int task_fd_cmp(const scamper_fd_t *a, const scamper_fd_t *b)
844 {
845 if(a < b) return -1;
846 if(a > b) return 1;
847 return 0;
848 }
849
850 /*
851 * task_fd
852 *
853 * make sure the task has a hold on this fd.
854 */
task_fd(scamper_task_t * t,scamper_fd_t * fd)855 static scamper_fd_t *task_fd(scamper_task_t *t, scamper_fd_t *fd)
856 {
857 if(fd == NULL)
858 return NULL;
859
860 if(array_find((void **)t->fds, t->fdc, fd, (array_cmp_t)task_fd_cmp) == NULL)
861 {
862 if(array_insert((void ***)&t->fds, &t->fdc, fd,
863 (array_cmp_t)task_fd_cmp) != 0)
864 {
865 scamper_fd_free(fd);
866 return NULL;
867 }
868 }
869 else
870 {
871 /* already have a hold of the fd */
872 scamper_fd_free(fd);
873 }
874 return fd;
875 }
876
scamper_task_fd_icmp4(scamper_task_t * task,void * addr)877 scamper_fd_t *scamper_task_fd_icmp4(scamper_task_t *task, void *addr)
878 {
879 scamper_fd_t *fd = scamper_fd_icmp4(addr);
880 return task_fd(task, fd);
881 }
882
scamper_task_fd_icmp6(scamper_task_t * task,void * addr)883 scamper_fd_t *scamper_task_fd_icmp6(scamper_task_t *task, void *addr)
884 {
885 scamper_fd_t *fd = scamper_fd_icmp6(addr);
886 return task_fd(task, fd);
887 }
888
scamper_task_fd_udp4(scamper_task_t * task,void * a,uint16_t sp)889 scamper_fd_t *scamper_task_fd_udp4(scamper_task_t *task, void *a, uint16_t sp)
890 {
891 scamper_fd_t *fd = scamper_fd_udp4(a, sp);
892 return task_fd(task, fd);
893 }
894
scamper_task_fd_udp6(scamper_task_t * task,void * a,uint16_t sp)895 scamper_fd_t *scamper_task_fd_udp6(scamper_task_t *task, void *a, uint16_t sp)
896 {
897 scamper_fd_t *fd = scamper_fd_udp6(a, sp);
898 return task_fd(task, fd);
899 }
900
scamper_task_fd_tcp4(scamper_task_t * task,void * a,uint16_t sp)901 scamper_fd_t *scamper_task_fd_tcp4(scamper_task_t *task, void *a, uint16_t sp)
902 {
903 scamper_fd_t *fd = scamper_fd_tcp4(a, sp);
904 return task_fd(task, fd);
905 }
906
scamper_task_fd_tcp6(scamper_task_t * task,void * a,uint16_t sp)907 scamper_fd_t *scamper_task_fd_tcp6(scamper_task_t *task, void *a, uint16_t sp)
908 {
909 scamper_fd_t *fd = scamper_fd_tcp6(a, sp);
910 return task_fd(task, fd);
911 }
912
scamper_task_fd_dl(scamper_task_t * task,int ifindex)913 scamper_fd_t *scamper_task_fd_dl(scamper_task_t *task, int ifindex)
914 {
915 scamper_fd_t *fd = scamper_fd_dl(ifindex);
916 return task_fd(task, fd);
917 }
918
scamper_task_fd_ip4(scamper_task_t * task)919 scamper_fd_t *scamper_task_fd_ip4(scamper_task_t *task)
920 {
921 scamper_fd_t *fd = scamper_fd_ip4();
922 return task_fd(task, fd);
923 }
924
925 #ifndef _WIN32
scamper_task_fd_rtsock(scamper_task_t * task)926 scamper_fd_t *scamper_task_fd_rtsock(scamper_task_t *task)
927 {
928 scamper_fd_t *fd = scamper_fd_rtsock();
929 return task_fd(task, fd);
930 }
931 #endif
932
scamper_task_init(void)933 int scamper_task_init(void)
934 {
935 if((tx_ip4 = patricia_alloc((patricia_bit_t)tx_ip_bit,
936 (patricia_cmp_t)tx_ip_cmp,
937 (patricia_fbd_t)tx_ip_fbd)) == NULL)
938 return -1;
939 if((tx_ip6 = patricia_alloc((patricia_bit_t)tx_ip_bit,
940 (patricia_cmp_t)tx_ip_cmp,
941 (patricia_fbd_t)tx_ip_fbd)) == NULL)
942 return -1;
943 if((tx_nd4 = patricia_alloc((patricia_bit_t)tx_nd_bit,
944 (patricia_cmp_t)tx_nd_cmp,
945 (patricia_fbd_t)tx_nd_fbd)) == NULL)
946 return -1;
947 if((tx_nd6 = patricia_alloc((patricia_bit_t)tx_nd_bit,
948 (patricia_cmp_t)tx_nd_cmp,
949 (patricia_fbd_t)tx_nd_fbd)) == NULL)
950 return -1;
951 if((host = splaytree_alloc((splaytree_cmp_t)host_cmp)) == NULL)
952 return -1;
953 if((sniff = dlist_alloc()) == NULL)
954 return -1;
955 return 0;
956 }
957
scamper_task_cleanup(void)958 void scamper_task_cleanup(void)
959 {
960 if(tx_ip4 != NULL) { patricia_free(tx_ip4); tx_ip4 = NULL; }
961 if(tx_ip6 != NULL) { patricia_free(tx_ip6); tx_ip6 = NULL; }
962 if(tx_nd4 != NULL) { patricia_free(tx_nd4); tx_nd4 = NULL; }
963 if(tx_nd6 != NULL) { patricia_free(tx_nd6); tx_nd6 = NULL; }
964 if(host != NULL) { splaytree_free(host, NULL); host = NULL; }
965 if(sniff != NULL) { dlist_free(sniff); sniff = NULL; }
966 return;
967 }
968