コード例 #1
0
ファイル: fakewww.c プロジェクト: m-lab/ndt-debian
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
ファイル: network.c プロジェクト: JSTLUV/ndt
int CreateConnectSocket(int* sockfd, I2Addr local_addr, I2Addr server_addr,
                        int options, int buf_size) {
  struct addrinfo *fai = NULL;
  struct addrinfo *ai = NULL;
  struct addrinfo *lfai = NULL;
  struct addrinfo *lai = NULL;
  socklen_t optlen;
  int set_size;

  assert(sockfd);
  assert(server_addr);

  if (!server_addr) {
    log_println(1, "Invalid server address");
    goto error;
  }

  // already connected and bound
  if ((*sockfd = I2AddrFD(server_addr)) > -1) {
    return 0;
  }

  if (!(fai = I2AddrAddrInfo(server_addr, NULL, NULL))) {
    log_println(1, "Failed to get address info for server address");
    goto error;
  }

  int family = AF_UNSPEC;
#ifdef AF_INET6
  // options provided by user indicate V6 or V4 only
  if ((options & OPT_IPV6_ONLY) != 0)
    family = AF_INET6;
#endif
  else if ((options & OPT_IPV4_ONLY) != 0)
    family = AF_INET;

  for (ai = fai; ai; ai = ai->ai_next) {
    if (family != AF_UNSPEC && ai->ai_family != family) {
      log_println(1, "Skipping family %d", family);
      continue;
    }

    // create socket with obtained address domain, socket type and protocol
    *sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    if (*sockfd < 0) {
      // socket create failed. Abandon further activities using this socket
      log_println(1, "Failed to create %d %d %d", ai->ai_family,
                  ai->ai_socktype, ai->ai_protocol);
      continue;
    }

    // local address has been specified. Get details and bind to this adderess
    if (local_addr) {
      printf("local_addr\n");
      int bindFailed = 1;
      if (!(lfai = I2AddrAddrInfo(local_addr, NULL, NULL)))
        continue;

      // Validate INET address family
      for (lai = lfai; lai; lai = lai->ai_next) {
        if (lai->ai_family != family)
          continue;

        // bind to local address
        if (bind((*sockfd), lai->ai_addr, lai->ai_addrlen) == 0) {
          bindFailed = 0;  // bind successful
          break; /* success */
        }
      }

      // Failed to bind. Close socket file-descriptor and move on
      if (bindFailed == 1) {
        close((*sockfd)); /* ignore this one */
        continue;
      }
    }  // end local address

    /* Set sock opt code from Marion Nakanson <[email protected]
     *  OHSU Advanced Computing Center
     * email on 2/19/09 correctly notes that setsockops must be made before open()
     * or listen() calls are made
     */

    optlen = sizeof(set_size);
    // get send buffer size for logs
    getsockopt(*sockfd, SOL_SOCKET, SO_SNDBUF, &set_size, &optlen);
    log_print(5, "\nSend buffer initialized to %d, ", set_size);
    // get receive buffer size for logs
    getsockopt(*sockfd, SOL_SOCKET, SO_RCVBUF, &set_size, &optlen);
    log_println(5, "Receive buffer initialized to %d", set_size);

    // now assign buffer sizes passed as arguments
    if (buf_size > 0) {
      setsockopt(*sockfd, SOL_SOCKET, SO_SNDBUF, &buf_size,
                 sizeof(buf_size));
      setsockopt(*sockfd, SOL_SOCKET, SO_RCVBUF, &buf_size,
                 sizeof(buf_size));
      // log values for reference
      getsockopt(*sockfd, SOL_SOCKET, SO_SNDBUF, &set_size, &optlen);
      log_print(5, "Changed buffer sizes: Send buffer set to %d(%d), ",
                set_size, buf_size);
      getsockopt(*sockfd, SOL_SOCKET, SO_RCVBUF, &set_size, &optlen);
      log_println(5, "Receive buffer set to %d(%d)", set_size, buf_size);
    }

    // Connect to target socket
    if (connect(*sockfd, ai->ai_addr, ai->ai_addrlen) == 0) {
      log_println(1, "Connected!");
      // save server address values
      if (I2AddrSetSAddr(server_addr, ai->ai_addr, ai->ai_addrlen) &&
          I2AddrSetSocktype(server_addr, ai->ai_socktype) &&
          I2AddrSetProtocol(server_addr, ai->ai_protocol) &&
          I2AddrSetFD(server_addr, *sockfd, True)) {
        log_println(1, "Client socket created");
        return 0;
      }
      // unable to save
      log_println(1, "I2Addr functions failed after successful connection");
      while ((close(*sockfd) < 0) && (errno == EINTR)) { }
      return 1;
    } else {
      log_println(0, "Failed to connect: %s", strerror(errno));
      // goto error;
    }
  }

  log_println(0, "No sockets could be created that match requirements.");

 error:
  return -1;
}
コード例 #3
0
ファイル: network.c プロジェクト: JSTLUV/ndt
I2Addr CreateListenSocket(I2Addr addr, char* serv, int options, int buf_size) {
  int fd = -1;
  socklen_t optlen;
  int set_size;

  if (addr && (I2AddrFD(addr) > -1)) {
    log_println(1, "Invalid I2Addr record - fd already specified.");
    goto error;
  }

  if ((!addr) &&
      !(addr = I2AddrByWildcard(get_errhandle(), SOCK_STREAM, serv))) {
    log_println(1, "Unable to create I2Addr record by wildcard.");
    goto error;
  }

  if (!I2AddrSetPassive(addr, True)) {
    log_println(1, "Unable to set passive mode in I2Addr record.");
    goto error;
  }

  // create and bind socket using arguments, prefering v6 (since v6 addresses
  // can be both v4 and v6).
#ifdef AF_INET6
  if ((options & OPT_IPV4_ONLY) == 0)
    fd = OpenSocket(addr, serv, AF_INET6, options);
#endif
  if (fd < 0)
    if ((options & OPT_IPV6_ONLY) == 0)
      fd = OpenSocket(addr, serv, AF_INET, options);

  if (fd < 0) {
    log_println(1, "Unable to open socket.");
    goto error;
  }

  /* Set sock opt code from Marion Nakanson <[email protected]
   *  OHSU Advanced Computing Center
   * email on 2/19/09 correctly notes that setsockops must be made before open()
   * or listen() calls are made
   */

  optlen = sizeof(set_size);
  // get send buffer size
  getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &set_size, &optlen);
  log_print(5, "\nSend buffer initialized to %d, ", set_size);

  // get receive buffer size
  getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &set_size, &optlen);
  log_println(5, "Receive buffer initialized to %d", set_size);

  // now assign buffer sizes passed as arguments
  if (buf_size > 0) {
    setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size));
    setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size));
    // print values set to help user verify
    getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &set_size, &optlen);
    log_print(5, "Changed buffer sizes: Send buffer set to %d(%d), ",
              set_size, buf_size);
    getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &set_size, &optlen);
    log_println(5, "Receive buffer set to %d(%d)", set_size, buf_size);
  }

  // listen on socket for connections, with backlog queue length = NDT_BACKLOG
  if (listen(fd, NDT_BACKLOG) < 0) {  // if listen returns value <0, then error
    log_println(1, "listen(%d,%d):%s", fd, NDT_BACKLOG, strerror(errno));
    goto error;
  }

  return addr;

  // If error, try freeing memory
 error:
  I2AddrFree(addr);
  return NULL;
}
コード例 #4
0
ファイル: test_c2s_srv.c プロジェクト: Rocknrenew/ndt
/**
 * 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
int
CreateConnectSocket(int* sockfd, I2Addr local_addr, I2Addr server_addr, int options, int buf_size)
{
  struct addrinfo *fai  = NULL;
  struct addrinfo *ai   = NULL;
  struct addrinfo *lfai = NULL;
  struct addrinfo *lai  = NULL;
  socklen_t optlen;
  int set_size; 

  assert(sockfd);
  assert(server_addr);

  if (!server_addr) {
    goto error;
  }

  if ((*sockfd = I2AddrFD(server_addr)) > -1) {
    return 0;
  }

  if (!(fai = I2AddrAddrInfo(server_addr, NULL, NULL))) {
    goto error;
  }

  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;
    }

    *sockfd = socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol);
    if (*sockfd < 0) {
      continue;
    }

    if (local_addr) {
      int bindFailed = 1;
      if (!(lfai = I2AddrAddrInfo(local_addr, NULL, NULL))) {
        continue;
      }
      
      for (lai=lfai; lai; lai=lai->ai_next) {
#ifdef AF_INET6
        if (options & OPT_IPV6_ONLY) {
          if(lai->ai_family != AF_INET6)
            continue;
        }
#endif

        if (options & OPT_IPV4_ONLY) {
          if(lai->ai_family != AF_INET)
            continue;
        }

        if (bind((*sockfd), lai->ai_addr, lai->ai_addrlen) == 0) {
          bindFailed = 0;
          break;      /* success */
        }
      }

      if (bindFailed == 1) {
        close((*sockfd));  /* ignore this one */
        continue;
      }
    }

