示例#1
0
int main(int argc, char** argv) {
  int c;
  int sockfd, newsockfd;
  int federated = 0, debug = 0, max_ttl = 10;
  time_t tt;
  socklen_t clilen;
  char* srcname = NULL;
  char* listenport = LISTEN_PORT;
  int conn_options = 0;

  char *ErLogFileName = BASEDIR
      "/"ERLOGFILE;
  char *AcLogFileName = BASEDIR
      "/"ACLOGFILE;
  struct sockaddr_storage cli_addr;
  I2Addr listenaddr = NULL;
  Allowed* ptr;

#ifdef AF_INET6
#define GETOPT_LONG_INET6(x) "46"x
#else
#define GETOPT_LONG_INET6(x) x
#endif

  while ((c = getopt_long(argc, argv, GETOPT_LONG_INET6("dhl:e:p:t:Ff:b:sS:v"),
                          long_options, 0)) != -1) {
    switch (c) {
      case '4':
        conn_options |= OPT_IPV4_ONLY;
        break;
      case '6':
        conn_options |= OPT_IPV6_ONLY;
        break;
      case 'd':
        debug++;
        break;
      case 'h':
        www_long_usage("ANL/Internet2 NDT version " VERSION " (fakewww)");
        break;
      case 'v':
        printf("ANL/Internet2 NDT version %s (fakewww)\n", VERSION);
        exit(0);
        break;
      case 'l':
        AcLogFileName = optarg;
        break;
      case 'e':
        ErLogFileName = optarg;
        break;
      case 'p':
        listenport = optarg;
        break;
      case 't':
        max_ttl = atoi(optarg);
        break;
      case 'F':
        federated = 1;
        break;
      case 'f':
        ptr = malloc(sizeof(Allowed));
        ptr->filename = optarg;
        ptr->next = a_root;
        a_root = ptr;
        break;
      case 'b':
        basedir = optarg;
        break;
      case 's':
        usesyslog = 1;
        break;
      case 'S':
        SysLogFacility = optarg;
        break;
      case 301:
        DefaultTree = optarg;
        break;
#ifdef AF_INET6
      case 302:
        DefaultTree6 = optarg;
        break;
#endif
      case '?':
        short_usage(argv[0], "");
        break;
    }
  }

  if (optind < argc) {
    short_usage(argv[0], "Unrecognized non-option elements");
  }

  log_init(argv[0], debug);

  if (SysLogFacility != NULL) {
    int i = 0;
    while (facilitynames[i].c_name) {
      if (strcmp(facilitynames[i].c_name, SysLogFacility) == 0) {
        syslogfacility = facilitynames[i].c_val;
        break;
      }
      ++i;
    }
    if (facilitynames[i].c_name == NULL) {
      log_println(
          0,
          "Warning: Unknown syslog facility [%s] --> using default (%d)",
          SysLogFacility, syslogfacility);
      SysLogFacility = NULL;
    }
  }

  if (DefaultTree == NULL) {
    snprintf(dtfn, sizeof(dtfn), "%s/%s", BASEDIR, DFLT_TREE);
    DefaultTree = dtfn;
  }

#ifdef AF_INET6
  if (DefaultTree6 == NULL) {
    snprintf(dt6fn, sizeof(dtfn), "%s/%s", BASEDIR, DFLT_TREE6);
    DefaultTree6 = dt6fn;
  }
#endif

  /*
   * Bind our local address so that the client can send to us.
   */
  if (srcname && !(listenaddr = I2AddrByNode(get_errhandle(), srcname))) {
    err_sys("server: Invalid source address specified");
  }
  if ((listenaddr = CreateListenSocket(listenaddr, listenport, conn_options,
                                       0)) == NULL) {
    err_sys("server: CreateListenSocket failed");
  }
  sockfd = I2AddrFD(listenaddr);

  tt = time(0);
  log_println(1, "%15.15s fakewww server started (NDT version %s)",
              ctime(&tt) + 4, VERSION);
  log_println(1, "\tport = %d", I2AddrPort(listenaddr));
  log_println(1, "\tfederated mode = %s", (federated == 1) ? "on" : "off");
  log_println(1, "\taccess log = %s\n\terror log = %s", AcLogFileName,
              ErLogFileName);
  log_println(1, "\tbasedir = %s", basedir);
  if (usesyslog) {
    log_println(1, "\tsyslog facility = %s (%d)",
                SysLogFacility ? SysLogFacility : "default", syslogfacility);
  }
  log_println(1, "\tdebug level set to %d", debug);

  logErLog(ErLogFileName, &tt, "notice",
           "fakewww server started (NDT version %s)", VERSION);
  logErLog(ErLogFileName, &tt, "notice", "\tport = %d",
           I2AddrPort(listenaddr));
  logErLog(ErLogFileName, &tt, "notice", "\tfederated mode = %s",
           (federated == 1) ? "on" : "off");
  logErLog(ErLogFileName, &tt, "notice", "\taccess log = %s", AcLogFileName);
  logErLog(ErLogFileName, &tt, "notice", "\terror log = %s", ErLogFileName);
  logErLog(ErLogFileName, &tt, "notice", "\tbasedir = %s", basedir);
  if (usesyslog) {
    logErLog(ErLogFileName, &tt, "notice", "\tsyslog facility = %s (%d)",
             SysLogFacility ? SysLogFacility : "default", syslogfacility);
  }
  logErLog(ErLogFileName, &tt, "notice", "\tdebug level set to %d", debug);

  if (usesyslog == 1)
    syslog(LOG_FACILITY | LOG_INFO, "Fakewww (ver %s) process started",
           VERSION);
  signal(SIGCHLD, reap); /* get rid of zombies */

  /*
   * Wait for a connection from a client process.
   * This is an example of a concurrent server.
   */

  for (;;) {
    clilen = sizeof(cli_addr);
    newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
    if (newsockfd < 0) {
      if (errno == EINTR)
        continue; /*sig child */
      err_sys("Fakewww server: accept error");
    }

    if (fork() == 0) { /* child */
      I2Addr caddr = I2AddrBySAddr(get_errhandle(),
                                   (struct sockaddr *) &cli_addr, clilen, 0, 0);
      alarm(300); /* kill child off after 5 minutes, should never happen */
      close(sockfd);
      dowww(newsockfd, caddr, listenport, AcLogFileName, ErLogFileName,
            federated, max_ttl);
      exit(0);
    }
    close(newsockfd);
  }
}
示例#2
0
int
test_mid_clt(int ctlSocket, char tests, char* host, int conn_options, int buf_size, char* tmpstr2)
{
  char buff[BUFFSIZE+1];
  int msgLen, msgType;
  int midport = 3003;
  I2Addr sec_addr = NULL;
  int ret, one=1, i, inlth;
  int in2Socket;
  double t, spdin;
  uint32_t bytes;
  struct timeval sel_tv;
  fd_set rfd;

  if (tests & TEST_MID) {
    log_println(1, " <-- Middlebox test -->");
    msgLen = sizeof(buff);
    if (recv_msg(ctlSocket, &msgType, buff, &msgLen)) {
      log_println(0, "Protocol error - missed prepare message!");
      return 1;
    }
    if (check_msg_type("Middlebox test", TEST_PREPARE, msgType, buff, msgLen)) {
      return 2;
    }
    if (msgLen <= 0) {
      log_println(0, "Improper message");
      return 3;
    }
    buff[msgLen] = 0;
    if (check_int(buff, &midport)) {
      log_println(0, "Invalid port number");
      return 4;
    }
    log_println(1, "  -- port: %d", midport);
    if ((sec_addr = I2AddrByNode(get_errhandle(), host)) == NULL) {
      log_println(0, "Unable to resolve server address: %s", strerror(errno));
      return -3;
    }
    I2AddrSetPort(sec_addr, midport);

    if (get_debuglvl() > 4) {
      char tmpbuff[200];
      size_t tmpBufLen = 199;
      memset(tmpbuff, 0, 200);
      I2AddrNodeName(sec_addr, tmpbuff, &tmpBufLen);
      log_println(5, "connecting to %s:%d", tmpbuff, I2AddrPort(sec_addr));
    }

    if ((ret = CreateConnectSocket(&in2Socket, NULL, sec_addr, conn_options, buf_size))) {
      log_println(0, "Connect() for middlebox failed: %s", strerror(errno));
      return -10;
    }

    printf("Checking for Middleboxes . . . . . . . . . . . . . . . . . .  ");
    fflush(stdout);
    tmpstr2[0] = '\0';
    i = 0;
    bytes = 0;
    t = secs() + 5.0;
    sel_tv.tv_sec = 6;
    sel_tv.tv_usec = 5;
    FD_ZERO(&rfd);
    FD_SET(in2Socket, &rfd);
    for (;;) {
      if (secs() > t)
        break;
      ret = select(in2Socket+1, &rfd, NULL, NULL, &sel_tv);
      if (ret > 0) {
        inlth = read(in2Socket, buff, sizeof(buff));
        if (inlth == 0)
          break;
        bytes += inlth;
        continue;
      }
      if (ret < 0) {
        printf("nothing to read, exiting read loop\n");
        break;
      }
      if (ret == 0) {
        printf("timer expired, exiting read loop\n");
        break;
      }
    }
    t =  secs() - t + 5.0;
    spdin = ((8.0 * bytes) / 1000) / t;

    msgLen = sizeof(buff);
    if (recv_msg(ctlSocket, &msgType, buff, &msgLen)) {
      log_println(0, "Protocol error - missed text message!");
      return 1;
    }
    if (check_msg_type("Middlebox test results", TEST_MSG, msgType, buff, msgLen)) {
      return 2;
    }
    strncat(tmpstr2, buff, msgLen);

    memset(buff, 0, 128);
    sprintf(buff, "%0.0f", spdin);
    log_println(4, "CWND limited speed = %0.2f kbps", spdin);
    send_msg(ctlSocket, TEST_MSG, buff, strlen(buff));
    printf("Done\n");

    I2AddrFree(sec_addr);

    msgLen = sizeof(buff);
    if (recv_msg(ctlSocket, &msgType, buff, &msgLen)) {
      log_println(0, "Protocol error - missed finalize message!");
      return 1;
    }
    if (check_msg_type("Middlebox test", TEST_FINALIZE, msgType, buff, msgLen)) {
      return 2;
    }
    log_println(1, " <-------------------->");
  }
  return 0;
}
示例#3
0
文件: network.c 项目: JSTLUV/ndt
static int OpenSocket(I2Addr addr, char* serv, int family, int options) {
  int fd = -1;
  int return_code = 0;

  struct addrinfo *fai = NULL;
  if (!(fai = I2AddrAddrInfo(addr, NULL, serv))) {
    return -2;
  }

  // Attempt to connect to one of the chosen addresses.
  struct addrinfo* ai = NULL;
  for (ai = fai; ai; ai = ai->ai_next) {
    if (ai->ai_family != family)
      continue;

    // create socket with obtained address domain, socket type and protocol
    fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);

    // socket create failed. Abandon further activities using this socket
    if (fd < 0)
      continue;

    // allow sockets to reuse local address while binding unless there
    // is an active listener. If unable to set this option, indicate failure
    int on = 1;
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) {
      return_code = -2;
      goto failsock;
    }
    // end trying to set socket option to reuse local address

