*****************************************************************

       Listing 1.

nettest_bsd.c:


 /* this routine implements the sending (netperf) side of the TCP_RR */
 /* test. */

void
send_tcp_rr(remote_host)
     char       remote_host[];
{

. . .

    /* Set-up the test end conditions. For a request/response test, they */
    /* can be either time or transaction based. */

    if (test_time) {
      /* The user wanted to end the test after a period of time. */
      times_up = 0;
      trans_remaining = 0;
      start_timer(test_time);
    }
    else {
      /* The tester wanted to send a number of bytes. */
      trans_remaining = test_bytes;
      times_up = 1;
    }

    /* The cpu_start routine will grab the current time and possibly */
    /* value of the idle counter for later use in measuring cpu */
    /* utilization and/or service demand and thruput. */

    cpu_start(local_cpu_usage);

. . .


    /* We use an "OR" to control test execution. When the test is */
    /* controlled by time, the byte count check will always return false. */
    /* When the test is controlled by byte count, the time test will */
    /* always return false. When the test is finished, the whole */
    /* expression will go false and we will stop sending data. */

    while ((!times_up) || (trans_remaining > 0)) {

      /* send the request. we assume that if we use a blocking socket, */
      /* the request will be sent at one shot. */
      if((len=send(send_socket,
                   send_ring->buffer_ptr,
                   req_size,
                   0)) != req_size) {
        if ((errno == EINTR) || (errno == 0)) {
          /* we hit the end of a */
          /* timed test. */
          timed_out = 1;
          break;
        }
        perror("send_tcp_rr: data send error");
        exit(1);
      }
      send_ring = send_ring->next;

      /* receive the response */
      rsp_bytes_left = rsp_size;
      temp_message_ptr  = recv_ring->buffer_ptr;
      while(rsp_bytes_left > 0) {
        if((rsp_bytes_recvd=recv(send_socket,
                                 temp_message_ptr,
                                 rsp_bytes_left,
                                 0)) < 0) {
          if (errno == EINTR) {
            /* We hit the end of a timed test. */
            timed_out = 1;
            break;
          }
          perror("send_tcp_rr: data recv error");
          exit(1);
        }
        rsp_bytes_left -= rsp_bytes_recvd;
        temp_message_ptr  += rsp_bytes_recvd;
      }
      recv_ring = recv_ring->next;

      if (timed_out) {
        /* we may have been in a nested while loop - we need */
        /* another call to break. */
        break;
      }

      nummessages++;
      if (trans_remaining) {
        trans_remaining--;
      }

. . .

    }

    /* this call will always give us the elapsed time for the test, and */
    /* will also store-away the necessaries for cpu utilization */

    cpu_stop(local_cpu_usage,&elapsed_time);

. . .

    /* We now calculate what our throughput was for the test. */
    thruput     = nummessages/elapsed_time;

. . .

}


*****************************************************************

       Listing 2


nettest_bsd.c:

/* This routine implements the TCP unidirectional data transfer test */
/* (a.k.a. stream) for the sockets interface. It receives its */
/* parameters via global variables from the shell and writes its */
/* output to the standard output. */


void
send_tcp_stream(remote_host)
char    remote_host[];
{

. . .

    /* Tell the remote end to do a listen.... */
    /* This call also sends a parameter message to Receiver (remote)
     * side.   -- yun
     */
    send_request();

. . .

    /* receive message from Receiver (remote); contains data such as
     * port number but can be seen as a "ready" status.  -- yun
     */
    recv_response();

. . .

    /*Connect up to the remote port on the data socket  */
    if (connect(send_socket,
                (struct sockaddr *)&server,
                sizeof(server)) <0){
      perror("netperf: send_tcp_stream: data socket connect failed");
      printf(" port: %d\n",ntohs(server.sin_port));
      exit(1);
    }

. . .

    /* Set-up the test end conditions. For a stream test, they can be */
    /* either time or byte-count based. */

    if (test_time) {
      /* The user wanted to end the test after a period of time. */
      times_up = 0;
      bytes_remaining = 0;
      start_timer(test_time);
    }
    else {
      /* The tester wanted to send a number of bytes. */
      bytes_remaining = test_bytes;
      times_up = 1;
    }

    /* The cpu_start routine will grab the current time and possibly */
    /* value of the idle counter for later use in measuring cpu */
    /* utilization and/or service demand and thruput. */

    cpu_start(local_cpu_usage);

. . .

    /* We use an "OR" to control test execution. When the test is */
    /* controlled by time, the byte count check will always return false. */
    /* When the test is controlled by byte count, the time test will */
    /* always return false. When the test is finished, the whole */
    /* expression will go false and we will stop sending data. */

    while ((!times_up) || (bytes_remaining > 0)) {

      if((len=send(send_socket,
                   send_ring->buffer_ptr,
                   send_size,
                   0)) != send_size) {
          /* the test was interrupted, must be the end of test */
          break;
        }
        perror("netperf: data send error");
        printf("len was %d\n",len);
        exit(1);
      }

      /* now we want to move our pointer to the next position in the */
      /* data buffer...we may also want to wrap back to the "beginning" */
      /* of the bufferspace, so we will mod the number of messages sent */
      /* by the send width, and use that to calculate the offset to add */
      /* to the base pointer. */
      nummessages++;
      send_ring = send_ring->next;
      if (bytes_remaining) {
        bytes_remaining -= send_size;
      }
    }

    /* The test is over. Flush the buffers to the remote end. We do a */
    /* graceful release to insure that all data has been taken by the */
    /* remote. */

