Example #1
0
/**
 * Puts the given message on the pending message list.  If it doesn't match
 * any pending message and there are no open slots, first send what's pending.
 * If the pending list is full after adding the given message, then send.
 */
void check_pending(int listidx, int hostidx, const unsigned char *message)
{
    struct infoack_h *infoack;
    struct status_h *status;
    struct complete_h *complete;
    const uint8_t *func;
    struct pr_pending_info_t *pending;
    int match, pendidx;

    func = message;
    infoack = (struct infoack_h *)message;
    status = (struct status_h *)message;
    complete = (struct complete_h *)message;

    for (pendidx = 0; pendidx < MAX_PEND; pendidx++) {
        pending = &group_list[listidx].pending[pendidx];
        if (group_list[listidx].pending[pendidx].msg == 0) {
            match = 1;
            break;
        }

        match = (*func == pending->msg);
        switch (*func) {
        case REGISTER:
            // REGISTER always matches itself
            break;
        case INFO_ACK:
            // Only in response to FILEINFO.
            // Responses to KEYINFO are not forwarded.
            match = match && (ntohs(infoack->file_id) == pending->file_id);
            break;
        case STATUS:
            match = match && ((ntohs(status->file_id) == pending->file_id) &&
                              (status->pass == pending->pass) &&
                              (ntohs(status->section) == pending->section));
            break;
        case COMPLETE:
            match = match && ((ntohs(complete->file_id) == pending->file_id) &&
                              (complete->status == pending->comp_status));
            break;
        default:
            log(group_list[listidx].group_id, 0, "Tried to check pending "
                    "on invalid type %s", func_name(*func));
            return;
        }
        if (match) {
            break;
        }
    }

    if (!match) {
        send_all_pending(listidx);
        pendidx = 0;
        pending = &group_list[listidx].pending[pendidx];
    }

    pending->msg = *func;
    if (group_list[listidx].destinfo[hostidx].pending != pendidx) {
        group_list[listidx].destinfo[hostidx].pending = pendidx;
        pending->count++;
    }

    switch (*func) {
    case INFO_ACK:
        if (pending->count == 1) {
            pending->partial = 1;
        }
        pending->file_id = ntohs(infoack->file_id);
        pending->partial = pending->partial &&
                            ((infoack->flags & FLAG_PARTIAL) != 0);
        break;
    case STATUS:
        pending->file_id = ntohs(status->file_id);
        pending->pass = status->pass;
        pending->section = ntohs(status->section);
        pending->seq = group_list[listidx].last_seq;
        if (!pending->naklist) {
            pending->naklist = calloc(group_list[listidx].blocksize, 1);
            if (pending->naklist == NULL) {
                syserror(0, 0, "calloc failed!");
                exit(1);
            }
        }
        if (ntohl(status->nak_count) != 0) {
            add_naks_to_pending(listidx, pendidx, message);
        }
        break;
    case COMPLETE:
        pending->file_id = ntohs(complete->file_id);
        pending->comp_status = complete->status;
        break;
    }

    if (pending->count == max_msg_dest(listidx, *func)) {
        send_pending(listidx, pendidx);
    } else {
        int total_pending, i;

        for (total_pending = 0, i = 0; i < MAX_PEND; i++) {
            total_pending += group_list[listidx].pending[i].count;
        }
        if (total_pending == 1) {
            set_timeout(listidx, 1);
        }
    }
}
Example #2
0
/**
 * Puts the given message on the pending message list.  If it doesn't match
 * any pending message and there are no open slots, first send what's pending.
 * If the pending list is full after adding the given message, then send.
 */