#ifdef AF_INET6
#ifdef IPV6_V6ONLY
    if (family == AF_INET6 && (options & OPT_IPV6_ONLY)) {
      on = 1;
      // the IPv6 version socket option setup
      if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) != 0) {
        return_code = -2;
        goto failsock;
      }
    }
#endif
#endif

    // try to bind to address
    if (bind(fd, ai->ai_addr, ai->ai_addrlen) == 0) {  // successful
      // set values in "addr" structure
      if (!I2AddrSetSAddr(addr, ai->ai_addr, ai->ai_addrlen) ||
          !I2AddrSetProtocol(addr, ai->ai_protocol) ||
          !I2AddrSetSocktype(addr, ai->ai_socktype)) {
        log_println(1, "OpenSocket: Unable to set saddr in address record");
        return_code = -1;
        goto failsock;
      }
      // set port if not already done, else return -1
      if (!I2AddrPort(addr)) {
        struct sockaddr_storage tmp_addr;
        socklen_t tmp_addr_len = sizeof(tmp_addr);
        I2Addr tmpAddr;
        if (getsockname(fd, (struct sockaddr*) &tmp_addr,
                        &tmp_addr_len)) {
          log_println(1, "OpenSocket: Unable to getsockname in address record");
          return_code = -1;
          goto failsock;
        }
        tmpAddr = I2AddrBySAddr(
            get_errhandle(), (struct sockaddr*) &tmp_addr, tmp_addr_len, 0, 0);
        I2AddrSetPort(addr, I2AddrPort(tmpAddr));
        I2AddrFree(tmpAddr);
      }
      // save socket file descriptor
      if (!I2AddrSetFD(addr, fd, True)) {
        log_println(1, "OpenSocket: Unable to set file descriptor in address "
                    "record");
        return_code = -1;
        goto failsock;
      }
      // end setting values in "addr" structure

      break;
    }

    // Address is indicated as being in use. Display actual socket options to
    // user and return
    if (errno == EADDRINUSE) {
      /* RAC debug statemement 10/11/06 */
      socklen_t onSize = sizeof(on);
      getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, &onSize);
      log_println(1, "bind(%d) failed: Address already in use given as the "
                  "reason, getsockopt() returned %d", fd, on);
    } else {
      log_println(1, "bind(%d) failed: %s", fd, strerror(errno));
    }
    return_code = -1;
    goto failsock;
  }

  return fd;

  // If opening socket failed, print error, and try to close socket
  // file-descriptor.
 failsock:
  while ((close(fd) < 0) && (errno == EINTR)) { }
  return return_code;
}
示例#4
0
/**
 * Perform the C2S Throughput test. This test intends to measure throughput
 * from the client to the server by performing a 10 seconds memory-to-memory
 * data transfer.
 *
 * Protocol messages are exchanged between the Client and the Server using the
 * same connection and message format as the NDTP-Control protocol.Throughput
 * packets are sent on the new connection and do not follow the NDTP-Control
 * protocol message format.
 *
 * When the Client stops streaming the test data (or the server test routine
 * times out), the Server sends the Client its calculated throughput value.
 *
 * @param ctl Client control Connection
 * @param agent Web100 agent used to track the connection
 * @param testOptions Test options
 * @param conn_options connection options
 * @param c2sspd In-out parameter to store C2S throughput value
 * @param set_buff enable setting TCP send/recv buffer size to be used (seems
 *                 unused in file)
 * @param window value of TCP send/rcv buffer size intended to be used.
 * @param autotune autotuning option. Deprecated.
 * @param device string device name inout parameter
 * @param options Test Option variables
 * @param record_reverse integer indicating whether receiver-side statistics
 *                       have to be logged
 * @param count_vars count of web100 variables
 * @param spds[] [] speed check array
 * @param spd_index  index used for speed check array
 * @param conn_options Connection options
 * @param ctx The SSL context (possibly NULL)
 * @param c2s_ThroughputSnapshots Variable used to set c2s throughput snapshots
 * @param extended indicates if extended c2s test should be performed
 * @return 0 on success, an error code otherwise
 *         Error codes:
 *           -1 - Listener socket creation failed
 *           -100 - Timeout while waiting for client to connect to server's
 *                  ephemeral port
 *           -101 - Retries exceeded while waiting for client to connect
 *           -102 - Retries exceeded while waiting for data from connected
 *                  client
 *           -errno - Other specific socket error numbers
 */
