示例#1
0
文件: api.c 项目: candlerb/bwctl
/*
 * Function:    _BWLTestSessionFree
 *
 * Description:    
 *     This function is used to free the memory associated with a "configured"
 *     test session.
 *
 * In Args:    
 *
 * Out Args:    
 *
 * Scope:    
 * Returns:    
 * Side Effect:    
 */
BWLErrSeverity
_BWLTestSessionFree(
        BWLContext      ctx,
        BWLTestSession  tsession,
        BWLAcceptType   aval
        )
{
    BWLErrSeverity  err=BWLErrOK;

    if(!tsession){
        return BWLErrOK;
    }

    /*
     * remove this tsession from the cntrl->tests list.
     */
    if(tsession->cntrl->tests == tsession){
        tsession->cntrl->tests = NULL;
    }

    (void)_BWLEndpointStop(ctx,tsession,aval,&err);

    if(tsession->closure){
        _BWLCallTestComplete(tsession,aval);
    }

    I2AddrFree(tsession->test_spec.client);
    I2AddrFree(tsession->test_spec.server);

    while(tsession->localfp &&
            (fclose(tsession->localfp) < 0) &&
            (errno == EINTR));
    while(tsession->remotefp &&
            (fclose(tsession->remotefp) < 0) &&
            (errno == EINTR));

    free(tsession);

    return err;
}
示例#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
文件: 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;
}
示例#5
0
int
test_s2c_clt(int ctlSocket, char tests, char* host, int conn_options, int buf_size, char* tmpstr)
{
  char buff[BUFFSIZE+1];
  int msgLen, msgType;
  int s2cport = 3003;
  I2Addr sec_addr = NULL;
  int inlth, ret, one=1, set_size;
  int inSocket;
  socklen_t optlen;
  uint32_t bytes;
  double t;
  struct timeval sel_tv;
  fd_set rfd;
  char* ptr;
  
  if (tests & TEST_S2C) {
    log_println(1, " <-- S2C throughput 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("S2C throughput 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, &s2cport)) {
      log_println(0, "Invalid port number");
      return 4;
    }
    log_println(1, "  -- port: %d", s2cport);

    /* Cygwin seems to want/need this extra getsockopt() function
     * call.  It certainly doesn't do anything, but the S2C test fails
     * at the connect() call if it's not there.  4/14/05 RAC
     */
    optlen = sizeof(set_size);
    getsockopt(ctlSocket, SOL_SOCKET, SO_SNDBUF, &set_size, &optlen);

    if ((sec_addr = I2AddrByNode(get_errhandle(), host)) == NULL) {
      log_println(0, "Unable to resolve server address: %s", strerror(errno));
      return -3;
    }
    I2AddrSetPort(sec_addr, s2cport);

    if ((ret = CreateConnectSocket(&inSocket, NULL, sec_addr, conn_options, buf_size))) {
      log_println(0, "Connect() for Server to Client failed", strerror(errno));
      return -15;
    }

    setsockopt(inSocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));

    /* Linux updates the sel_tv time values everytime select returns.  This
     * means that eventually the timer will reach 0 seconds and select will
     * exit with a timeout signal.  Other OS's don't do that so they need
     * another method for detecting a long-running process.  The check below
     * will cause the loop to terminate if select says there is something
     * to read and the loop has been active for over 14 seconds.  This usually
     * happens when there is a problem (duplex mismatch) and there is data
     * queued up on the server.
     */
    
    msgLen = sizeof(buff);
    if (recv_msg(ctlSocket, &msgType, buff, &msgLen)) {
      log_println(0, "Protocol error - missed start message!");
      return 1;
    }
    if (check_msg_type("S2C throughput test", TEST_START, msgType, buff, msgLen)) {
      return 2;
    }

    printf("running 10s inbound test (server to client) . . . . . . ");
    fflush(stdout);

    bytes = 0;
    t = secs() + 15.0;
    sel_tv.tv_sec = 15;
    sel_tv.tv_usec = 5;
    FD_ZERO(&rfd);
    FD_SET(inSocket, &rfd);
    for (;;) {
      ret = select(inSocket+1, &rfd, NULL, NULL, &sel_tv);
      if (secs() > t) {
        log_println(5, "Receive test running long, break out of read loop");
        break;
      }
      if (ret > 0) {
        inlth = read(inSocket, buff, sizeof(buff));
        if (inlth == 0)
          break;
        bytes += inlth;
        continue;
      }
      if (get_debuglvl() > 5) {
        log_println(0, "s2c read loop exiting:", strerror(errno));
      }
      break;
    }
    t = secs() - t + 15.0;
    spdin = ((8.0 * bytes) / 1000) / t;

    /* receive the s2cspd from the server */
    msgLen = sizeof(buff);
    if (recv_msg(ctlSocket, &msgType, buff, &msgLen)) {
      log_println(0, "Protocol error - missed text message!");
      return 1;
    }
    if (check_msg_type("S2C throughput test", TEST_MSG, msgType, buff, msgLen)) {
      return 2;
    }
    if (msgLen <= 0) { 
      log_println(0, "Improper message");
      return 3;
    }
    buff[msgLen] = 0; 
    ptr = strtok(buff, " ");
    if (ptr == NULL) {
      log_println(0, "S2C: Improper message");
      return 4;
    }
    s2cspd = atoi(ptr);
    ptr = strtok(NULL, " ");
    if (ptr == NULL) {
      log_println(0, "S2C: Improper message");
      return 4;
    }
    ssndqueue = atoi(ptr);
    ptr = strtok(NULL, " ");
    if (ptr == NULL) {
      log_println(0, "S2C: Improper message");
      return 4;
    }
    sbytes = atoi(ptr);
    
    if (spdin < 1000)
      printf("%0.2f kb/s\n", spdin);
    else
      printf("%0.2f Mb/s\n", spdin/1000);

    I2AddrFree(sec_addr);

    sprintf(buff, "%0.0f", spdin);
    send_msg(ctlSocket, TEST_MSG, buff, strlen(buff));
    
    /* get web100 variables from server */
    tmpstr[0] = '\0';
    for (;;) {
      msgLen = sizeof(buff);
      if (recv_msg(ctlSocket, &msgType, buff, &msgLen)) {
        log_println(0, "Protocol error - missed text/finalize message!");
        return 1;
      }
      if (msgType == TEST_FINALIZE) {
        break;
      }
      if (check_msg_type("S2C throughput test", TEST_MSG, msgType, buff, msgLen)) {
        return 2;
      }
      strncat(tmpstr, buff, msgLen);
      log_println(6, "tmpstr = '%s'", tmpstr);
    }
    log_println(1, " <------------------------->");
  }


  return 0;
}
示例#6
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;
}
示例#7
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;
}
示例#8
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;
}