/* Set sock opt code from Marion Nakanson <[email protected]
 *  OHSU Advanced Computing Center
 * email on 2/19/09 correctly notes that setsockops must be made before open()
 * or listen() calls are made
 */

  optlen = sizeof(set_size);
  getsockopt(*sockfd, SOL_SOCKET, SO_SNDBUF, &set_size, &optlen);
  log_print(5, "\nSend buffer initialized to %d, ", set_size);
  getsockopt(*sockfd, SOL_SOCKET, SO_RCVBUF, &set_size, &optlen);
  log_println(5, "Receive buffer initialized to %d", set_size);
  if (buf_size > 0) {
    setsockopt(*sockfd, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size));
    setsockopt(*sockfd, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size));
    getsockopt(*sockfd, SOL_SOCKET, SO_SNDBUF, &set_size, &optlen);
    log_print(5, "Changed buffer sizes: Send buffer set to %d(%d), ", set_size, buf_size);
    getsockopt(*sockfd, SOL_SOCKET, SO_RCVBUF, &set_size, &optlen);
    log_println(5, "Receive buffer set to %d(%d)", set_size, buf_size);
  }

    if (connect(*sockfd,ai->ai_addr,ai->ai_addrlen) == 0) {
      if(I2AddrSetSAddr(server_addr,ai->ai_addr,ai->ai_addrlen) &&
          I2AddrSetSocktype(server_addr,ai->ai_socktype) &&
          I2AddrSetProtocol(server_addr,ai->ai_protocol) &&
          I2AddrSetFD(server_addr,*sockfd,True)){
        return 0;
      }
      log_println(1, "I2Addr functions failed after successful connection");
      while((close(*sockfd) < 0) && (errno == EINTR));
      return 1;
    }
  }