int test_c2s(Connection *ctl, tcp_stat_agent *agent, TestOptions *testOptions,
             int conn_options, double *c2sspd, int set_buff, int window,
             int autotune, char *device, Options *options, int record_reverse,
             int count_vars, char spds[4][256], int *spd_index, SSL_CTX *ctx,
             struct throughputSnapshot **c2s_ThroughputSnapshots,
             int extended) {
  tcp_stat_connection conn;
  tcp_stat_group *group = NULL;
  /* The pipe that will return packet pair results */
  int mon_pipe[2];
  int packet_trace_running = 0;
  pid_t c2s_childpid = 0;       // child process pids
  int msgretvalue, read_error;  // used during the "read"/"write" process
  int i;                  // used as loop iterator
  int conn_index, attempts;
  int retvalue = 0;
  int streamsNum = 1;
  int activeStreams = 1;
  int local_errno;

  struct sockaddr_storage cli_addr[MAX_STREAMS];
  Connection c2s_conns[MAX_STREAMS];
  struct throughputSnapshot *lastThroughputSnapshot;

  socklen_t clilen;
  char tmpstr[256];  // string array used for all sorts of temp storage purposes
  double start_time, measured_test_duration;
  double throughputSnapshotTime;  // specify the next snapshot time
  double testDuration = 10;       // default test duration
  double bytes_read = 0;    // number of bytes read during the throughput tests
  struct timeval sel_tv;    // time
  fd_set rfd;       // receive file descriptors
  int max_fd;
  char buff[BUFFSIZE + 1];  // message "payload" buffer
  PortPair pair;            // socket ports
  I2Addr c2ssrv_addr = NULL;  // c2s test's server address
  // I2Addr src_addr=NULL;  // c2s test source address
  char listenc2sport[10];  // listening port
  pthread_t workerThreadId;

  // snap related variables
  SnapArgs snapArgs;
  snapArgs.snap = NULL;
#if USE_WEB100
  snapArgs.log = NULL;
#endif
  snapArgs.delay = options->snapDelay;

  // Test ID and status descriptors
  enum TEST_ID testids = extended ? C2S_EXT : C2S;
  enum TEST_STATUS_INT teststatuses = TEST_NOT_STARTED;
  char namesuffix[256] = "c2s_snaplog";

  for (i = 0; i < MAX_STREAMS; i++) {
    c2s_conns[i].socket = 0;
    c2s_conns[i].ssl = NULL;
  }

  if (!extended && testOptions->c2sopt) {
    setCurrentTest(TEST_C2S);
  } else if (extended && testOptions->c2sextopt) {
    setCurrentTest(TEST_C2S_EXT);
  } else {
    return 0;
  }
  log_println(1, " <-- %d - C2S throughput test -->", testOptions->child0);
  strlcpy(listenc2sport, PORT2, sizeof(listenc2sport));

  // log protocol validation logs
  teststatuses = TEST_STARTED;
  protolog_status(testOptions->child0, testids, teststatuses, ctl->socket);

  // Determine port to be used. Compute based on options set earlier
  // by reading from config file, or use default port2 (3002).
  if (testOptions->c2ssockport) {
    snprintf(listenc2sport, sizeof(listenc2sport), "%d",
             testOptions->c2ssockport);
  } else if (testOptions->mainport) {
    snprintf(listenc2sport, sizeof(listenc2sport), "%d",
             testOptions->mainport + 1);
  }

  if (testOptions->multiple) {
    strlcpy(listenc2sport, "0", sizeof(listenc2sport));
  }

  // attempt to bind to a new port and obtain address structure with details
  // of listening port
  while (c2ssrv_addr == NULL) {
    c2ssrv_addr = CreateListenSocket(
        NULL, (testOptions->multiple
                   ? mrange_next(listenc2sport, sizeof(listenc2sport))
                   : listenc2sport),
        conn_options, 0);
    if (strcmp(listenc2sport, "0") == 0) {
      log_println(1, "WARNING: ephemeral port number was bound");
      break;
    }
    if (testOptions->multiple == 0) {
      break;
    }
  }
  if (c2ssrv_addr == NULL) {
    log_println(0,
                "Server (C2S throughput test): CreateListenSocket failed: %s",
                strerror(errno));
    snprintf(buff, sizeof(buff),
             "Server (C2S throughput test): CreateListenSocket failed: %s",
             strerror(errno));
    send_json_message_any(ctl, MSG_ERROR, buff, strlen(buff),
                          testOptions->connection_flags, JSON_SINGLE_VALUE);
    return -1;
  }

  // get socket FD and the ephemeral port number that client will connect to
  // run tests
  testOptions->c2ssockfd = I2AddrFD(c2ssrv_addr);
  testOptions->c2ssockport = I2AddrPort(c2ssrv_addr);
  log_println(1, "  -- c2s %d port: %d", testOptions->child0,
              testOptions->c2ssockport);
  if (extended) {
    log_println(1, "  -- c2s ext -- duration = %d", options->c2s_duration);
    log_println(1,
                "  -- c2s ext -- throughput snapshots: enabled = %s, "
                "delay = %d, offset = %d",
                options->c2s_throughputsnaps ? "true" : "false",
                options->c2s_snapsdelay, options->c2s_snapsoffset);
    log_println(1, "  -- c2s ext -- number of streams: %d",
                options->c2s_streamsnum);
  }
  pair.port1 = testOptions->c2ssockport;
  pair.port2 = -1;

  log_println(
      1, "listening for Inet connection on testOptions->c2ssockfd, fd=%d",
      testOptions->c2ssockfd);

  log_println(
      1, "Sending 'GO' signal, to tell client %d to head for the next test",
      testOptions->child0);
  snprintf(buff, sizeof(buff), "%d", testOptions->c2ssockport);
  if (extended) {
    snprintf(buff, sizeof(buff), "%d %d %d %d %d %d",
             testOptions->c2ssockport, options->c2s_duration,
             options->c2s_throughputsnaps, options->c2s_snapsdelay,
             options->c2s_snapsoffset, options->c2s_streamsnum);
    lastThroughputSnapshot = NULL;
  }

  // send TEST_PREPARE message with ephemeral port detail, indicating start
  // of tests
  if ((msgretvalue = send_json_message_any(
           ctl, TEST_PREPARE, buff, strlen(buff),
           testOptions->connection_flags, JSON_SINGLE_VALUE)) < 0) {
    log_println(2, "Child %d could not send details about ephemeral port",
                getpid());
    return msgretvalue;
  }

  // Wait on listening socket and read data once ready.
  // Retry 5 times,  waiting for activity on the socket
  clilen = sizeof(cli_addr);
  log_println(6, "child %d - sent c2s prepare to client",
              testOptions->child0);
  FD_ZERO(&rfd);
  FD_SET(testOptions->c2ssockfd, &rfd);
  sel_tv.tv_sec = 5;
  sel_tv.tv_usec = 0;
  if (extended) {
    streamsNum = options->c2s_streamsnum;
    testDuration = options->c2s_duration / 1000.0;
  }

  conn_index = 0;
  for (attempts = 0;
       attempts < RETRY_COUNT * streamsNum && conn_index < streamsNum;
       attempts++) {
    msgretvalue = select((testOptions->c2ssockfd) + 1, &rfd, NULL, NULL,
                         &sel_tv);  // TODO
    // socket interrupted. continue waiting for activity on socket
    if ((msgretvalue == -1) && (errno == EINTR)) {
      continue;
    }
    if (msgretvalue == 0)  // timeout
      retvalue = -SOCKET_CONNECT_TIMEOUT;
    if (msgretvalue < 0)  // other socket errors. exit
      retvalue = -errno;
    if (!retvalue) {
      // If a valid connection request is received, client has connected.
      // Proceed.
      c2s_conns[conn_index].socket = accept(
          testOptions->c2ssockfd,
          (struct sockaddr *)&cli_addr[conn_index],
          &clilen);
      // socket interrupted, wait some more
      if ((c2s_conns[conn_index].socket == -1) && (errno == EINTR)) {
        log_println(
            6,
            "Child %d interrupted while waiting for accept() to complete",
            testOptions->child0);
        continue;
      }
      if (c2s_conns[conn_index].socket <= 0) {
        continue;
      }
      log_println(6, "accept(%d/%d) for %d completed", conn_index + 1,
                  streamsNum, testOptions->child0);

      // log protocol validation indicating client accept
      protolog_procstatus(testOptions->child0, testids, CONNECT_TYPE,
                          PROCESS_STARTED, c2s_conns[conn_index].socket);
      if (testOptions->connection_flags & TLS_SUPPORT) {
        errno = setup_SSL_connection(&c2s_conns[conn_index], ctx);
        if (errno != 0) return -errno;
      }

      // To preserve user privacy, make sure that the HTTP header
      // processing is done prior to the start of packet capture, as many
      // browsers have headers that uniquely identify a single user.
      if (testOptions->connection_flags & WEBSOCKET_SUPPORT) {
        if (initialize_websocket_connection(&c2s_conns[conn_index], 0, "c2s") !=
            0) {
          close_all_connections(c2s_conns, streamsNum);
          return -EIO;
        }
      }

      conn_index++;
    }

    if (retvalue) {
      log_println(
          6,
          "-------     C2S connection setup for %d returned because (%d)",
          testOptions->child0, retvalue);
      close_all_connections(c2s_conns, streamsNum);
      return retvalue;
    }
  }
  // If we haven't created enough streams after the loop is over, quit.
  if (conn_index != streamsNum) {
    log_println(
        6,
        "c2s child %d, unable to open connection, return from test",
        testOptions->child0);
     close_all_connections(c2s_conns, streamsNum);
     return RETRY_EXCEEDED_WAITING_DATA;
  }

  // Get address associated with the throughput test. Used for packet tracing
  log_println(6, "child %d - c2s ready for test with fd=%d",
              testOptions->child0, c2s_conns[0].socket);

  // commenting out below to move to init_pkttrace function
  I2Addr src_addr = I2AddrByLocalSockFD(get_errhandle(), c2s_conns[0].socket, 0);

  // Get tcp_stat connection. Used to collect tcp_stat variable statistics
  conn = tcp_stat_connection_from_socket(agent, c2s_conns[0].socket);

  // set up packet tracing. Collected data is used for bottleneck link
  // calculations
  if (getuid() == 0) {
    if (pipe(mon_pipe) != 0) {
      log_println(0, "C2S test error: can't create pipe.");
    } else {
      if ((c2s_childpid = fork()) == 0) {
        close(testOptions->c2ssockfd);
        close_all_connections(c2s_conns, streamsNum);
        // Don't capture more than 14 seconds of packet traces:
        //   2 seconds of sleep + 10 seconds of test + 2 seconds of slop
        alarm(testDuration + RACE_CONDITION_WAIT_TIME + 2);
        log_println(
            5,
            "C2S test Child %d thinks pipe() returned fd0=%d, fd1=%d",
            testOptions->child0, mon_pipe[0], mon_pipe[1]);
        log_println(2, "C2S test calling init_pkttrace() with pd=%p",
                    &cli_addr[0]);
        init_pkttrace(src_addr, cli_addr, streamsNum, clilen,
                      mon_pipe, device, &pair, "c2s", options->c2s_duration / 1000.0);
        log_println(1, "c2s is exiting gracefully");
        /* Close the pipe */
        close(mon_pipe[0]);
        close(mon_pipe[1]);
        exit(0); /* Packet trace finished, terminate gracefully */
      } else if (c2s_childpid < 0) {
        log_println(0, "C2S test error: can't create child process.");
      }
    }

    packet_trace_running = wait_for_readable_fd(mon_pipe[0]);

    if (packet_trace_running) {
      // Get data collected from packet tracing into the C2S "ndttrace" file
      memset(tmpstr, 0, 256);
      for (i = 0; i < 5; i++) {
        msgretvalue = read(mon_pipe[0], tmpstr, 128);
        if ((msgretvalue == -1) && (errno == EINTR))
          continue;
        break;
      }

      if (strlen(tmpstr) > 5)
        memcpy(meta.c2s_ndttrace, tmpstr, strlen(tmpstr));
      // name of nettrace file passed back from pcap child
      log_println(3, "--tracefile after packet_trace %s",
                  meta.c2s_ndttrace);
    } else {
      log_println(0, "Packet trace was unable to be created");
      packet_trace_emergency_shutdown(mon_pipe);
    }
  }

  log_println(5, "C2S test Parent thinks pipe() returned fd0=%d, fd1=%d",
              mon_pipe[0], mon_pipe[1]);

  // experimental code, delete when finished
  setCwndlimit(conn, group, agent, options);

  // Create C->S snaplog directories, and perform some initialization based on
  // options
  create_client_logdir((struct sockaddr *) &cli_addr[0], clilen,
                       options->c2s_logname, sizeof(options->c2s_logname),
                       namesuffix, sizeof(namesuffix));
  sleep(RACE_CONDITION_WAIT_TIME);
  // Reset alarm() again. This 10 sec test should finish before this signal is
  // generated, but sleep() can render existing alarm()s invalid, and alarm() is
  // our watchdog timer.
  alarm(30);

  // send empty TEST_START indicating start of the test
  send_json_message_any(ctl, TEST_START, "", 0, testOptions->connection_flags,
                        JSON_SINGLE_VALUE);

  // If snaplog recording is enabled, update meta file to indicate the same
  // and proceed to get snapshot and log it.
  // This block is needed here since the meta file stores names without the
  // full directory but fopen needs full path. Else, it could have gone into
  // the "start_snap_worker" method
  if (options->snapshots && options->snaplog) {
    memcpy(meta.c2s_snaplog, namesuffix, strlen(namesuffix));
    /*start_snap_worker(&snapArgs, agent, options->snaplog, &workerLoop,
      &workerThreadId, meta.c2s_snaplog, options->c2s_logname,
      conn, group); */
  }
  if (options->snapshots)
    start_snap_worker(&snapArgs, agent, NULL, options->snaplog, &workerThreadId,
                      options->c2s_logname, conn, group);
  // Wait on listening socket and read data once ready.
  start_time = secs();
  throughputSnapshotTime = start_time + (options->c2s_snapsoffset / 1000.0);

  activeStreams = connections_to_fd_set(c2s_conns, streamsNum, &rfd, &max_fd);

  while (activeStreams > 0 && (secs() - start_time) < testDuration) {
    // POSIX says "Upon successful completion, the select() function may
    // modify the object pointed to by the timeout argument."
    // Therefore sel_tv is undefined afterwards and we must set it every time.
    sel_tv.tv_sec = testDuration + 1;  // time out after test duration + 1sec
    sel_tv.tv_usec = 0;
    msgretvalue = select(max_fd + 1, &rfd, NULL, NULL, &sel_tv);
    if (msgretvalue == -1) {
      if (errno == EINTR) {
        // select interrupted. Continue waiting for activity on socket
        continue;
      } else {
        log_println(1,
                    "Error while trying to wait for incoming data in c2s: %s",
                    strerror(errno));
        break;
      }
    }
    if (extended && options->c2s_throughputsnaps && secs() > throughputSnapshotTime) {
      if (lastThroughputSnapshot != NULL) {
        lastThroughputSnapshot->next = (struct throughputSnapshot*) malloc(sizeof(struct throughputSnapshot));
        lastThroughputSnapshot = lastThroughputSnapshot->next;
      } else {
        *c2s_ThroughputSnapshots = lastThroughputSnapshot = (struct throughputSnapshot*) malloc(sizeof(struct throughputSnapshot));
      }
      lastThroughputSnapshot->next = NULL;
      lastThroughputSnapshot->time = secs() - start_time;
      lastThroughputSnapshot->throughput = (8.e-3 * bytes_read) / (lastThroughputSnapshot->time);  // kbps
      log_println(6, " ---C->S: Throughput at %0.2f secs: Received %0.0f bytes, Spdin= %f",
                     lastThroughputSnapshot->time, bytes_read, lastThroughputSnapshot->throughput);
      throughputSnapshotTime += options->c2s_snapsdelay / 1000.0;
    }

    if (msgretvalue > 0) {
      read_error = read_ready_streams(&rfd, c2s_conns, streamsNum, buff, sizeof(buff), &bytes_read);
      if (read_error != 0 && read_error != EINTR) {
        // EINTR is expected, but all other errors are actually errors
        log_println(1, "Error while trying to read incoming data in c2s: %s",
                    strerror(read_error));
        break;
      }
    }

    // Set up the FD_SET and activeStreams for the next select.
    activeStreams = connections_to_fd_set(c2s_conns, streamsNum, &rfd, &max_fd);
  }
  measured_test_duration = secs() - start_time;
  // From the NDT spec:
  //  throughput in kilo bits per sec =
  //  (transmitted_byte_count * 8) / (time_duration)*(1000)
  *c2sspd = (8.0e-3 * bytes_read) / measured_test_duration;

  // As a kindness to old clients, drain their queues for a second or two.
  // TODO: Fix web100clt code to eliminate the need for this.  In general,
  //       clients that need this line should be removed from their respective
  //       gene pools and this code should be deleted.
  drain_old_clients(c2s_conns, streamsNum, buff, sizeof(buff));

  // c->s throuput value calculated and assigned ! Release resources, conclude
  // snap writing.
  if (options->snapshots)
    stop_snap_worker(&workerThreadId, options->snaplog, &snapArgs);

  // send the server calculated value of C->S throughput as result to client
  snprintf(buff, sizeof(buff), "%6.0f kbps outbound for child %d", *c2sspd,
           testOptions->child0);
  log_println(1, "%s", buff);
  snprintf(buff, sizeof(buff), "%0.0f", *c2sspd);
  if (extended && options->c2s_throughputsnaps && *c2s_ThroughputSnapshots != NULL) {
    struct throughputSnapshot *snapshotsPtr = *c2s_ThroughputSnapshots;
    while (snapshotsPtr != NULL) {
      int currBuffLength = strlen(buff);
      snprintf(&buff[currBuffLength], sizeof(buff)-currBuffLength, " %0.2f %0.2f", snapshotsPtr->time, snapshotsPtr->throughput);
      snapshotsPtr = snapshotsPtr->next;
    }
  }
  send_json_message_any(ctl, TEST_MSG, buff, strlen(buff),
                        testOptions->connection_flags, JSON_SINGLE_VALUE);

  // get receiver side Web100 stats and write them to the log file. close
  // sockets
  if (record_reverse == 1)
    tcp_stat_get_data_recv(c2s_conns[0].socket, agent, conn, count_vars);


  close_all_connections(c2s_conns, streamsNum);
  close(testOptions->c2ssockfd);

  if (packet_trace_running) {
    log_println(1, "Signal USR1(%d) sent to child [%d]", SIGUSR1,
                c2s_childpid);
    testOptions->child1 = c2s_childpid;
    kill(c2s_childpid, SIGUSR1);
    i = 0;

    for (;;) {
      FD_ZERO(&rfd);
      FD_SET(mon_pipe[0], &rfd);
      sel_tv.tv_sec = 1;
      sel_tv.tv_usec = 100000;
      msgretvalue = select(mon_pipe[0] + 1, &rfd, NULL, NULL, &sel_tv);
      if (msgretvalue <= 0) {
        local_errno = (msgretvalue == -1) ? errno : 0;
        if (local_errno == EINTR) continue;
        // Either a timeout or an error that wasn't EINTR...
        log_println(4, "Failed to read pkt-pair data from C2S flow, "
                    "retcode=%d, reason=%d", msgretvalue, local_errno);
        snprintf(spds[(*spd_index)++],
                 sizeof(spds[*spd_index]),
                 " -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0.0 0 0 0 0 0 -1");
        snprintf(spds[(*spd_index)++],
                 sizeof(spds[*spd_index]),
                 " -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0.0 0 0 0 0 0 -1");
        break;
      } else {
        /* There is something to read, so get it from the pktpair child.  If an
         * interrupt occurs, just skip the read and go on
         * RAC 2/8/10
         */
        if ((msgretvalue = read(mon_pipe[0], spds[*spd_index],
                                sizeof(spds[*spd_index]))) < 0) {
          snprintf(
              spds[*spd_index],
              sizeof(spds[*spd_index]),
              " -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0.0 0 0 0 0 0 -1");
        }
        log_println(1, "%d bytes read '%s' from C2S monitor pipe",
                    msgretvalue, spds[*spd_index]);
        (*spd_index)++;
        if (i++ == 1) break;
      }
    }
  }

  // An empty TEST_FINALIZE message is sent to conclude the test
  send_json_message_any(ctl, TEST_FINALIZE, "", 0,
                        testOptions->connection_flags, JSON_SINGLE_VALUE);

  //  Close opened resources for packet capture
  if (packet_trace_running) {
    // TODO: Determine whether this shutdown can be performed in a non-blocking
    // manner, and if so then refactor packet_trace_emergency_shutdown to have
    // better error handling and use that refactored and renamed function here.
    stop_packet_trace(mon_pipe);
    packet_trace_running = 0;
  }

  // log end of C->S test
  log_println(1, " <----------- %d -------------->", testOptions->child0);
  // protocol logs
  teststatuses = TEST_ENDED;
  protolog_status(testOptions->child0, testids, teststatuses, ctl->socket);

  // set current test status and free address
  setCurrentTest(TEST_NONE);


  return 0;
}
示例#5
0
static int
OpenSocket(I2Addr addr, char* serv, int options)
{
  struct addrinfo *fai;
  struct addrinfo *ai;
  int             on;
  socklen_t       onSize;
  int             fd=-1;

  if (!(fai = I2AddrAddrInfo(addr, NULL, serv))) {
    return -2;
  }

  for (ai = fai; ai; ai = ai->ai_next) {
#ifdef AF_INET6
    if (options & OPT_IPV6_ONLY) {
      if(ai->ai_family != AF_INET6)
        continue;
    }
#endif
    
    if (options & OPT_IPV4_ONLY) {
      if(ai->ai_family != AF_INET)
        continue;
    }

    fd = socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol);

/* 
    if (meta.family == 0)
	meta.family = ai->ai_family;
 */

    if (fd < 0) {
      continue;
    }

    on=1;
    if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) != 0) {
      goto failsock;
    }

