void pt_process_instance(const void * node, VISIT visit, int level) { algorithm_instance_t * instance = *((algorithm_instance_t * const *) node); size_t i, num_events; uint64_t ret; ssize_t count; // Save temporarily this algorithm context instance->loop->cur_instance = instance; // Execute algorithm handler for events of each algorithm num_events = dynarray_get_size(instance->events); for (i = 0; i < num_events; i++) { event_t * event; count = read(instance->loop->eventfd_algorithm, &ret, sizeof(ret)); if (count == -1) return; event = dynarray_get_ith_element(instance->events, i); instance->algorithm->handler(instance->loop, event, &instance->data, instance->probe_skel, instance->options); } // Restore the algorithm context instance->loop->cur_instance = NULL; // Flush events queue algorithm_instance_clear_events(instance); }
static void network_flying_probes_dump(network_t * network) { size_t i, num_flying_probes = dynarray_get_size(network->probes); uint16_t tag_probe; probe_t * probe; printf("\n%u flying probe(s) :\n", (unsigned int)num_flying_probes); for (i = 0; i < num_flying_probes; i++) { probe = dynarray_get_ith_element(network->probes, i); probe_extract_tag(probe, &tag_probe) ? printf(" 0x%x", tag_probe): printf(" (invalid tag)"); printf("\n"); } }
bool network_drop_expired_flying_probe(network_t * network) { // Drop every expired probes size_t i, num_flying_probes = dynarray_get_size(network->probes); bool ret = false; probe_t * probe; // Is there flying probe(s) ? if (num_flying_probes > 0) { // Iterate on each expired probes (at least the oldest one has expired) for (i = 0 ;i < num_flying_probes; i++) { probe = dynarray_get_ith_element(network->probes, i); // Some probe may expires very soon and may expire before the next probe timeout // update. If so, the timer will be disarmed and libparistraceroute may freeze. // To avoid this kind of deadlock, we provoke a probe timeout for each probe // expiring in less that EXTRA_DELAY seconds. if (network_get_probe_timeout(network, probe) - EXTRA_DELAY > 0) break; // This probe has expired, raise a PROBE_TIMEOUT event. pt_throw(NULL, probe->caller, event_create(PROBE_TIMEOUT, probe, NULL, NULL)); //(ELEMENT_FREE) probe_free)); } // Delete the i oldest probes, which have expired. if (i != 0) { dynarray_del_n_elements(network->probes, 0, i, NULL); } ret = network_update_next_timeout(network); } else { fprintf(stderr, "network_drop_expired_flying_probe: a probe has expired, but there are no more flying probes!\n"); } return ret; }
// TODO This could be replaced by watchers: FD -> action bool network_process_sendq(network_t * network) { probe_t * probe; packet_t * packet; size_t num_flying_probes; struct itimerspec new_timeout; // Probe skeleton when entering the network layer. // We have to duplicate the probe since the same address of skeleton // may have been passed to pt_send_probe. // => We duplicate this probe in the // network layer registry (network->probes) and then tagged. // Do not free probe at the end of this function. // Its address will be saved in network->probes and freed later. probe = queue_pop_element(network->sendq, NULL); // Tag the probe if (!network_tag_probe(network, probe)) { fprintf(stderr, "Can't tag probe\n"); goto ERR_TAG_PROBE; } if (network->is_verbose) { printf("Sending probe packet:\n"); probe_dump(probe); } // Make a packet from the probe structure if (!(packet = probe_create_packet(probe))) { fprintf(stderr, "Can't create packet\n"); goto ERR_CREATE_PACKET; } // Send the packet if (!(socketpool_send_packet(network->socketpool, packet))) { fprintf(stderr, "Can't send packet\n"); goto ERR_SEND_PACKET; } // Update the sending time probe_set_sending_time(probe, get_timestamp()); // Register this probe in the list of flying probes if (!(dynarray_push_element(network->probes, probe))) { fprintf(stderr, "Can't register probe\n"); goto ERR_PUSH_PROBE; } // We've just sent a probe and currently, this is the only one in transit. // So currently, there is no running timer, prepare timerfd. num_flying_probes = dynarray_get_size(network->probes); if (num_flying_probes == 1) { itimerspec_set_delay(&new_timeout, network_get_timeout(network)); if (timerfd_settime(network->timerfd, 0, &new_timeout, NULL) == -1) { fprintf(stderr, "Can't set timerfd\n"); goto ERR_TIMERFD; } } return true; ERR_TIMERFD: ERR_PUSH_PROBE: ERR_SEND_PACKET: packet_free(packet); ERR_CREATE_PACKET: ERR_TAG_PROBE: return false; }
static probe_t * network_get_matching_probe(network_t * network, const probe_t * reply) { // Suppose we perform a traceroute measurement thanks to IPv4/UDP packet // We encode in the IPv4 checksum the ID of the probe. // Then, we should sniff an IPv4/ICMP/IPv4/UDP packet. // The ICMP message carries the begining of our probe packet, so we can // retrieve the checksum (= our probe ID) of the second IP layer, which // corresponds to the 3rd checksum field of our probe. uint16_t tag_probe, tag_reply; probe_t * probe; size_t i, num_flying_probes; // XXX // Fetch the tag from the reply. Its the 3rd checksum field. if (!(reply_extract_tag(reply, &tag_reply))) { // This is not an IP / ICMP / IP / * reply :( if (network->is_verbose) fprintf(stderr, "Can't retrieve tag from reply\n"); return NULL; } num_flying_probes = dynarray_get_size(network->probes); for (i = 0; i < num_flying_probes; i++) { probe = dynarray_get_ith_element(network->probes, i); // Reply / probe comparison. In our probe packet, the probe ID // is stored in the checksum of the (first) IP layer. if (probe_extract_tag(probe, &tag_probe)) { if (tag_reply == tag_probe) break; } } /* // XXX BEGIN Harcoded ICMP response (JA 17/07/2014) tag_reply = 0; tag_probe = 0; tag_probe++; tag_reply++; num_flying_probes = dynarray_get_size(network->probes); for (i = 0; i < num_flying_probes; i++) { probe = dynarray_get_ith_element(network->probes, i); // Reply / probe comparison. In our probe packet, the probe ID // is stored in the checksum of the (first) IP layer. if (probe_match((const struct probe_s *)probe, (const struct probe_s *)reply)) break; } // XXX END Hardcoded ICMP response */ // No match found if we reached the end of the array if (i == num_flying_probes) { if (network->is_verbose) { fprintf(stderr, "network_get_matching_probe: This reply has been discarded: tag = 0x%x.\n", tag_reply); network_flying_probes_dump(network); } return NULL; } // We delete the corresponding probe // TODO: ... but it should be kept, for archive purposes, and to match for duplicates... // But we cannot reenable it until we set the probe ID into the // checksum, since probes with same flow_id and different TTL have the // same checksum dynarray_del_ith_element(network->probes, i, NULL); // The matching probe is the oldest one and there are other probes, update // the timer according to the next unexpired probe timeout. if (i == 0) { if (!(network_update_next_timeout(network))) { fprintf(stderr, "Error while updating timeout\n"); } } return probe; }
size_t probe_get_num_layers(const probe_t * probe) { return dynarray_get_size(probe->layers); }