. . .

    if (shutdown(send_socket,1) == -1) {
      perror("netperf: cannot shutdown tcp stream socket");
      exit(1);
    }

    /* hang a recv() off the socket to block until the remote has */
    /* brought all the data up into the application. it will do a */
    /* shutdown to cause a FIN to be sent our way. We will assume that */
    /* any exit from the recv() call is good... raj 4/93 */

    recv(send_socket, send_ring->buffer_ptr, send_size, 0);

    /* this call will always give us the elapsed time for the test, and */
    /* will also store-away the necessaries for cpu utilization */

    cpu_stop(local_cpu_usage,&elapsed_time);

    /* we are finished with the socket, so close it to prevent hitting */
    /* the limit on maximum open files. */

    close(send_socket);

    /* Get the statistics from the remote end. The remote will have */
    /* calculated service demand and all those interesting things. If it */
    /* wasn't supposed to care, it will return obvious values. */

    recv_response();
    if (!netperf_response.content.serv_errno) {
      if (debug)
        fprintf(where,"remote results obtained\n");
    }
    else {
      errno = netperf_response.content.serv_errno;
      fprintf(where,
              "netperf: remote error %d",
              netperf_response.content.serv_errno);
      perror("");
      fflush(where);

      exit(1);
    }

    /* We now calculate what our thruput was for the test. In the future, */
    /* we may want to include a calculation of the thruput measured by */
    /* the remote, but it should be the case that for a TCP stream test, */
    /* that the two numbers should be *very* close... We calculate */
    /* bytes_sent regardless of the way the test length was controlled. */
    /* If it was time, we needed to, and if it was by bytes, the user may */
    /* have specified a number of bytes that wasn't a multiple of the */
    /* send_size, so we really didn't send what he asked for ;-) */

    bytes_sent  = ntohd(tcp_stream_result->bytes_received);

    thruput     = (double) calc_thruput(bytes_sent);

. . .

}

*****************************************************************

       Listing 3


nettest_bsd.c:

/* This is the server-side routine for the tcp stream test. It is */
/* implemented as one routine. I could break things-out somewhat, but */
/* didn't feel it was necessary. */

void
recv_tcp_stream()
{

. . .

  /* The parameter message from the Sender side had already been received
   * by the parent of recv_tcp_stream().  -- yun
   */

. . .

  /* Now, let's set-up the socket to listen for connections */
  if (listen(s_listen, 5) == -1) {
    netperf_response.content.serv_errno = errno;
    close(s_listen);
    send_response();

    exit(1);
  }

. . .

  /* send data such as port number to Sender; can also be seen as
   * Receiver's "ready" status  -- yun
   */
  send_response();

. . .

  if ((s_data=accept(s_listen,
                     (struct sockaddr *)&peeraddr_in,
                     &addrlen)) == -1) {
    /* Let's just punt. The remote will be given some information */
    close(s_listen);
    exit(1);
  }

. . .

  cpu_start(tcp_stream_request->measure_cpu);

. . .

  /* The loop will exit when the sender does a shutdown, which will */
  /* return a length of zero   */

  while ((len = recv(s_data, recv_ring->buffer_ptr, recv_size, 0)) != 0) {
    if (len < 0) {
      netperf_response.content.serv_errno = errno;

      netperf_response.content.serv_errno = errno;
      send_response();
      exit(1);
    }
    bytes_received += len;
    receive_calls++;

    /* more to the next buffer in the recv_ring */
    recv_ring = recv_ring->next;
  }

  /* perform a shutdown to signal the sender that */
  /* we have received all the data sent. raj 4/93 */

  if (shutdown(s_data,1) == -1) {
      netperf_response.content.serv_errno = errno;
      send_response();
      exit(1);
    }

  cpu_stop(tcp_stream_request->measure_cpu,&elapsed_time);

. . .

}

