Exemplo n.º 1
0
static void log_group( const struct asym *grp, const struct dsym *segs )
/**********************************************************************/
{
    unsigned i;
    const char *pdots;
    struct seg_item *curr;

    i = grp->name_size;
    pdots = (( i >= DOTSMAX ) ? "" : dots + i + 1);
    LstPrintf( "%s %s        %s", grp->name, pdots, strings[LS_GROUP] );
    LstNL();

    /* the FLAT groups is always empty */
    if ( grp == (struct asym *)ModuleInfo.flat_grp ) {
        for( ; segs; segs = segs->next ) {
            log_segment( (struct asym *)segs, grp );
        }
    } else
        for( curr = ((struct dsym *)grp)->e.grpinfo->seglist; curr; curr = curr->next ) {
            log_segment( (struct asym *)curr->seg, grp );
        }
}
Exemplo n.º 2
0
/**
 * Sends a cTCP segment to a destination associated with the provided
 * connection object.
 *
 * conn: Connection object.
 * segment: Pointer to cTCP segment to send.
 * len: Length of the segment (including the cTCP header and data).
 *
 * returns: The number of bytes actually sent, 0 if nothing was sent, -1 if
 *          there in an error.
 */
int conn_send(conn_t *conn, ctcp_segment_t *segment, size_t len) { ASSERT_CONN;
  /* Check parameters. */
  if (conn == NULL || segment == NULL) {
    fprintf(stderr, "[ERROR] NULL parameters in conn_send\n");
    return -1;
  }

  /* Make a copy of the segment first. */
  ctcp_segment_t *segment_copy = calloc(len, 1);
  memcpy(segment_copy, segment, len);

  /* Fork process off in order to do unreliability. Keep track of whether we
     are forked or not. */
  int fork_level = 0;
  bool am_i_forked = 0;

  /* Segment drop. Don't send the segment. */
  if ((test_debug_on && !tester_did_unreliable && opt_drop) ||
      (!test_debug_on && rand_percent(fork_level) < opt_drop)) {
    tester_did_unreliable = true;

    if (DEBUG) {
      fprintf(stderr, "[DEBUG] Dropping segment\n");
      print_hdr_ctcp(segment_copy);
    }
    free(segment_copy);
    return len;
  }

  /* Segment duplication. Fork another process to send the other segment. */
  if ((test_debug_on && !tester_did_unreliable && opt_duplicate) ||
      (!test_debug_on && rand_percent(fork_level) < opt_duplicate)) {
    tester_did_unreliable = true;

    if (DEBUG) {
      fprintf(stderr, "[DEBUG] Duplicating segment\n");
      print_hdr_ctcp(segment_copy);
    }
    if (fork() == 0) {
      am_i_forked = 1;
      fork_level++;
    }
  }

  /* Segment delay. Fork another process to delay the segment, and kill the
     current one. */
  if ((test_debug_on && !tester_did_unreliable && opt_delay) ||
       (!test_debug_on && rand_percent(fork_level) < opt_delay)) {
    tester_did_unreliable = true;

    if (DEBUG) {
      fprintf(stderr, "[DEBUG] Delaying segment\n");
      print_hdr_ctcp(segment_copy);
    }
    /* Forked process. Sleep for a bit. */
    if (fork() == 0) {
      am_i_forked = 1;
      fork_level++;
      sleep(rand() % 5);
    }
    /* Original process. */
    else {
      free(segment_copy);
      return len;
    }
  }

  /* Segment corruption. Flip bits in the segment after the TCP flags (to avoid
     corrupting the flags, which may cause problems). */
  bool do_corrupt = rand_percent(fork_level) < opt_corrupt;
  uint16_t data_length = len - sizeof(ctcp_segment_t) + sizeof(uint32_t);
  uint16_t rand_bit = rand() % (data_length * 8 - 1) +
                      (sizeof(ctcp_segment_t) - sizeof(uint32_t)) * 8;

  if ((test_debug_on && !tester_did_unreliable && opt_corrupt) ||
      (!test_debug_on && do_corrupt)) {
    tester_did_unreliable = true;

    if (DEBUG) {
      fprintf(stderr, "[DEBUG] Corrupting segment\n");
      print_hdr_ctcp(segment_copy);
    }
    flipbit(segment_copy, rand_bit);
  }

  uint16_t data_len = len - sizeof(ctcp_segment_t);
  uint16_t total_len = FULL_HDR_SIZE + data_len;

  if (log_file != -1 || test_debug_on) {
    log_segment(log_file, config->ip_addr, config->port, conn, segment_copy,
                len, true, unix_socket);
  }

  /* Convert from a cTCP segment to a real one and finally send the segment. */
  char *pkt = convert_to_datagram(conn, segment_copy, len);
  int n = send_pkt(conn, config->socket, pkt, total_len, 0);
  if (DEBUG) {
    fprintf(stderr, "[DEBUG] Sent segment\n");
    print_hdr_ctcp(segment_copy);
  }
  free(pkt);
  free(segment_copy);

  /* Kill forked process. */
  if (am_i_forked)
    exit(0);

  /* Return number of bytes sent. Need to subtract some because the return value
     is actually the size of the TCP segment instead of the cTCP segment. */
  if (n >= (long int)TCP_HDR_SIZE)
    return n - (TCP_HDR_SIZE + IP_HDR_SIZE - sizeof(ctcp_segment_t));
  return n;
}
Exemplo n.º 3
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();
  }
}