void check_pending(struct pr_group_list_t *group, int hostidx,
                   const unsigned char *message)
{
    const struct fileinfoack_h *fileinfoack;
    const struct status_h *status;
    const struct complete_h *complete;
    const uint8_t *func;
    struct pr_pending_info_t *pending;
    int match, pendidx, hlen;

    func = message;
    fileinfoack = (const struct fileinfoack_h *)message;
    status = (const struct status_h *)message;
    complete = (const struct complete_h *)message;

    glog3(group, "check_timeout: looking for pending %s", func_name(*func));
    for (pendidx = 0; pendidx < MAX_PEND; pendidx++) {
        pending = &group->pending[pendidx];
        if (group->pending[pendidx].msg == 0) {
            glog3(group, "check_timeout: found empty slot %d", pendidx);
            match = 1;
            break;
        }

        match = (*func == pending->msg);
        switch (*func) {
        case REGISTER:
            // REGISTER always matches itself
            break;
        case FILEINFO_ACK:
            match = match && (ntohs(fileinfoack->file_id) == pending->file_id);
            break;
        case STATUS:
            match = match && ((ntohs(status->file_id) == pending->file_id) &&
                              (ntohs(status->section) == pending->section));
            break;
        case COMPLETE:
            match = match && ((ntohs(complete->file_id) == pending->file_id) &&
                              (complete->status == pending->comp_status));
            break;
        default:
            glog1(group, "Tried to check pending on invalid type %s",
                         func_name(*func));
            return;
        }
        if (match) {
            break;
        }
    }

    if (!match) {
        send_all_pending(group);
        pendidx = 0;
        pending = &group->pending[pendidx];
    }

    glog3(group, "check_timeout: found match at slot %d", pendidx);
    pending->msg = *func;
    if (group->destinfo[hostidx].pending != pendidx) {
        group->destinfo[hostidx].pending = pendidx;
        pending->count++;
    }

    switch (*func) {
    case REGISTER:
        hlen = sizeof(struct register_h);
        if (pending->count == 1) {
            gettimeofday(&pending->rx_tstamp, NULL);
            pending->tstamp = group->destinfo[hostidx].regtime;
            glog3(group, "send time = %d.%06d",
                         pending->tstamp.tv_sec, pending->tstamp.tv_usec);
            glog3(group, "rx time = %d.%06d",
                         pending->rx_tstamp.tv_sec, pending->rx_tstamp.tv_usec);
        }
        break;
    case FILEINFO_ACK:
        hlen = sizeof(struct fileinfoack_h);
        if (pending->count == 1) {
            pending->partial = 1;
            gettimeofday(&pending->rx_tstamp, NULL);
            pending->tstamp.tv_sec = ntohl(fileinfoack->tstamp_sec);
            pending->tstamp.tv_usec = ntohl(fileinfoack->tstamp_usec);
            glog3(group, "send time = %d.%06d",
                         pending->tstamp.tv_sec, pending->tstamp.tv_usec);
            glog3(group, "rx time = %d.%06d",
                         pending->rx_tstamp.tv_sec, pending->rx_tstamp.tv_usec);
        }
        pending->file_id = ntohs(fileinfoack->file_id);
        pending->partial = pending->partial &&
                            ((fileinfoack->flags & FLAG_PARTIAL) != 0);
        break;
    case STATUS:
        hlen = sizeof(struct status_h);
        pending->file_id = ntohs(status->file_id);
        pending->section = ntohs(status->section);
        if (!pending->naklist) {
            pending->naklist = safe_calloc(group->blocksize, 1);
        }
        add_naks_to_pending(group, pendidx, message);
        break;
    case COMPLETE:
        hlen = sizeof(struct complete_h);
        pending->file_id = ntohs(complete->file_id);
        pending->comp_status = complete->status;
        break;
    }

    if ((*func != STATUS) &&
            (pending->count == max_msg_dest(group, *func, hlen))) {
        send_pending(group, pendidx);
    } else {
        int total_pending, i;

        glog3(group, "check_timeout: getting pending count for %s",
                     func_name(*func));
        for (total_pending = 0, i = 0; i < MAX_PEND; i++) {
            glog3(group, "check_timeout: adding %d pending for %d",
                         group->pending[i].count, i);
            total_pending += group->pending[i].count;
        }
        if (total_pending == 1) {
            set_timeout(group, 1, 0);
        }
    }
}