error:
  log_println(1, "Unable to create connect socket.");
  return -1;
}
コード例 #6
0
I2Addr
CreateListenSocket(I2Addr addr, char* serv, int options, int buf_size)
{
  int fd = -1;
  socklen_t optlen;
  int set_size;

  if (addr && (I2AddrFD(addr) > -1)) {
    log_println(1, "Invalid I2Addr record - fd already specified.");
    goto error;
  }

  if ((!addr) && !(addr = I2AddrByWildcard(get_errhandle(), SOCK_STREAM, serv))) {
    log_println(1, "Unable to create I2Addr record by wildcard.");
    goto error;
  }

  if (!I2AddrSetPassive(addr,True)) {
    log_println(1, "Unable to set passive mode in I2Addr record.");
    goto error;
  }
  
  fd = OpenSocket(addr, serv, options);
  
  if (fd < 0) {
    log_println(1, "Unable to open socket.");
    goto error;
  }

/* Set sock opt code from Marion Nakanson <[email protected]
 *  OHSU Advanced Computing Center
 * email on 2/19/09 correctly notes that setsockops must be made before open()
 * or listen() calls are made
 */

  optlen = sizeof(set_size);
  getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &set_size, &optlen);
  log_print(5, "\nSend buffer initialized to %d, ", set_size);
  getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &set_size, &optlen);
  log_println(5, "Receive buffer initialized to %d", set_size);
  if (buf_size > 0) {
    setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size));
    setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size));
    getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &set_size, &optlen);
    log_print(5, "Changed buffer sizes: Send buffer set to %d(%d), ", set_size, buf_size);
    getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &set_size, &optlen);
    log_println(5, "Receive buffer set to %d(%d)", set_size, buf_size);
  }


  if (listen(fd, NDT_BACKLOG) < 0) {
    log_println(1, "listen(%d,%d):%s", fd, NDT_BACKLOG, strerror(errno));
    goto error;
  }

  return addr;
  
error:
    I2AddrFree(addr);
    return NULL;
}