/* when an ack packet is received, invoke the function to process the pakcet */ void process_ack_packet(char* packet, bt_config_t* config, struct sockaddr_in* from) { /* 1. parse ack packet */ int ack_num = parse_ack(packet); // fix 0-1 problem ack_num--; DPRINTF(DEBUG_SOCKETS, "recv ack: %d\n", ack_num); /* 2. find the peer that send the ack packet */ bt_peer_t* peer = find_peer(config->peers, from); if (peer->up_con == NULL){ /* a "out-of-date" ack packet, ignore it*/ return; } /* successfully receive a packet, reset successive_fail */ peer->up_con->successive_fail = 0; /* 3. ack to window */ int is_resend = window_ack_packet(peer->up_con, ack_num); if (is_resend) DPRINTF(DEBUG_SOCKETS, "resend data packet due to duplicate ack\n"); /* 4. send (or resend) data packet */ send_data_packet(is_resend, config, peer); /* 5. check if have received all acks (finish uploading) */ if (window_finish_ack(peer->up_con)){ /* CLR select set*/ FD_CLR(peer->up_con->timer_fd, &config->readset); /* destroy connection with peer */ destroy_connection(peer->up_con); peer->up_con = NULL; /* dec current upload number */ config->cur_upload_num--; } }
static void esmtpparent() { unsigned i; fd_set fdc, fds; time_t current_time; libmail_changeuidgid(MAILUID, MAILGID); module_init(&terminated_child); if ((info=(struct esmtpchildinfo *)malloc(sizeof(*info)* module_nchildren)) == 0) clog_msg_errno(); for (i=0; i<module_nchildren; i++) { info[i].pid= -1; info[i].cmdpipe= -1; info[i].host=0; info[i].pendel=0; } if (pipe(completionpipe) < 0) clog_msg_errno(); if ((childresultpipe=fdopen(completionpipe[0], "r")) == 0) clog_msg_errno(); FD_ZERO(&fdc); FD_SET(0, &fdc); FD_SET(completionpipe[0], &fdc); mybuf_init(&courierdbuf, 0); mybuf_init(&childbuf, completionpipe[0]); module_blockset(); time(¤t_time); for (;;) { time_t wait_time; struct timeval tv; wait_time=0; for (i=0; i<module_nchildren; i++) { if (!ESMTP_IDLE(&info[i])) continue; if (info[i].termtime <= current_time) { close(info[i].cmdpipe); info[i].cmdpipe= -1; continue; } if (wait_time == 0 || info[i].termtime < wait_time) wait_time=info[i].termtime; } if (wait_time) { tv.tv_sec= wait_time - current_time; tv.tv_usec=0; } fds=fdc; module_blockclr(); while (select(completionpipe[0]+1, &fds, (fd_set *)0, (fd_set *)0, (wait_time ? &tv:(struct timeval *)0)) < 0) { if (errno != EINTR) clog_msg_errno(); } module_blockset(); time(¤t_time); if (FD_ISSET(completionpipe[0], &fds)) { char *line; do { pid_t p; line=module_getline( &call_mybuf_get, &childbuf); if (parse_ack(line, &i, &p) || i >= module_nchildren || (p == info[i].pid && !ESMTP_BUSY(&info[i]))) { clog_msg_start_err(); clog_msg_str("INVALID message from child process."); clog_msg_send(); _exit(0); } if (p != info[i].pid) continue; info[i].isbusy=0; info[i].termtime=current_time + esmtpkeepalive; if (info[i].pendel) { free(info[i].pendel); info[i].pendel=0; } module_completed(i, module_delids[i]); } while (mybuf_more(&childbuf)); } if (!FD_ISSET(0, &fds)) continue; do { char **cols; const char *hostp; size_t hostplen; time_t misctime; unsigned j; char *line; line=module_getline( &call_mybuf_get, &courierdbuf); if (!line) { module_restore(); /* ** If all processes are idle, wait for them ** to finish normally. Otherwise, kill ** the processes. */ for (j=0; j<module_nchildren; j++) if (ESMTP_BUSY(&info[j])) break; if (j < module_nchildren) { for (j=0; j<module_nchildren; j++) if (info[j].pid > 0) kill(info[j].pid, SIGTERM); } else { int waitstat; for (j=0; j<module_nchildren; j++) { if (info[j].cmdpipe > 0) { close(info[j].cmdpipe); info[j].cmdpipe= -1; } } while (wait(&waitstat) != -1 || errno == EINTR) ; } _exit(0); } cols=module_parsecols(line); if (!cols) _exit(0); hostp=MODULEDEL_HOST(cols); for (hostplen=0; hostp[hostplen] && hostp[hostplen] != '\t'; hostplen++) ; for (i=0; i<module_nchildren; i++) { if (!ESMTP_IDLE(&info[i])) continue; if (memcmp(info[i].host, hostp, hostplen) == 0 && info[i].host[hostplen] == 0) break; } if (i < module_nchildren) /* Reuse a process */ { send_child(i, line, cols); continue; } for (i=0; i<module_nchildren; i++) if (ESMTP_NOCHILD(&info[i])) break; if (i < module_nchildren) /* We can fork */ { start_child(i, line, cols); send_child(i, line, cols); continue; } /* ** Find a process that's been idled the longest, ** and reuse that one. */ misctime=0; j=0; for (i=0; i<module_nchildren; i++) { if (ESMTP_IDLE(&info[i]) && (misctime == 0 || misctime > info[i].termtime)) { j=i; misctime=info[i].termtime; } } if (misctime) { if (info[j].pendel) { clog_msg_start_err(); clog_msg_str("INTERNAL ERROR: unexpected scheduled delivery."); clog_msg_send(); _exit(1); } info[j].pendel=strcpy( courier_malloc(strlen(line)+1), line); close(info[j].cmdpipe); info[j].cmdpipe= -1; continue; } /* The ONLY remaining possibility is something in ** the TERMINATING stage, without another delivery ** already scheduled for that slot. */ for (i=0; i<module_nchildren; i++) { if (ESMTP_TERMINATING(&info[i]) && info[i].pendel == 0) break; } if (i < module_nchildren) { info[i].pendel=strcpy( courier_malloc(strlen(line)+1), line); continue; } clog_msg_start_err(); clog_msg_str("INTERNAL ERROR: unexpected delivery."); clog_msg_send(); _exit(1); } while (mybuf_more(&courierdbuf)); } }