Example #1
0
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);
            }
        }
    }
}
Example #2
0
/**
 * 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();
  }
}