#if defined(AF_INET6) && defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
    if ((ai->ai_family == AF_INET6) && (options & OPT_IPV6_ONLY) &&
        setsockopt(fd,IPPROTO_IPV6,IPV6_V6ONLY,&on,sizeof(on)) != 0) {
      goto failsock;
    }
#endif

    if (bind(fd,ai->ai_addr,ai->ai_addrlen) == 0) {

      if (!I2AddrSetSAddr(addr,ai->ai_addr,ai->ai_addrlen) ||
          !I2AddrSetProtocol(addr,ai->ai_protocol) ||
          !I2AddrSetSocktype(addr,ai->ai_socktype)) {
        log_println(1, "OpenSocket: Unable to set saddr in address record");
        return -1;
      }
      if (!I2AddrPort(addr)) {
        struct sockaddr_storage tmp_addr;
        socklen_t tmp_addr_len = sizeof(tmp_addr);
        I2Addr tmpAddr;
        if (getsockname(fd, (struct sockaddr*) &tmp_addr, &tmp_addr_len)) {
          return -1;
        }
        tmpAddr = I2AddrBySAddr(get_errhandle(), (struct sockaddr*) &tmp_addr, tmp_addr_len, 0, 0);
        I2AddrSetPort(addr, I2AddrPort(tmpAddr));
        I2AddrFree(tmpAddr);
      }
      if (!I2AddrSetFD(addr,fd,True)) {
        log_println(1, "OpenSocket: Unable to set file descriptor in address record");
        return -1;
      }

      break;
    }

    if (errno == EADDRINUSE) {
      /* RAC debug statemement 10/11/06 */
      onSize = sizeof(on);
      getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, &onSize);
      log_println(1, "bind(%d) failed: Address already in use given as the reason, getsockopt() returned %d", fd, on);
      return -2;
    }

