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;
}
Exemple #6
0
size_t probe_get_num_layers(const probe_t * probe) {
    return dynarray_get_size(probe->layers);
}