*****************************************************************

       Listing 4


nettest_bsd.c:

void
send_udp_stream(remote_host)
char    remote_host[];
{
  /**********************************************************************/
  /*                                                                    */
  /*                    UDP Unidirectional Send Test                    */
  /*                                                                    */
  /**********************************************************************/

. . .


    /* Send parameters to Receiver (remote) side. */
    send_request();

    /* Receive message from Receiver (remote); contains data such as
     * port number but can be seen as a "ready" status.  -- yun
     */
    recv_response();

. . .

    /* We "connect" up to the remote post to allow is to use the send */
    /* call instead of the sendto call.... */

    if (connect(data_socket,
                (struct sockaddr *)&server,
                sizeof(server)) <0){
      perror("send_udp_stream: data socket connect failed");
      exit(1);
    }

    /* set up the timer to call us after test_time. one of these days, */
    /* it might be nice to figure-out a nice reliable way to have the */
    /* test controlled by a byte count as well, but since UDP is not */
    /* reliable, that could prove difficult. so, in the meantime, we */
    /* only allow a UDP_STREAM test to be a timed test. */

    if (test_time) {
      times_up = 0;
      start_timer(test_time);
    }
    else {
      fprintf(where,"Sorry, UDP_STREAM tests must be timed.\n");
      fflush(where);
    }

    /* Get the start count for the idle counter and the start time */

    cpu_start(local_cpu_usage);

    /* Send datagrams like there was no tomorrow.... */
    while (!times_up) {

      if ((len=send(data_socket,
                    send_ring->buffer_ptr,
                    send_size,
                    0))  != send_size) {
      if ((len >= 0) ||
          (errno == EINTR))
        if (errno == ENOBUFS) {
          failed_sends++;
          continue;
        }
        perror("udp_send: data send error");
        exit(1);
      }
      messages_sent++;

      /* now we want to move our pointer to the next position in the */
      /* data buffer... */

      send_ring = send_ring->next;

    }

    /* This is a timed test, so the remote will be returning to us after */
    /* a time. We should not need to send any "strange" messages to tell */
    /* the remote that the test is completed, unless we decide to add a */
    /* number of messages to the test. */

    /* the test is over, so get stats and stuff */
    cpu_stop(local_cpu_usage,
             &elapsed_time);

    /* Get the statistics from the remote end   */
    recv_response();

. . .

    /* we asume that the remote ran for as long as we did */

    remote_thruput = (double) calc_thruput(bytes_recvd);

. . .

}

*****************************************************************

       Listing 5


nettest_bsd.c:

 /* this routine implements the receive side (netserver) of the */
 /* UDP_STREAM performance test. */

void
recv_udp_stream()
{

. . .

  /* The parameter message from the Sender side had already been received
   * by the parent of recv_udp_stream().  -- yun
   */

. . .

  /* send data such as port number to Sender; can also be seen as
   * Receiver's "ready" status  -- yun
   */
  send_response();

  /* Now it's time to start receiving data on the connection. We will */
  /* first grab the apropriate counters and then start grabbing. */

  cpu_start(udp_stream_request->measure_cpu);

  /* The loop will exit when the timer pops, or if we happen to recv a */
  /* message of less than send_size bytes... */

  times_up = 0;
  start_timer(test_time + PAD_TIME);

. . .

  while (!times_up) {

    if ((len = recv(s_data,
                    recv_ring->buffer_ptr,
                    message_size,
                    0)) != message_size) {
      if ((len == -1) && (errno != EINTR)) {
        netperf_response.content.serv_errno = errno;
        send_response();
        exit(1);
      }
      break;
    }
    messages_recvd++;
    recv_ring = recv_ring->next;
  }

. . .

  /* The loop now exits due timer or < send_size bytes received. in */
  /* reality, we only really support a timed UDP_STREAM test. raj */
  /* 12/95 */

  cpu_stop(udp_stream_request->measure_cpu,&elapsed_time);

  if (times_up) {
    /* we ended on a timer, subtract the PAD_TIME */
    elapsed_time -= (float)PAD_TIME;
  }
  else {
    stop_timer();
  }

. . .

  /* send the results to the sender */
. . .
  send_response();

. . .

}