failsock:
    /* RAC debug statemement 10/11/06 */
    log_println(1, "failsock: Unable to set socket options for fd=%d", fd);
    while((close(fd) < 0) && (errno == EINTR));
  }
  
  if (meta.family == 0)
    meta.family = ai->ai_family;
  return fd;
}
示例#6
0
/**
 * Perform the client part of the middleBox testing. The middlebox test
 * is a 5.0 second throughput test from the Server to the Client to
 * check for duplex mismatch conditions. It determines if routers or
 * switches in the path may be making changes to some TCP parameters.
 * @param ctlSocket server control socket descriptor
 * @param tests set of tests to perform
 * @param host hostname of the server
 * @param conn_options connection options
 * @param buf_size TCP send/receive buffer size
 * @param testresult_str result obtained from server (containing server ip,
 * 						client ip, currentMSS, WinSCaleSent, WinScaleRcvd)
 * @param jsonSupport Indicates if messages should be sent using JSON format
 * @return  integer
 *     => 0 on success
 *     < 0 if error
 *     Return codes used:
 *     0 = (the test has been finalized)
 *     > 0 if protocol interactions were not as expected:
 *     		1: Unable to receive protocol message successfully
 * 			2: Wrong message type received
 *			3: Protocol message received was of invalid length
 *			4: Protocol payload data received was invalid
 *			5: Protocol message received was invalid
 *     < 0 if generic error:
 *			-3: Unable to resolve server address
 *			-10: creating connection to server failed
 *
 */
