void rel_timer () { /* Iterate over all the reliable connections */ rel_t *r; for (r = rel_list; r != NULL; r = r->next) { /* Poke the output, just in case it died on us */ rel_output(r); /* Send window is [head of buffer queue, head of buffer queue + window size], * so we iterate over the send window, and send anything that's timed out. */ int i = 0; for (i = bq_get_head_seq(r->send_bq); rel_seqno_in_send_window(r,i); i++) { /* This is just a safety check, in case we haven't read in this part * of the send window yet */ if (!bq_element_buffered(r->send_bq, i)) continue; /* Borrowed need_timer_in from rlib: just checks whether it's * been r->timeout ms since elem->time_sent */ send_bq_element_t *elem = bq_get_element(r->send_bq, i); if (need_timer_in (&(elem->time_sent), r->timeout) == 0) { rel_send_buffered_pkt(r,elem); } } } }
/** * Main loop. Handles the following: * - Input from STDIN. * - Messages from programs. * - Packets from the socket. * - Timeouts. */ void do_loop() { char buf[MAX_PACKET_SIZE]; conn_t *conn = NULL; while (true) { memset(buf, 0, MAX_PACKET_SIZE); poll(events, NUM_POLL + num_connected, need_timer_in(&last_timeout, ctcp_cfg->timer)); /* Input from stdin. Server will only send to most-recently connected client. */ if (!run_program && events[STDIN_FILENO].revents & POLLIN) { conn = get_connections(); if (conn != NULL) ctcp_read(conn->state); } /* See if we can output more. */ if (events[STDOUT_FILENO].revents & (POLLOUT | POLLHUP | POLLERR)) { for (conn = get_connections(); conn; conn = conn->next) { conn_drain(conn); } } /* Poll for output received from running programs. Send to client client associated with this program instance. */ if (run_program) { conn = get_connections(); while (conn != NULL) { if (conn->poll_fd->revents & POLLIN) { ctcp_read(conn->state); } conn = conn->next; } } /* Receive packet on socket from other hosts. Ignore packets if they are not large enough or not for us. */ if (events[2].revents & POLLIN) { conn = NULL; int len = recv_filter(config->socket, buf, MAX_PACKET_SIZE, 0, &conn); if (len >= FULL_HDR_SIZE) { tcphdr_t *tcp_hdr = (tcphdr_t *) (buf + IP_HDR_SIZE); /* Packet from an established connection. Pass to student code. */ if (conn != NULL) { ctcp_segment_t *segment = convert_to_ctcp(conn, buf, len); len = len - FULL_HDR_SIZE + sizeof(ctcp_segment_t); /* Don't log or forward to student code if it's an ACK from a new connection. */ if (tcp_hdr->th_sport == new_connection && (segment->flags & TH_ACK) && ntohl(segment->seqno) == 1 && ntohl(segment->ackno) == 1) { new_connection = 0; free(segment); } else { if (log_file != -1 || test_debug_on) { log_segment(log_file, config->ip_addr, config->port, conn, segment, len, false, unix_socket); } ctcp_receive(conn->state, segment, len); } } /* New connection. */ else if (tcp_hdr->th_flags & TH_SYN) { conn_t *conn = tcp_new_connection(buf); /* Start a new program associated with this client. */ if (run_program && conn) execute_program(conn); new_connection = tcp_hdr->th_sport; } } } /* Check if timer is up. */ if (need_timer_in(&last_timeout, ctcp_cfg->timer) == 0) { ctcp_timer(); get_time(&last_timeout); } /* Delete connections if needed. */ delete_all_connections(); } }