/** * 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); } } }
/** * 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); } } }