int test_mid_clt(int ctlSocket, char tests, char* host, int conn_options,
                 int buf_size, char* testresult_str, int jsonSupport) {
  char buff[BUFFSIZE + 1];
  int msgLen, msgType;
  int midport = atoi(PORT3);
  I2Addr sec_addr = NULL;
  int retcode, inlth;
  int in2Socket;
  double t, spdin;
  uint32_t bytes;
  struct timeval sel_tv;
  fd_set rfd;
  char* jsonMsgValue;

  enum TEST_STATUS_INT teststatuses = TEST_NOT_STARTED;
  enum TEST_ID testids = MIDDLEBOX;

  if (tests & TEST_MID) {  // middlebox test has to be performed
    log_println(1, " <-- Middlebox test -->");
    setCurrentTest(TEST_MID);
    // protocol logs
    teststatuses = TEST_STARTED;
    protolog_status(getpid(), testids, teststatuses, ctlSocket);


    //  Initially, expecting a TEST_PREPARE message. Any other message
    // ..type is unexpected at this stage.

    msgLen = sizeof(buff);
    if (recv_msg(ctlSocket, &msgType, buff, &msgLen)) {
      log_println(0, "Protocol error - missed prepare message!");
      return 1;
    }
    if (check_msg_type(MIDBOX_TEST_LOG, TEST_PREPARE, msgType, buff, msgLen)) {
      return 2;
    }

    // The server is expected to send a message with a valid payload that
    // contains the port number that server wants client to bind to for this
    // test
    buff[msgLen] = 0;
    if (jsonSupport) {
      jsonMsgValue = json_read_map_value(buff, DEFAULT_KEY);
      strlcpy(buff, jsonMsgValue, sizeof(buff));
      msgLen = strlen(buff);
      free(jsonMsgValue);
    }
    if (msgLen <= 0) {
      log_println(0, "Improper message");
      return 3;
    }
    if (check_int(buff, &midport)) {  // obtained message does not contain
                                      // integer port#
      log_println(0, "Invalid port number");
      return 4;
    }

    // get server address and set port
    log_println(1, "  -- port: %d", midport);
    if ((sec_addr = I2AddrByNode(get_errhandle(), host)) == NULL) {
      log_println(0, "Unable to resolve server address: %s", strerror(errno));
      return -3;
    }
    I2AddrSetPort(sec_addr, midport);

    // debug to check if correct port was set in addr struct
    if (get_debuglvl() > 4) {
      char tmpbuff[200];
      size_t tmpBufLen = 199;
      memset(tmpbuff, 0, 200);
      I2AddrNodeName(sec_addr, tmpbuff, &tmpBufLen);
      log_println(5, "connecting to %s:%d", tmpbuff, I2AddrPort(sec_addr));
    }

    // connect to server using port obtained above
    if ((retcode = CreateConnectSocket(&in2Socket, NULL, sec_addr,
                                       conn_options, buf_size))) {
      log_println(0, "Connect() for middlebox failed: %s", strerror(errno));
      return -10;
    }

    // start reading throughput test data from server using the connection
    // created above
    printf("Checking for Middleboxes . . . . . . . . . . . . . . . . . .  ");
    fflush(stdout);
    testresult_str[0] = '\0';
    bytes = 0;
    t = secs() + 5.0;  // set timer for 5 seconds, and read for 5 seconds
    sel_tv.tv_sec = 6;  // Time out the socket after 6.5 seconds
    sel_tv.tv_usec = 5;  // 500?
    FD_ZERO(&rfd);
    FD_SET(in2Socket, &rfd);
    for (;;) {
      if (secs() > t)
        break;
      retcode = select(in2Socket+1, &rfd, NULL, NULL, &sel_tv);
      if (retcode > 0) {
        inlth = read(in2Socket, buff, sizeof(buff));
        if (inlth == 0)
          break;
        bytes += inlth;
        continue;
      }
      if (retcode < 0) {
        printf("nothing to read, exiting read loop\n");
        break;
      }
      if (retcode == 0) {
        printf("timer expired, exiting read loop\n");
        break;
      }
    }
    // get actual time for which test was run
    t = secs() - t + 5.0;

    // calculate throughput in Kbps
    spdin = ((BITS_8_FLOAT * bytes) / KILO) / t;

    // Test is complete. Now, get results from server (includes CurrentMSS,
    // WinScaleSent, WinScaleRcvd..).
    // The results are sent from server in the form of a TEST_MSG object
    msgLen = sizeof(buff);
    if (recv_msg(ctlSocket, &msgType, buff, &msgLen)) {
      log_println(0, "Protocol error - missed text message!");
      return 1;
    }
    if (check_msg_type(MIDBOX_TEST_LOG " results", TEST_MSG, msgType, buff,
                       msgLen)) {
      return 2;
    }
    buff[msgLen] = 0;

    strlcat(testresult_str, buff, MIDBOX_TEST_RES_SIZE);

    memset(buff, 0, sizeof(buff));
    // this should work since the throughput results from the server should
    //  ...fit well within BUFFSIZE
    snprintf(buff, sizeof(buff), "%0.0f", spdin);
    log_println(4, "CWND limited speed = %0.2f kbps", spdin);

    // client now sends throughput it calculated above to server, as a TEST_MSG
    send_json_message(ctlSocket, TEST_MSG, buff, strlen(buff), jsonSupport, JSON_SINGLE_VALUE);
    printf("Done\n");

    I2AddrFree(sec_addr);

    // Expect an empty TEST_FINALIZE message from server
    msgLen = sizeof(buff);
    if (recv_msg(ctlSocket, &msgType, buff, &msgLen)) {
      log_println(0, "Protocol error - missed finalize message!");
      return 1;
    }
    if (check_msg_type(MIDBOX_TEST_LOG, TEST_FINALIZE, msgType, buff, msgLen)) {
      return 2;
    }
    log_println(1, " <-------------------->");
    // log protocol test ending
    teststatuses = TEST_ENDED;
    protolog_status(getpid(), testids, teststatuses, ctlSocket);
    setCurrentTest(TEST_NONE);
  }
  return 0;
}