aboutsummaryrefslogtreecommitdiff
path: root/nettest_sctp.c
diff options
context:
space:
mode:
Diffstat (limited to 'nettest_sctp.c')
-rw-r--r--nettest_sctp.c4869
1 files changed, 0 insertions, 4869 deletions
diff --git a/nettest_sctp.c b/nettest_sctp.c
deleted file mode 100644
index 7cfcd9f..0000000
--- a/nettest_sctp.c
+++ /dev/null
@@ -1,4869 +0,0 @@
-#ifndef lint
-char nettest_sctp[]="\
-@(#)nettest_sctp.c (c) Copyright 2005-2007 Hewlett-Packard Co. Version 2.4.3";
-#else
-#define DIRTY
-#define WANT_HISTOGRAM
-#define WANT_INTERVALS
-#endif /* lint */
-
-/****************************************************************/
-/* */
-/* nettest_sctp.c */
-/* */
-/* */
-/* scan_sctp_args() get the sctp command line args */
-/* */
-/* the actual test routines... */
-/* */
-/* send_sctp_stream() perform a sctp stream test */
-/* recv_sctp_stream() */
-/* send_sctp_rr() perform a sctp request/response */
-/* recv_sctp_rr() */
-/* send_sctp_stream_udp() perform a sctp request/response */
-/* recv_sctp_stream_upd() using UDP style API */
-/* send_sctp_rr_udp() perform a sctp request/response */
-/* recv_sctp_rr_upd() using UDP style API */
-/* */
-/* relies on create_data_socket in nettest_bsd.c */
-/****************************************************************/
-
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#if defined(WANT_SCTP)
-
-#include <sys/types.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#ifdef NOSTDLIBH
-#include <malloc.h>
-#else /* NOSTDLIBH */
-#include <stdlib.h>
-#endif /* NOSTDLIBH */
-
-#if !defined(__VMS)
-#include <sys/ipc.h>
-#endif /* !defined(__VMS) */
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <netinet/sctp.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
-/* would seem that not all sctp.h files define a MSG_EOF, but that
- MSG_EOF can be the same as MSG_FIN so lets work with that
- assumption. initial find by Jon Pedersen. raj 2006-02-01 */
-#ifndef MSG_EOF
-#ifdef MSG_FIN
-#define MSG_EOF MSG_FIN
-#else
-#error Must have either MSG_EOF or MSG_FIN defined
-#endif
-#endif
-
-#include "netlib.h"
-#include "netsh.h"
-/* get some of the functions from nettest_bsd.c */
-#include "nettest_bsd.h"
-#include "nettest_sctp.h"
-
-#ifdef WANT_HISTOGRAM
-#ifdef __sgi
-#include <sys/time.h>
-#endif /* __sgi */
-#include "hist.h"
-#endif /* WANT_HISTOGRAM */
-
-#ifdef WANT_FIRST_BURST
-extern int first_burst_size;
-#endif /* WANT_FIRST_BURST */
-
-
-
-/* these variables are specific to SCTP tests. declare */
-/* them static to make them global only to this file. */
-
-static int
- msg_count = 0, /* number of messages to transmit on association */
- non_block = 0, /* default to blocking sockets */
- num_associations = 1; /* number of associations on the endpoint */
-
-static int confidence_iteration;
-static char local_cpu_method;
-static char remote_cpu_method;
-
-#ifdef WANT_HISTOGRAM
-static struct timeval time_one;
-static struct timeval time_two;
-static HIST time_hist;
-#endif /* WANT_HISTOGRAM */
-
-
-char sctp_usage[] = "\n\
-Usage: netperf [global options] -- [test options] \n\
-\n\
-SCTP Sockets Test Options:\n\
- -b number Send number requests at the start of _RR tests\n\
- -D [L][,R] Set SCTP_NODELAY locally and/or remotely\n\
- -h Display this text\n\
- -H name,fam Use name (or IP) and family as target of data connection\n\
- -L name,fam Use name (or IP) and family as source of data connextion\n\
- -m bytes Set the size of each sent message\n\
- -M bytes Set the size of each received messages\n\
- -P local[,remote] Set the local/remote port for the data socket\n\
- -r req,[rsp] Set request/response sizes (_RR tests)\n\
- -s send[,recv] Set local socket send/recv buffer sizes\n\
- -S send[,recv] Set remote socket send/recv buffer sizes\n\
- -V Enable copy avoidance if supported\n\
- -N number Specifies the number of messages to send (_STREAM tests)\n\
- -B run the test in non-blocking mode\n\
- -T number Number of associations to create (_MANY tests)\n\
- -4 Use AF_INET (eg IPv4) on both ends of the data conn\n\
- -6 Use AF_INET6 (eg IPv6) on both ends of the data conn\n\
-\n\
-For those options taking two parms, at least one must be specified;\n\
-specifying one value without a comma will set both parms to that\n\
-value, specifying a value with a leading comma will set just the second\n\
-parm, a value with a trailing comma will set just the first. To set\n\
-each parm to unique values, specify both and separate them with a\n\
-comma.\n";
-
-
- /* This routine is intended to retrieve interesting aspects of tcp */
- /* for the data connection. at first, it attempts to retrieve the */
- /* maximum segment size. later, it might be modified to retrieve */
- /* other information, but it must be information that can be */
- /* retrieved quickly as it is called during the timing of the test. */
- /* for that reason, a second routine may be created that can be */
- /* called outside of the timing loop */
-static
-void
-get_sctp_info(socket, mss)
- int socket;
- int *mss;
-{
-
- int sock_opt_len;
-
- if (sctp_opt_info(socket,
- 0,
- SCTP_MAXSEG,
- mss,
- &sock_opt_len) < 0) {
- lss_size = -1;
- }
-}
-
-
-static
-void
-sctp_enable_events(socket, ev_mask)
- int socket;
- int ev_mask;
-{
- struct sctp_event_subscribe ev;
-
- bzero(&ev, sizeof(ev));
-
- if (ev_mask & SCTP_SNDRCV_INFO_EV)
- ev.sctp_data_io_event = 1;
-
- if (ev_mask & SCTP_ASSOC_CHANGE_EV)
- ev.sctp_association_event = 1;
-
- if (ev_mask & SCTP_PEERADDR_CHANGE_EV)
- ev.sctp_address_event = 1;
-
- if (ev_mask & SCTP_SND_FAILED_EV)
- ev.sctp_send_failure_event = 1;
-
- if (ev_mask & SCTP_REMOTE_ERROR_EV)
- ev.sctp_peer_error_event = 1;
-
- if (ev_mask & SCTP_SHUTDOWN_EV)
- ev.sctp_shutdown_event = 1;
-
- if (ev_mask & SCTP_PD_EV)
- ev.sctp_partial_delivery_event = 1;
-
- if (ev_mask & SCTP_ADAPT_EV)
-#ifdef HAVE_SCTP_ADAPTATION_LAYER_EVENT
- ev.sctp_adaptation_layer_event = 1;
-#else
- ev.sctp_adaption_layer_event = 1;
-#endif
-
- if (setsockopt(socket,
- IPPROTO_SCTP,
-#ifdef SCTP_EVENTS
- SCTP_EVENTS,
-#else
- SCTP_SET_EVENTS,
-#endif
- (const char*)&ev,
- sizeof(ev)) != 0 ) {
- fprintf(where,
- "sctp_enable_event: could not set sctp events errno %d\n",
- errno);
- fflush(where);
- exit(1);
- }
-}
-
-
-static
-sctp_disposition_t
-sctp_process_event(socket, buf)
- int socket;
- void *buf;
-{
-
- struct sctp_assoc_change *sac;
- struct sctp_send_failed *ssf;
- struct sctp_paddr_change *spc;
- struct sctp_remote_error *sre;
- union sctp_notification *snp;
-
- snp = buf;
-
- switch (snp->sn_header.sn_type) {
- case SCTP_ASSOC_CHANGE:
- if (debug) {
- fprintf(where, "\tSCTP_ASSOC_CHANGE event, type:");
- fflush(where);
- }
- sac = &snp->sn_assoc_change;
- switch (sac->sac_type) {
- case SCTP_COMM_UP:
- if (debug) {
- fprintf(where, " SCTP_COMM_UP\n");
- fflush(where);
- }
- break;
- case SCTP_RESTART:
- if (debug) {
- fprintf(where, " SCTP_RESTART\n");
- fflush(where);
- }
- break;
- case SCTP_CANT_STR_ASSOC:
- if (debug) {
- fprintf(where, " SCTP_CANT_STR_ASSOC\n");
- fflush(where);
- }
- break; /* FIXME ignore above status changes */
- case SCTP_COMM_LOST:
- if (debug) {
- fprintf(where, " SCTP_COMM_LOST\n");
- fflush(where);
- }
- return SCTP_CLOSE;
- case SCTP_SHUTDOWN_COMP:
- if (debug) {
- fprintf(where, " SCTP_SHUTDOWN_COMPLETE\n");
- fflush(where);
- }
- return SCTP_CLOSE;
- break;
- }
-
- case SCTP_SEND_FAILED:
- if (debug) {
- fprintf(where, "\tSCTP_SEND_FAILED event\n");
- fflush(where);
- }
- ssf = &snp->sn_send_failed;
- break; /* FIXME ??? ignore this for now */
-
- case SCTP_PEER_ADDR_CHANGE:
- if (debug) {
- fprintf(where, "\tSCTP_PEER_ADDR_CHANGE event\n");
- fflush(where);
- }
- spc = &snp->sn_paddr_change;
- break; /* FIXME ??? ignore this for now */
-
- case SCTP_REMOTE_ERROR:
- if (debug) {
- fprintf(where, "\tSCTP_REMOTE_ERROR event\n");
- fflush(where);
- }
- sre = &snp->sn_remote_error;
- break; /* FIXME ??? ignore this for now */
- case SCTP_SHUTDOWN_EVENT:
- if (debug) {
- fprintf(where, "\tSCTP_SHUTDOWN event\n");
- fflush(where);
- }
- return SCTP_CLOSE;
- default:
- fprintf(where, "unknown type: %hu\n", snp->sn_header.sn_type);
- fflush(where);
- break;
- }
- return SCTP_OK;
-}
-
-
-
-/* This routine implements the SCTP 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_sctp_stream(remote_host)
-char remote_host[];
-{
-
- char *tput_title = "\
-Recv Send Send \n\
-Socket Socket Message Elapsed \n\
-Size Size Size Time Throughput \n\
-bytes bytes bytes secs. %s/sec \n\n";
-
- char *tput_fmt_0 =
- "%7.2f\n";
-
- char *tput_fmt_1 =
- "%6d %6d %6d %-6.2f %7.2f \n";
-
- char *cpu_title = "\
-Recv Send Send Utilization Service Demand\n\
-Socket Socket Message Elapsed Send Recv Send Recv\n\
-Size Size Size Time Throughput local remote local remote\n\
-bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n";
-
- char *cpu_fmt_0 =
- "%6.3f %c\n";
-
- char *cpu_fmt_1 =
- "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
-
- char *ksink_fmt = "\n\
-Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\
-Local Remote Local Remote Xfered Per Per\n\
-Send Recv Send Recv Send (avg) Recv (avg)\n\
-%5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n";
-
- char *ksink_fmt2 = "\n\
-Maximum\n\
-Segment\n\
-Size (bytes)\n\
-%6d\n";
-
-
- float elapsed_time;
-
-#ifdef WANT_INTERVALS
- int interval_count;
- sigset_t signal_set;
-#endif
-
- /* what we want is to have a buffer space that is at least one */
- /* send-size greater than our send window. this will insure that we */
- /* are never trying to re-use a buffer that may still be in the hands */
- /* of the transport. This buffer will be malloc'd after we have found */
- /* the size of the local senc socket buffer. We will want to deal */
- /* with alignment and offset concerns as well. */
-
-#ifdef DIRTY
- int *message_int_ptr;
-#endif
-
- struct ring_elt *send_ring;
-
- int len;
- unsigned int nummessages = 0;
- int send_socket;
- int bytes_remaining;
- int sctp_mss;
- int timed_out;
-
- /* with links like fddi, one can send > 32 bits worth of bytes */
- /* during a test... ;-) at some point, this should probably become a */
- /* 64bit integral type, but those are not entirely common yet */
- double bytes_sent = 0.0;
-
-#ifdef DIRTY
- int i;
-#endif /* DIRTY */
-
- float local_cpu_utilization;
- float local_service_demand;
- float remote_cpu_utilization;
- float remote_service_demand;
-
- double thruput;
-
- struct addrinfo *remote_res;
- struct addrinfo *local_res;
- struct addrinfo *local_remote_res;
- struct addrinfo *local_local_res;
-
- struct sctp_stream_request_struct *sctp_stream_request;
- struct sctp_stream_response_struct *sctp_stream_response;
- struct sctp_stream_results_struct *sctp_stream_result;
-
- sctp_stream_request =
- (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data;
- sctp_stream_response =
- (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data;
- sctp_stream_result =
- (struct sctp_stream_results_struct *)netperf_response.content.test_specific_data;
-
-#ifdef WANT_HISTOGRAM
- time_hist = HIST_new();
-#endif /* WANT_HISTOGRAM */
- /* since we are now disconnected from the code that established the */
- /* control socket, and since we want to be able to use different */
- /* protocols and such, we are passed the name of the remote host and */
- /* must turn that into the test specific addressing information. */
-
- /* complete_addrinfos will either succede or exit the process */
- complete_addrinfos(&remote_res,
- &local_res,
- remote_host,
- SOCK_STREAM,
- IPPROTO_SCTP,
- 0);
-
- if ( print_headers ) {
- print_top_test_header("SCTP STREAM TEST", local_res, remote_res);
- }
-
- send_ring = NULL;
- confidence_iteration = 1;
- init_stat();
-
- /* we have a great-big while loop which controls the number of times */
- /* we run a particular test. this is for the calculation of a */
- /* confidence interval (I really should have stayed awake during */
- /* probstats :). If the user did not request confidence measurement */
- /* (no confidence is the default) then we will only go though the */
- /* loop once. the confidence stuff originates from the folks at IBM */
-
- while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
- (confidence_iteration <= iteration_min)) {
-
- /* initialize a few counters. we have to remember that we might be */
- /* going through the loop more than once. */
-
- nummessages = 0;
- bytes_sent = 0.0;
- times_up = 0;
- timed_out = 0;
-
- /*set up the data socket */
- send_socket = create_data_socket(local_res);
-
- if (send_socket == INVALID_SOCKET){
- perror("netperf: send_sctp_stream: sctp stream data socket");
- exit(1);
- }
-
- if (debug) {
- fprintf(where,"send_sctp_stream: send_socket obtained...\n");
- }
-
- /* at this point, we have either retrieved the socket buffer sizes, */
- /* or have tried to set them, so now, we may want to set the send */
- /* size based on that (because the user either did not use a -m */
- /* option, or used one with an argument of 0). If the socket buffer */
- /* size is not available, we will set the send size to 4KB - no */
- /* particular reason, just arbitrary... */
- if (send_size == 0) {
- if (lss_size > 0) {
- send_size = lss_size;
- }
- else {
- send_size = 4096;
- }
- }
-
- /* set-up the data buffer ring with the requested alignment and offset. */
- /* note also that we have allocated a quantity */
- /* of memory that is at least one send-size greater than our socket */
- /* buffer size. We want to be sure that there are at least two */
- /* buffers allocated - this can be a bit of a problem when the */
- /* send_size is bigger than the socket size, so we must check... the */
- /* user may have wanted to explicitly set the "width" of our send */
- /* buffers, we should respect that wish... */
- if (send_width == 0) {
- send_width = (lss_size/send_size) + 1;
- if (send_width == 1) send_width++;
- }
-
- if (send_ring == NULL) {
- /* only allocate the send ring once. this is a networking test, */
- /* not a memory allocation test. this way, we do not need a */
- /* deallocate_buffer_ring() routine, and I don't feel like */
- /* writing one anyway :) raj 11/94 */
- send_ring = allocate_buffer_ring(send_width,
- send_size,
- local_send_align,
- local_send_offset);
- }
-
- /* If the user has requested cpu utilization measurements, we must */
- /* calibrate the cpu(s). We will perform this task within the tests */
- /* themselves. If the user has specified the cpu rate, then */
- /* calibrate_local_cpu will return rather quickly as it will have */
- /* nothing to do. If local_cpu_rate is zero, then we will go through */
- /* all the "normal" calibration stuff and return the rate back. */
-
- if (local_cpu_usage) {
- local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
- }
-
- /* Tell the remote end to do a listen. The server alters the socket */
- /* paramters on the other side at this point, hence the reason for */
- /* all the values being passed in the setup message. If the user did */
- /* not specify any of the parameters, they will be passed as 0, which */
- /* will indicate to the remote that no changes beyond the system's */
- /* default should be used. Alignment is the exception, it will */
- /* default to 1, which will be no alignment alterations. */
-
- netperf_request.content.request_type = DO_SCTP_STREAM;
- sctp_stream_request->send_buf_size = rss_size_req;
- sctp_stream_request->recv_buf_size = rsr_size_req;
- sctp_stream_request->receive_size = recv_size;
- sctp_stream_request->no_delay = rem_nodelay;
- sctp_stream_request->recv_alignment = remote_recv_align;
- sctp_stream_request->recv_offset = remote_recv_offset;
- sctp_stream_request->measure_cpu = remote_cpu_usage;
- sctp_stream_request->cpu_rate = remote_cpu_rate;
- if (test_time) {
- sctp_stream_request->test_length = test_time;
- }
- else {
- if (msg_count)
- test_bytes = send_size * msg_count;
-
- sctp_stream_request->test_length = test_bytes;
- }
- sctp_stream_request->so_rcvavoid = rem_rcvavoid;
- sctp_stream_request->so_sndavoid = rem_sndavoid;
-#ifdef DIRTY
- sctp_stream_request->dirty_count = rem_dirty_count;
- sctp_stream_request->clean_count = rem_clean_count;
-#endif /* DIRTY */
- sctp_stream_request->port = htonl(atoi(remote_data_port));
- sctp_stream_request->ipfamily = af_to_nf(remote_res->ai_family);
- sctp_stream_request->non_blocking = non_block;
-
-
- if (debug > 1) {
- fprintf(where,
- "netperf: send_sctp_stream: requesting sctp stream test\n");
- }
-
- send_request();
-
- /* The response from the remote will contain all of the relevant */
- /* socket parameters for this test type. We will put them back into */
- /* the variables here so they can be displayed if desired. The */
- /* remote will have calibrated CPU if necessary, and will have done */
- /* all the needed set-up we will have calibrated the cpu locally */
- /* before sending the request, and will grab the counter value right*/
- /* after the connect returns. The remote will grab the counter right*/
- /* after the accept call. This saves the hassle of extra messages */
- /* being sent for the sctp tests. */
-
- recv_response();
-
- if (!netperf_response.content.serv_errno) {
- if (debug)
- fprintf(where,"remote listen done.\n");
- rsr_size = sctp_stream_response->recv_buf_size;
- rss_size = sctp_stream_response->send_buf_size;
- rem_nodelay = sctp_stream_response->no_delay;
- remote_cpu_usage= sctp_stream_response->measure_cpu;
- remote_cpu_rate = sctp_stream_response->cpu_rate;
-
- /* we have to make sure that the server port number is in */
- /* network order */
- set_port_number(remote_res, (short)sctp_stream_response->data_port_number);
-
- rem_rcvavoid = sctp_stream_response->so_rcvavoid;
- rem_sndavoid = sctp_stream_response->so_sndavoid;
- }
- else {
- Set_errno(netperf_response.content.serv_errno);
- fprintf(where,
- "netperf: remote error %d",
- netperf_response.content.serv_errno);
- perror("");
- fflush(where);
-
- exit(1);
- }
-
- /*Connect up to the remote port on the data socket */
- if (connect(send_socket,
- remote_res->ai_addr,
- remote_res->ai_addrlen) == INVALID_SOCKET) {
- perror("netperf: send_sctp_stream: data socket connect failed");
- exit(1);
- }
-
- sctp_enable_events(send_socket, SCTP_ASSOC_CHANGE_EV);
-
- if (non_block) {
- /* now that we are connected, mark the socket as non-blocking */
- if (!set_nonblock(send_socket)) {
- perror("netperf: fcntl");
- exit(1);
- }
- }
-
- /* Data Socket set-up is finished. If there were problems, either */
- /* the connect would have failed, or the previous response would */
- /* have indicated a problem. I failed to see the value of the */
- /* extra message after the accept on the remote. If it failed, */
- /* we'll see it here. If it didn't, we might as well start pumping */
- /* data. */
-
- /* 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;
- /* in previous revisions, we had the same code repeated throught */
- /* all the test suites. this was unnecessary, and meant more */
- /* work for me when I wanted to switch to POSIX signals, so I */
- /* have abstracted this out into a routine in netlib.c. if you */
- /* are experiencing signal problems, you might want to look */
- /* there. raj 11/94 */
- 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);
-
-#ifdef WANT_INTERVALS
- if ((interval_burst) || (demo_mode)) {
- /* zero means that we never pause, so we never should need the */
- /* interval timer, unless we are in demo_mode */
- start_itimer(interval_wate);
- }
- interval_count = interval_burst;
- /* get the signal set for the call to sigsuspend */
- if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
- fprintf(where,
- "send_sctp_stream: unable to get sigmask errno %d\n",
- errno);
- fflush(where);
- exit(1);
- }
-#endif /* WANT_INTERVALS */
-
-#ifdef DIRTY
- /* initialize the random number generator for putting dirty stuff */
- /* into the send buffer. raj */
- srand((int) getpid());
-#endif
-
- /* before we start, initialize a few variables */
-
- /* 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)) {
-
-#ifdef DIRTY
- /* we want to dirty some number of consecutive integers in the buffer */
- /* we are about to send. we may also want to bring some number of */
- /* them cleanly into the cache. The clean ones will follow any dirty */
- /* ones into the cache. at some point, we might want to replace */
- /* the rand() call with something from a table to reduce our call */
- /* overhead during the test, but it is not a high priority item. */
- message_int_ptr = (int *)(send_ring->buffer_ptr);
- for (i = 0; i < loc_dirty_count; i++) {
- *message_int_ptr = rand();
- message_int_ptr++;
- }
- for (i = 0; i < loc_clean_count; i++) {
- loc_dirty_count = *message_int_ptr;
- message_int_ptr++;
- }
-#endif /* DIRTY */
-
-#ifdef WANT_HISTOGRAM
- /* timestamp just before we go into send and then again just after */
- /* we come out raj 8/94 */
- HIST_timestamp(&time_one);
-#endif /* WANT_HISTOGRAM */
-
- while ((len=sctp_sendmsg(send_socket,
- send_ring->buffer_ptr, send_size,
- NULL, 0,
- 0, 0, 0, 0, 0)) != send_size) {
- if (non_block && errno == EAGAIN)
- continue;
- else if ((len >=0) || SOCKET_EINTR(len)) {
- /* the test was interrupted, must be the end of test */
- timed_out = 1;
- break;
- }
- perror("netperf: data send error");
- printf("len was %d\n",len);
- exit(1);
- }
-
- if (timed_out)
- break; /* we timed out durint sendmsg, done with test */
-
-#ifdef WANT_HISTOGRAM
- /* timestamp the exit from the send call and update the histogram */
- HIST_timestamp(&time_two);
- HIST_add(time_hist,delta_micro(&time_one,&time_two));
-#endif /* WANT_HISTOGRAM */
-
-#ifdef WANT_INTERVALS
- if (demo_mode) {
- units_this_tick += send_size;
- }
- /* in this case, the interval count is the count-down couter */
- /* to decide to sleep for a little bit */
- if ((interval_burst) && (--interval_count == 0)) {
- /* call sigsuspend and wait for the interval timer to get us */
- /* out */
- if (debug > 1) {
- fprintf(where,"about to suspend\n");
- fflush(where);
- }
- if (sigsuspend(&signal_set) == EFAULT) {
- fprintf(where,
- "send_sctp_stream: fault with sigsuspend.\n");
- fflush(where);
- exit(1);
- }
- interval_count = interval_burst;
- }
-#endif /* WANT_INTERVALS */
-
- /* 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. */
-
- /* but first, if the verbosity is greater than 1, find-out what */
- /* the sctp maximum segment_size was (if possible) */
- if (verbosity > 1) {
- sctp_mss = -1;
- get_sctp_info(send_socket, &sctp_mss);
- }
-
- shutdown(send_socket, SHUT_WR);
-
- /* The test server will signal to us when it wants to shutdown.
- * In blocking mode, we can call recvmsg. In non-blocking
- * mode, we need to select on the socket for reading.
- * We'll assume that all returns are succefull
- */
- if (non_block) {
- fd_set readfds;
-
- FD_ZERO(&readfds);
- FD_SET(send_socket, &readfds);
- select(send_socket+1, &readfds, NULL, NULL, NULL);
- } else {
- sctp_recvmsg(send_socket, send_ring->buffer_ptr, send_size, NULL,
- 0, NULL, 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); /* was cpu being */
- /* measured and how */
- /* long did we really */
- /* run? */
-
- /* 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 {
- Set_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 sctp 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(sctp_stream_result->bytes_received);
-
- thruput = (double) calc_thruput(bytes_sent);
-
- if (local_cpu_usage || remote_cpu_usage) {
- /* We must now do a little math for service demand and cpu */
- /* utilization for the system(s) */
- /* Of course, some of the information might be bogus because */
- /* there was no idle counter in the kernel(s). We need to make */
- /* a note of this for the user's benefit...*/
- if (local_cpu_usage) {
-
- local_cpu_utilization = calc_cpu_util(0.0);
- local_service_demand = calc_service_demand(bytes_sent,
- 0.0,
- 0.0,
- 0);
- }
- else {
- local_cpu_utilization = (float) -1.0;
- local_service_demand = (float) -1.0;
- }
-
- if (remote_cpu_usage) {
-
- remote_cpu_utilization = sctp_stream_result->cpu_util;
- remote_service_demand = calc_service_demand(bytes_sent,
- 0.0,
- remote_cpu_utilization,
- sctp_stream_result->num_cpus);
- }
- else {
- remote_cpu_utilization = (float) -1.0;
- remote_service_demand = (float) -1.0;
- }
- }
- else {
- /* we were not measuring cpu, for the confidence stuff, we */
- /* should make it -1.0 */
- local_cpu_utilization = (float) -1.0;
- local_service_demand = (float) -1.0;
- remote_cpu_utilization = (float) -1.0;
- remote_service_demand = (float) -1.0;
- }
-
- /* at this point, we want to calculate the confidence information. */
- /* if debugging is on, calculate_confidence will print-out the */
- /* parameters we pass it */
-
- calculate_confidence(confidence_iteration,
- elapsed_time,
- thruput,
- local_cpu_utilization,
- remote_cpu_utilization,
- local_service_demand,
- remote_service_demand);
-
-
- confidence_iteration++;
- }
-
- /* at this point, we have finished making all the runs that we */
- /* will be making. so, we should extract what the calcuated values */
- /* are for all the confidence stuff. we could make the values */
- /* global, but that seemed a little messy, and it did not seem worth */
- /* all the mucking with header files. so, we create a routine much */
- /* like calcualte_confidence, which just returns the mean values. */
- /* raj 11/94 */
-
- retrieve_confident_values(&elapsed_time,
- &thruput,
- &local_cpu_utilization,
- &remote_cpu_utilization,
- &local_service_demand,
- &remote_service_demand);
-
- /* We are now ready to print all the information. If the user */
- /* has specified zero-level verbosity, we will just print the */
- /* local service demand, or the remote service demand. If the */
- /* user has requested verbosity level 1, he will get the basic */
- /* "streamperf" numbers. If the user has specified a verbosity */
- /* of greater than 1, we will display a veritable plethora of */
- /* background information from outside of this block as it it */
- /* not cpu_measurement specific... */
-
- if (confidence < 0) {
- /* we did not hit confidence, but were we asked to look for it? */
- if (iteration_max > 1) {
- display_confidence();
- }
- }
-
- if (local_cpu_usage || remote_cpu_usage) {
- local_cpu_method = format_cpu_method(cpu_method);
- remote_cpu_method = format_cpu_method(sctp_stream_result->cpu_method);
-
- switch (verbosity) {
- case 0:
- if (local_cpu_usage) {
- fprintf(where,
- cpu_fmt_0,
- local_service_demand,
- local_cpu_method);
- }
- else {
- fprintf(where,
- cpu_fmt_0,
- remote_service_demand,
- remote_cpu_method);
- }
- break;
- case 1:
- case 2:
- if (print_headers) {
- fprintf(where,
- cpu_title,
- format_units(),
- local_cpu_method,
- remote_cpu_method);
- }
-
- fprintf(where,
- cpu_fmt_1, /* the format string */
- rsr_size, /* remote recvbuf size */
- lss_size, /* local sendbuf size */
- send_size, /* how large were the sends */
- elapsed_time, /* how long was the test */
- thruput, /* what was the xfer rate */
- local_cpu_utilization, /* local cpu */
- remote_cpu_utilization, /* remote cpu */
- local_service_demand, /* local service demand */
- remote_service_demand); /* remote service demand */
- break;
- }
- }
- else {
- /* The tester did not wish to measure service demand. */
-
- switch (verbosity) {
- case 0:
- fprintf(where,
- tput_fmt_0,
- thruput);
- break;
- case 1:
- case 2:
- if (print_headers) {
- fprintf(where,tput_title,format_units());
- }
- fprintf(where,
- tput_fmt_1, /* the format string */
- rsr_size, /* remote recvbuf size */
- lss_size, /* local sendbuf size */
- send_size, /* how large were the sends */
- elapsed_time, /* how long did it take */
- thruput);/* how fast did it go */
- break;
- }
- }
-
- /* it would be a good thing to include information about some of the */
- /* other parameters that may have been set for this test, but at the */
- /* moment, I do not wish to figure-out all the formatting, so I will */
- /* just put this comment here to help remind me that it is something */
- /* that should be done at a later time. */
-
- if (verbosity > 1) {
- /* The user wanted to know it all, so we will give it to him. */
- /* This information will include as much as we can find about */
- /* sctp statistics, the alignments of the sends and receives */
- /* and all that sort of rot... */
-
- /* this stuff needs to be worked-out in the presence of confidence */
- /* intervals and multiple iterations of the test... raj 11/94 */
-
- fprintf(where,
- ksink_fmt,
- "Bytes",
- "Bytes",
- "Bytes",
- local_send_align,
- remote_recv_align,
- local_send_offset,
- remote_recv_offset,
- bytes_sent,
- bytes_sent / (double)nummessages,
- nummessages,
- bytes_sent / (double)sctp_stream_result->recv_calls,
- sctp_stream_result->recv_calls);
- fprintf(where,
- ksink_fmt2,
- sctp_mss);
- fflush(where);
-#ifdef WANT_HISTOGRAM
- fprintf(where,"\n\nHistogram of time spent in send() call.\n");
- fflush(where);
- HIST_report(time_hist);
-#endif /* WANT_HISTOGRAM */
- }
-
-}
-
-
-
-
-/* This is the server-side routine for the sctp stream test. It is */
-/* implemented as one routine. I could break things-out somewhat, but */
-/* didn't feel it was necessary. */
-
-void
-recv_sctp_stream()
-{
-
- struct sockaddr_in myaddr_in; /* needed to get port number */
- struct sockaddr_storage peeraddr; /* used in accept */
- int s_listen,s_data;
- int addrlen;
- int len;
- unsigned int receive_calls;
- float elapsed_time;
- double bytes_received;
-
- struct ring_elt *recv_ring;
-
- struct addrinfo *local_res;
- char local_name[BUFSIZ];
- char port_buffer[PORTBUFSIZE];
- int msg_flags = 0;
-
-#ifdef DIRTY
- int *message_int_ptr;
- int dirty_count;
- int clean_count;
- int i;
-#endif
-
-#ifdef DO_SELECT
- fd_set readfds;
- struct timeval timeout;
-#endif /* DO_SELECT */
-
- struct sctp_stream_request_struct *sctp_stream_request;
- struct sctp_stream_response_struct *sctp_stream_response;
- struct sctp_stream_results_struct *sctp_stream_results;
-
-#ifdef DO_SELECT
- FD_ZERO(&readfds);
- timeout.tv_sec = 1;
- timeout.tv_usec = 0;
-#endif /* DO_SELECT */
-
- sctp_stream_request =
- (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data;
- sctp_stream_response =
- (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data;
- sctp_stream_results =
- (struct sctp_stream_results_struct *)netperf_response.content.test_specific_data;
-
- if (debug) {
- fprintf(where,"netserver: recv_sctp_stream: entered...\n");
- fflush(where);
- }
-
- /* We want to set-up the listen socket with all the desired */
- /* parameters and then let the initiator know that all is ready. If */
- /* socket size defaults are to be used, then the initiator will have */
- /* sent us 0's. If the socket sizes cannot be changed, then we will */
- /* send-back what they are. If that information cannot be determined, */
- /* then we send-back -1's for the sizes. If things go wrong for any */
- /* reason, we will drop back ten yards and punt. */
-
- /* If anything goes wrong, we want the remote to know about it. It */
- /* would be best if the error that the remote reports to the user is */
- /* the actual error we encountered, rather than some bogus unexpected */
- /* response type message. */
-
- if (debug) {
- fprintf(where,"recv_sctp_stream: setting the response type...\n");
- fflush(where);
- }
-
- netperf_response.content.response_type = SCTP_STREAM_RESPONSE;
-
- if (debug) {
- fprintf(where,"recv_sctp_stream: the response type is set...\n");
- fflush(where);
- }
-
- /* We now alter the message_ptr variable to be at the desired */
- /* alignment with the desired offset. */
-
- if (debug) {
- fprintf(where,"recv_sctp_stream: requested alignment of %d\n",
- sctp_stream_request->recv_alignment);
- fflush(where);
- }
-
- /* create_data_socket expects to find some things in the global */
- /* variables, so set the globals based on the values in the request. */
- /* once the socket has been created, we will set the response values */
- /* based on the updated value of those globals. raj 7/94 */
- lss_size_req = sctp_stream_request->send_buf_size;
- lsr_size_req = sctp_stream_request->recv_buf_size;
- loc_nodelay = sctp_stream_request->no_delay;
- loc_rcvavoid = sctp_stream_request->so_rcvavoid;
- loc_sndavoid = sctp_stream_request->so_sndavoid;
- non_block = sctp_stream_request->non_blocking;
-
- set_hostname_and_port(local_name,
- port_buffer,
- nf_to_af(sctp_stream_request->ipfamily),
- sctp_stream_request->port);
-
- local_res = complete_addrinfo(local_name,
- local_name,
- port_buffer,
- nf_to_af(sctp_stream_request->ipfamily),
- SOCK_STREAM,
- IPPROTO_SCTP,
- 0);
-
- s_listen = create_data_socket(local_res);
-
- if (s_listen < 0) {
- netperf_response.content.serv_errno = errno;
- send_response();
- exit(1);
- }
-
- /* what sort of sizes did we end-up with? */
- if (sctp_stream_request->receive_size == 0) {
- if (lsr_size > 0) {
- recv_size = lsr_size;
- }
- else {
- recv_size = 4096;
- }
- }
- else {
- recv_size = sctp_stream_request->receive_size;
- }
-
- /* we want to set-up our recv_ring in a manner analagous to what we */
- /* do on the sending side. this is more for the sake of symmetry */
- /* than for the needs of say copy avoidance, but it might also be */
- /* more realistic - this way one could conceivably go with a */
- /* double-buffering scheme when taking the data an putting it into */
- /* the filesystem or something like that. raj 7/94 */
-
- if (recv_width == 0) {
- recv_width = (lsr_size/recv_size) + 1;
- if (recv_width == 1) recv_width++;
- }
-
- recv_ring = allocate_buffer_ring(recv_width,
- recv_size,
- sctp_stream_request->recv_alignment,
- sctp_stream_request->recv_offset);
-
- if (debug) {
- fprintf(where,"recv_sctp_stream: set recv_size = %d, align = %d, offset = %d.\n",
- recv_size, sctp_stream_request->recv_alignment,
- sctp_stream_request->recv_offset);
- fflush(where);
- }
-
- /* now get the port number assigned by the system */
- addrlen = sizeof(myaddr_in);
- if (getsockname(s_listen,
- (struct sockaddr *)&myaddr_in,
- &addrlen) == -1){
- netperf_response.content.serv_errno = errno;
- close(s_listen);
- send_response();
-
- exit(1);
- }
-
- /* Now myaddr_in contains the port and the internet address this is */
- /* returned to the sender also implicitly telling the sender that the */
- /* socket buffer sizing has been done. */
-
- sctp_stream_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
- netperf_response.content.serv_errno = 0;
-
- /* But wait, there's more. If the initiator wanted cpu measurements, */
- /* then we must call the calibrate routine, which will return the max */
- /* rate back to the initiator. If the CPU was not to be measured, or */
- /* something went wrong with the calibration, we will return a -1 to */
- /* the initiator. */
-
- sctp_stream_response->cpu_rate = (float)0.0; /* assume no cpu */
- if (sctp_stream_request->measure_cpu) {
- sctp_stream_response->measure_cpu = 1;
- sctp_stream_response->cpu_rate =
- calibrate_local_cpu(sctp_stream_request->cpu_rate);
- }
- else {
- sctp_stream_response->measure_cpu = 0;
- }
-
- /* before we send the response back to the initiator, pull some of */
- /* the socket parms from the globals */
- sctp_stream_response->send_buf_size = lss_size;
- sctp_stream_response->recv_buf_size = lsr_size;
- sctp_stream_response->no_delay = loc_nodelay;
- sctp_stream_response->so_rcvavoid = loc_rcvavoid;
- sctp_stream_response->so_sndavoid = loc_sndavoid;
- sctp_stream_response->receive_size = recv_size;
-
- /* 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_response();
-
- addrlen = sizeof(peeraddr);
-
- if ((s_data = accept(s_listen,
- (struct sockaddr *)&peeraddr,
- &addrlen)) == INVALID_SOCKET) {
- /* Let's just punt. The remote will be given some information */
- close(s_listen);
- exit(1);
- }
-
- sctp_enable_events(s_data, SCTP_ASSOC_CHANGE_EV | SCTP_SHUTDOWN_EV);
-
- /* now that we are connected, mark the socket as non-blocking */
- if (non_block) {
- fprintf(where, "setting socket as nonblocking\n");
- fflush(where);
- if (!set_nonblock(s_data)) {
- close(s_data);
- exit(1);
- }
- }
-
-#ifdef KLUDGE_SOCKET_OPTIONS
- /* this is for those systems which *INCORRECTLY* fail to pass */
- /* attributes across an accept() call. Including this goes against */
- /* my better judgement :( raj 11/95 */
-
- kludge_socket_options(s_data);
-
-#endif /* KLUDGE_SOCKET_OPTIONS */
-
- /* Now it's time to start receiving data on the connection. We will */
- /* first grab the apropriate counters and then start grabbing. */
-
- cpu_start(sctp_stream_request->measure_cpu);
-
- /* The loop will exit when the sender does a shutdown, which will */
- /* return a length of zero */
-
-#ifdef DIRTY
- /* we want to dirty some number of consecutive integers in the buffer */
- /* we are about to recv. we may also want to bring some number of */
- /* them cleanly into the cache. The clean ones will follow any dirty */
- /* ones into the cache. */
-
- dirty_count = sctp_stream_request->dirty_count;
- clean_count = sctp_stream_request->clean_count;
- message_int_ptr = (int *)recv_ring->buffer_ptr;
- for (i = 0; i < dirty_count; i++) {
- *message_int_ptr = rand();
- message_int_ptr++;
- }
- for (i = 0; i < clean_count; i++) {
- dirty_count = *message_int_ptr;
- message_int_ptr++;
- }
-#endif /* DIRTY */
-
- bytes_received = 0;
- receive_calls = 0;
-
- while ((len = sctp_recvmsg(s_data,
- recv_ring->buffer_ptr, recv_size,
- NULL, 0, NULL, &msg_flags)) != 0) {
- if (len == SOCKET_ERROR) {
- if (non_block && errno == EAGAIN) {
- if (debug){
- fprintf(where,
- "recv_sctp_stream: sctp_recvmsg timed out, trying again\n");
- fflush(where);
- }
- Set_errno(0);
- continue;
- }
- if (debug) {
- fprintf(where,
- "recv_sctp_stream: sctp_recvmsg error %d, exiting",
- errno);
- fflush(where);
- }
- netperf_response.content.serv_errno = errno;
- send_response();
- close(s_data);
- exit(1);
- }
-
- if (msg_flags & MSG_NOTIFICATION) {
- msg_flags = 0;
- if (debug) {
- fprintf(where,
- "recv_sctp_stream: Got notification... processing\n");
- fflush(where);
- }
- if (sctp_process_event(s_data, recv_ring->buffer_ptr) == SCTP_CLOSE)
- break; /* break out of the recvmsg loop */
-
- continue;
- }
-
- bytes_received += len;
- receive_calls++;
-
- /* more to the next buffer in the recv_ring */
- recv_ring = recv_ring->next;
-
-#ifdef PAUSE
- sleep(1);
-#endif /* PAUSE */
-
-#ifdef DIRTY
- message_int_ptr = (int *)(recv_ring->buffer_ptr);
- for (i = 0; i < dirty_count; i++) {
- *message_int_ptr = rand();
- message_int_ptr++;
- }
- for (i = 0; i < clean_count; i++) {
- dirty_count = *message_int_ptr;
- message_int_ptr++;
- }
-#endif /* DIRTY */
-
-#ifdef DO_SELECT
- FD_SET(s_data,&readfds);
- select(s_data+1,&readfds,NULL,NULL,&timeout);
-#endif /* DO_SELECT */
-
- }
-
- /* perform a shutdown to signal the sender that */
- /* we have received all the data sent. raj 4/93 */
-
- if (close(s_data) == -1) {
- netperf_response.content.serv_errno = errno;
- send_response();
- exit(1);
- }
-
- cpu_stop(sctp_stream_request->measure_cpu,&elapsed_time);
-
- /* send the results to the sender */
-
- if (debug) {
- fprintf(where,
- "recv_sctp_stream: got %g bytes\n",
- bytes_received);
- fprintf(where,
- "recv_sctp_stream: got %d recvs\n",
- receive_calls);
- fflush(where);
- }
-
- sctp_stream_results->bytes_received = htond(bytes_received);
- sctp_stream_results->elapsed_time = elapsed_time;
- sctp_stream_results->recv_calls = receive_calls;
-
- if (sctp_stream_request->measure_cpu) {
- sctp_stream_results->cpu_util = calc_cpu_util(0.0);
- };
-
- if (debug) {
- fprintf(where,
- "recv_sctp_stream: test complete, sending results.\n");
- fprintf(where,
- " bytes_received %g receive_calls %d\n",
- bytes_received,
- receive_calls);
- fprintf(where,
- " len %d\n",
- len);
- fflush(where);
- }
-
- sctp_stream_results->cpu_method = cpu_method;
- sctp_stream_results->num_cpus = lib_num_loc_cpus;
- send_response();
-
- /* we are now done with the sockets */
- close(s_listen);
-
-}
-
-
-/* This routine implements the SCTP 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_sctp_stream_1toMany(remote_host)
-char remote_host[];
-{
-
- char *tput_title = "\
-Recv Send Send \n\
-Socket Socket Message Elapsed \n\
-Size Size Size Time Throughput \n\
-bytes bytes bytes secs. %s/sec \n\n";
-
- char *tput_fmt_0 =
- "%7.2f\n";
-
- char *tput_fmt_1 =
- "%6d %6d %6d %-6.2f %7.2f \n";
-
- char *cpu_title = "\
-Recv Send Send Utilization Service Demand\n\
-Socket Socket Message Elapsed Send Recv Send Recv\n\
-Size Size Size Time Throughput local remote local remote\n\
-bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n";
-
- char *cpu_fmt_0 =
- "%6.3f %c\n";
-
- char *cpu_fmt_1 =
- "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
-
- char *ksink_fmt = "\n\
-Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\
-Local Remote Local Remote Xfered Per Per\n\
-Send Recv Send Recv Send (avg) Recv (avg)\n\
-%5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n";
-
- char *ksink_fmt2 = "\n\
-Maximum\n\
-Segment\n\
-Size (bytes)\n\
-%6d\n";
-
-
- float elapsed_time;
-
-#ifdef WANT_INTERVALS
- int interval_count;
- sigset_t signal_set;
-#endif
-
- /* what we want is to have a buffer space that is at least one */
- /* send-size greater than our send window. this will insure that we */
- /* are never trying to re-use a buffer that may still be in the hands */
- /* of the transport. This buffer will be malloc'd after we have found */
- /* the size of the local senc socket buffer. We will want to deal */
- /* with alignment and offset concerns as well. */
-
-#ifdef DIRTY
- int *message_int_ptr;
-#endif
-
- struct ring_elt *send_ring;
-
- int len;
- unsigned int nummessages = 0;
- int *send_socket;
- int bytes_remaining;
- int sctp_mss;
-
- /* with links like fddi, one can send > 32 bits worth of bytes */
- /* during a test... ;-) at some point, this should probably become a */
- /* 64bit integral type, but those are not entirely common yet */
- double bytes_sent = 0.0;
-
-#ifdef DIRTY
- int i;
-#endif /* DIRTY */
- int j;
-
- float local_cpu_utilization;
- float local_service_demand;
- float remote_cpu_utilization;
- float remote_service_demand;
-
- double thruput;
-
- struct addrinfo *remote_res;
- struct addrinfo *local_res;
- struct addrinfo *last_remote_res;
- struct addrinfo *last_local_res;
-
- struct sctp_stream_request_struct *sctp_stream_request;
- struct sctp_stream_response_struct *sctp_stream_response;
- struct sctp_stream_results_struct *sctp_stream_result;
-
- sctp_stream_request =
- (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data;
- sctp_stream_response =
- (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data;
- sctp_stream_result =
- (struct sctp_stream_results_struct *)netperf_response.content.test_specific_data;
-
-#ifdef WANT_HISTOGRAM
- time_hist = HIST_new();
-#endif /* WANT_HISTOGRAM */
-
- complete_addrinfos(&remote_res,
- &local_res,
- remote_host,
- SOCK_SEQPACKET,
- IPPROTO_SCTP,
- 0);
-
- if ( print_headers ) {
- print_top_test_header("SCTP 1-TO-MANY STREAM TEST",local_res,remote_res);
- }
-
- send_ring = NULL;
- confidence_iteration = 1;
- init_stat();
-
- send_socket = malloc(sizeof (int) * num_associations);
- if (send_socket == NULL) {
- fprintf(where, "send_sctp_stream_1toMany: failed to allocation sockets!\n");
- exit(1);
- }
-
- /* we have a great-big while loop which controls the number of times */
- /* we run a particular test. this is for the calculation of a */
- /* confidence interval (I really should have stayed awake during */
- /* probstats :). If the user did not request confidence measurement */
- /* (no confidence is the default) then we will only go though the */
- /* loop once. the confidence stuff originates from the folks at IBM */
-
- while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
- (confidence_iteration <= iteration_min)) {
-
- int j=0;
- int timed_out = 0;
-
-
- /* initialize a few counters. we have to remember that we might be */
- /* going through the loop more than once. */
-
- nummessages = 0;
- bytes_sent = 0.0;
- times_up = 0;
-
- /* at this point, we have either retrieved the socket buffer sizes, */
- /* or have tried to set them, so now, we may want to set the send */
- /* size based on that (because the user either did not use a -m */
- /* option, or used one with an argument of 0). If the socket buffer */
- /* size is not available, we will set the send size to 4KB - no */
- /* particular reason, just arbitrary... */
- if (send_size == 0) {
- if (lss_size > 0) {
- send_size = lss_size;
- }
- else {
- send_size = 4096;
- }
- }
-
- /* set-up the data buffer ring with the requested alignment and offset. */
- /* note also that we have allocated a quantity */
- /* of memory that is at least one send-size greater than our socket */
- /* buffer size. We want to be sure that there are at least two */
- /* buffers allocated - this can be a bit of a problem when the */
- /* send_size is bigger than the socket size, so we must check... the */
- /* user may have wanted to explicitly set the "width" of our send */
- /* buffers, we should respect that wish... */
- if (send_width == 0) {
- send_width = (lss_size/send_size) + 1;
- if (send_width == 1) send_width++;
- }
-
- if (send_ring == NULL) {
- /* only allocate the send ring once. this is a networking test, */
- /* not a memory allocation test. this way, we do not need a */
- /* deallocate_buffer_ring() routine, and I don't feel like */
- /* writing one anyway :) raj 11/94 */
- send_ring = allocate_buffer_ring(send_width,
- send_size,
- local_send_align,
- local_send_offset);
- }
-
- /* If the user has requested cpu utilization measurements, we must */
- /* calibrate the cpu(s). We will perform this task within the tests */
- /* themselves. If the user has specified the cpu rate, then */
- /* calibrate_local_cpu will return rather quickly as it will have */
- /* nothing to do. If local_cpu_rate is zero, then we will go through */
- /* all the "normal" calibration stuff and return the rate back. */
-
- if (local_cpu_usage) {
- local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
- }
-
- /* Tell the remote end to do a listen. The server alters the socket */
- /* paramters on the other side at this point, hence the reason for */
- /* all the values being passed in the setup message. If the user did */
- /* not specify any of the parameters, they will be passed as 0, which */
- /* will indicate to the remote that no changes beyond the system's */
- /* default should be used. Alignment is the exception, it will */
- /* default to 1, which will be no alignment alterations. */
-
- netperf_request.content.request_type = DO_SCTP_STREAM_MANY;
- sctp_stream_request->send_buf_size = rss_size_req;
- sctp_stream_request->recv_buf_size = rsr_size_req;
- sctp_stream_request->receive_size = recv_size;
- sctp_stream_request->no_delay = rem_nodelay;
- sctp_stream_request->recv_alignment = remote_recv_align;
- sctp_stream_request->recv_offset = remote_recv_offset;
- sctp_stream_request->measure_cpu = remote_cpu_usage;
- sctp_stream_request->cpu_rate = remote_cpu_rate;
- if (test_time) {
- sctp_stream_request->test_length = test_time;
- }
- else {
- if (msg_count)
- test_bytes = send_size * msg_count;
-
- sctp_stream_request->test_length = test_bytes*num_associations;
- }
- sctp_stream_request->so_rcvavoid = rem_rcvavoid;
- sctp_stream_request->so_sndavoid = rem_sndavoid;
-#ifdef DIRTY
- sctp_stream_request->dirty_count = rem_dirty_count;
- sctp_stream_request->clean_count = rem_clean_count;
-#endif /* DIRTY */
- sctp_stream_request->port = (atoi(remote_data_port));
- sctp_stream_request->ipfamily = af_to_nf(remote_res->ai_family);
- sctp_stream_request->non_blocking = non_block;
-
-
- if (debug > 1) {
- fprintf(where,
- "netperf: send_sctp_stream_1toMany: requesting sctp stream test\n");
- }
-
- send_request();
-
- /* The response from the remote will contain all of the relevant */
- /* socket parameters for this test type. We will put them back into */
- /* the variables here so they can be displayed if desired. The */
- /* remote will have calibrated CPU if necessary, and will have done */
- /* all the needed set-up we will have calibrated the cpu locally */
- /* before sending the request, and will grab the counter value right*/
- /* after the connect returns. The remote will grab the counter right*/
- /* after the accept call. This saves the hassle of extra messages */
- /* being sent for the sctp tests. */
-
- recv_response();
-
- if (!netperf_response.content.serv_errno) {
- if (debug)
- fprintf(where,"remote listen done.\n");
- rsr_size = sctp_stream_response->recv_buf_size;
- rss_size = sctp_stream_response->send_buf_size;
- rem_nodelay = sctp_stream_response->no_delay;
- remote_cpu_usage= sctp_stream_response->measure_cpu;
- remote_cpu_rate = sctp_stream_response->cpu_rate;
-
- /* we have to make sure that the server port number is in */
- /* network order */
- set_port_number(remote_res, (unsigned short)sctp_stream_response->data_port_number);
- rem_rcvavoid = sctp_stream_response->so_rcvavoid;
- rem_sndavoid = sctp_stream_response->so_sndavoid;
- }
- else {
- Set_errno(netperf_response.content.serv_errno);
- fprintf(where,
- "netperf: remote error %d",
- netperf_response.content.serv_errno);
- perror("");
- fflush(where);
-
- exit(1);
- }
-
- /*set up the the array of data sockets and connect them to the server */
-
- for (j = 0; j < num_associations; j++) {
- send_socket[j] = create_data_socket(local_res);
-
- if (send_socket[j] < 0){
- perror("netperf: send_sctp_stream_1toMany: sctp stream data socket");
- exit(1);
- }
-
- if (debug) {
- fprintf(where,"send_sctp_stream_1toMany: send_socket obtained...\n");
- }
-
- /*Connect up to the remote port on the data socket */
- if (connect(send_socket[j],
- remote_res->ai_addr,
- remote_res->ai_addrlen) == INVALID_SOCKET){
- perror("netperf: send_sctp_stream_1toMany: data socket connect failed");
- exit(1);
- }
-
- /* Do it after connect is successfull, so that we don't see COMM_UP */
- sctp_enable_events(send_socket[j], SCTP_ASSOC_CHANGE_EV);
-
- if (non_block) {
- /* now that we are connected, mark the socket as non-blocking */
- if (!set_nonblock(send_socket[j])) {
- perror("netperf: fcntl");
- exit(1);
- }
- }
- }
-
- /* Data Socket set-up is finished. If there were problems, either */
- /* the connect would have failed, or the previous response would */
- /* have indicated a problem. I failed to see the value of the */
- /* extra message after the accept on the remote. If it failed, */
- /* we'll see it here. If it didn't, we might as well start pumping */
- /* data. */
-
- /* 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;
- /* in previous revisions, we had the same code repeated throught */
- /* all the test suites. this was unnecessary, and meant more */
- /* work for me when I wanted to switch to POSIX signals, so I */
- /* have abstracted this out into a routine in netlib.c. if you */
- /* are experiencing signal problems, you might want to look */
- /* there. raj 11/94 */
- start_timer(test_time);
- }
- else {
- /* The tester wanted to send a number of bytes. */
- bytes_remaining = test_bytes * num_associations;
- 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);
-
-#ifdef WANT_INTERVALS
- if ((interval_burst) || (demo_mode)) {
- /* zero means that we never pause, so we never should need the */
- /* interval timer, unless we are in demo_mode */
- start_itimer(interval_wate);
- }
- interval_count = interval_burst;
- /* get the signal set for the call to sigsuspend */
- if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
- fprintf(where,
- "send_sctp_stream_1toMany: unable to get sigmask errno %d\n",
- errno);
- fflush(where);
- exit(1);
- }
-#endif /* WANT_INTERVALS */
-
-#ifdef DIRTY
- /* initialize the random number generator for putting dirty stuff */
- /* into the send buffer. raj */
- srand((int) getpid());
-#endif
-
- /* before we start, initialize a few variables */
-
- /* 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)) {
-
-#ifdef DIRTY
- /* we want to dirty some number of consecutive integers in the buffer */
- /* we are about to send. we may also want to bring some number of */
- /* them cleanly into the cache. The clean ones will follow any dirty */
- /* ones into the cache. at some point, we might want to replace */
- /* the rand() call with something from a table to reduce our call */
- /* overhead during the test, but it is not a high priority item. */
- message_int_ptr = (int *)(send_ring->buffer_ptr);
- for (i = 0; i < loc_dirty_count; i++) {
- *message_int_ptr = rand();
- message_int_ptr++;
- }
- for (i = 0; i < loc_clean_count; i++) {
- loc_dirty_count = *message_int_ptr;
- message_int_ptr++;
- }
-#endif /* DIRTY */
-
-#ifdef WANT_HISTOGRAM
- /* timestamp just before we go into send and then again just after */
- /* we come out raj 8/94 */
- gettimeofday(&time_one,NULL);
-#endif /* WANT_HISTOGRAM */
-
- for (j = 0; j < num_associations; j++) {
-
- if((len=sctp_sendmsg(send_socket[j],
- send_ring->buffer_ptr,
- send_size,
- (struct sockaddr *)remote_res->ai_addr,
- remote_res->ai_addrlen,
- 0, 0, 0, 0, 0)) != send_size) {
- if ((len >=0) || SOCKET_EINTR(len)) {
- /* the test was interrupted, must be the end of test */
- timed_out = 1;
- break;
- } else if (non_block && errno == EAGAIN) {
- j--; /* send again on the same socket */
- Set_errno(0);
- continue;
- }
- perror("netperf: data send error");
- printf("len was %d\n",len);
- exit(1);
- }
- }
-
- if (timed_out)
- break; /* test is over, try next iteration */
-
-#ifdef WANT_HISTOGRAM
- /* timestamp the exit from the send call and update the histogram */
- gettimeofday(&time_two,NULL);
- HIST_add(time_hist,delta_micro(&time_one,&time_two));
-#endif /* WANT_HISTOGRAM */
-
-#ifdef WANT_INTERVALS
- if (demo_mode) {
- units_this_tick += send_size;
- }
- /* in this case, the interval count is the count-down couter */
- /* to decide to sleep for a little bit */
- if ((interval_burst) && (--interval_count == 0)) {
- /* call sigsuspend and wait for the interval timer to get us */
- /* out */
- if (debug > 1) {
- fprintf(where,"about to suspend\n");
- fflush(where);
- }
- if (sigsuspend(&signal_set) == EFAULT) {
- fprintf(where,
- "send_sctp_stream_1toMany: fault with sigsuspend.\n");
- fflush(where);
- exit(1);
- }
- interval_count = interval_burst;
- }
-#endif /* WANT_INTERVALS */
-
- /* 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. */
-
- /* but first, if the verbosity is greater than 1, find-out what */
- /* the sctp maximum segment_size was (if possible) */
- if (verbosity > 1) {
- sctp_mss = -1;
- get_sctp_info(send_socket[0], &sctp_mss);
- }
-
- /* signal the server that we are all done writing, this will
- * initiate a shutdonw of one of the associations on the
- * server and trigger an event telling the server it's all done
- */
- sctp_sendmsg(send_socket[0], NULL, 0, remote_res->ai_addr,
- remote_res->ai_addrlen, 0, MSG_EOF, 0, 0, 0);
-
-
- /* The test server will initiate closure of all associations
- * when it's done reading. We want a basic mechanism to catch this
- * and are using SCTP events for this.
- * In blocking mode, we can call recvmsg with the last socket we created.
- * In non-blocking mode, we need to select on the socket for reading.
- * We'll assume that all returns are succefull and signify
- * closure.
- * It is sufficient to do this on a single socket in the client.
- * We choose to do it on a socket other then the one that send MSG_EOF.
- * This means that anything comming in on that socket will be a shutdown.
- */
- if (non_block) {
- fd_set readfds;
-
- FD_ZERO(&readfds);
- FD_SET(send_socket[num_associations-1], &readfds);
- select(send_socket[num_associations-1]+1, &readfds, NULL, NULL, NULL);
- } else {
- sctp_recvmsg(send_socket[num_associations], send_ring->buffer_ptr,
- send_size, NULL, 0, NULL, 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); /* was cpu being */
- /* measured and how */
- /* long did we really */
- /* run? */
-
- /* we are finished with our sockets, so close them to prevent hitting */
- /* the limit on maximum open files. */
- for (j = 0; j < num_associations; j++)
- close(send_socket[j]);
-
- /* 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 {
- Set_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 sctp 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(sctp_stream_result->bytes_received);
-
- thruput = (double) calc_thruput(bytes_sent);
-
- if (local_cpu_usage || remote_cpu_usage) {
- /* We must now do a little math for service demand and cpu */
- /* utilization for the system(s) */
- /* Of course, some of the information might be bogus because */
- /* there was no idle counter in the kernel(s). We need to make */
- /* a note of this for the user's benefit...*/
- if (local_cpu_usage) {
-
- local_cpu_utilization = calc_cpu_util(0.0);
- local_service_demand = calc_service_demand(bytes_sent,
- 0.0,
- 0.0,
- 0);
- }
- else {
- local_cpu_utilization = (float) -1.0;
- local_service_demand = (float) -1.0;
- }
-
- if (remote_cpu_usage) {
-
- remote_cpu_utilization = sctp_stream_result->cpu_util;
- remote_service_demand = calc_service_demand(bytes_sent,
- 0.0,
- remote_cpu_utilization,
- sctp_stream_result->num_cpus);
- }
- else {
- remote_cpu_utilization = (float) -1.0;
- remote_service_demand = (float) -1.0;
- }
- }
- else {
- /* we were not measuring cpu, for the confidence stuff, we */
- /* should make it -1.0 */
- local_cpu_utilization = (float) -1.0;
- local_service_demand = (float) -1.0;
- remote_cpu_utilization = (float) -1.0;
- remote_service_demand = (float) -1.0;
- }
-
- /* at this point, we want to calculate the confidence information. */
- /* if debugging is on, calculate_confidence will print-out the */
- /* parameters we pass it */
-
- calculate_confidence(confidence_iteration,
- elapsed_time,
- thruput,
- local_cpu_utilization,
- remote_cpu_utilization,
- local_service_demand,
- remote_service_demand);
-
-
- confidence_iteration++;
- }
-
- /* at this point, we have finished making all the runs that we */
- /* will be making. so, we should extract what the calcuated values */
- /* are for all the confidence stuff. we could make the values */
- /* global, but that seemed a little messy, and it did not seem worth */
- /* all the mucking with header files. so, we create a routine much */
- /* like calcualte_confidence, which just returns the mean values. */
- /* raj 11/94 */
-
- retrieve_confident_values(&elapsed_time,
- &thruput,
- &local_cpu_utilization,
- &remote_cpu_utilization,
- &local_service_demand,
- &remote_service_demand);
-
- /* We are now ready to print all the information. If the user */
- /* has specified zero-level verbosity, we will just print the */
- /* local service demand, or the remote service demand. If the */
- /* user has requested verbosity level 1, he will get the basic */
- /* "streamperf" numbers. If the user has specified a verbosity */
- /* of greater than 1, we will display a veritable plethora of */
- /* background information from outside of this block as it it */
- /* not cpu_measurement specific... */
-
- if (confidence < 0) {
- /* we did not hit confidence, but were we asked to look for it? */
- if (iteration_max > 1) {
- display_confidence();
- }
- }
-
- if (local_cpu_usage || remote_cpu_usage) {
- local_cpu_method = format_cpu_method(cpu_method);
- remote_cpu_method = format_cpu_method(sctp_stream_result->cpu_method);
-
- switch (verbosity) {
- case 0:
- if (local_cpu_usage) {
- fprintf(where,
- cpu_fmt_0,
- local_service_demand,
- local_cpu_method);
- }
- else {
- fprintf(where,
- cpu_fmt_0,
- remote_service_demand,
- remote_cpu_method);
- }
- break;
- case 1:
- case 2:
- if (print_headers) {
- fprintf(where,
- cpu_title,
- format_units(),
- local_cpu_method,
- remote_cpu_method);
- }
-
- fprintf(where,
- cpu_fmt_1, /* the format string */
- rsr_size, /* remote recvbuf size */
- lss_size, /* local sendbuf size */
- send_size, /* how large were the sends */
- elapsed_time, /* how long was the test */
- thruput, /* what was the xfer rate */
- local_cpu_utilization, /* local cpu */
- remote_cpu_utilization, /* remote cpu */
- local_service_demand, /* local service demand */
- remote_service_demand); /* remote service demand */
- break;
- }
- }
- else {
- /* The tester did not wish to measure service demand. */
-
- switch (verbosity) {
- case 0:
- fprintf(where,
- tput_fmt_0,
- thruput);
- break;
- case 1:
- case 2:
- if (print_headers) {
- fprintf(where,tput_title,format_units());
- }
- fprintf(where,
- tput_fmt_1, /* the format string */
- rsr_size, /* remote recvbuf size */
- lss_size, /* local sendbuf size */
- send_size, /* how large were the sends */
- elapsed_time, /* how long did it take */
- thruput);/* how fast did it go */
- break;
- }
- }
-
- /* it would be a good thing to include information about some of the */
- /* other parameters that may have been set for this test, but at the */
- /* moment, I do not wish to figure-out all the formatting, so I will */
- /* just put this comment here to help remind me that it is something */
- /* that should be done at a later time. */
-
- if (verbosity > 1) {
- /* The user wanted to know it all, so we will give it to him. */
- /* This information will include as much as we can find about */
- /* sctp statistics, the alignments of the sends and receives */
- /* and all that sort of rot... */
-
- /* this stuff needs to be worked-out in the presence of confidence */
- /* intervals and multiple iterations of the test... raj 11/94 */
-
- fprintf(where,
- ksink_fmt,
- "Bytes",
- "Bytes",
- "Bytes",
- local_send_align,
- remote_recv_align,
- local_send_offset,
- remote_recv_offset,
- bytes_sent,
- bytes_sent / (double)nummessages,
- nummessages,
- bytes_sent / (double)sctp_stream_result->recv_calls,
- sctp_stream_result->recv_calls);
- fprintf(where,
- ksink_fmt2,
- sctp_mss);
- fflush(where);
-#ifdef WANT_HISTOGRAM
- fprintf(where,"\n\nHistogram of time spent in send() call.\n");
- fflush(where);
- HIST_report(time_hist);
-#endif /* WANT_HISTOGRAM */
- }
-
-}
-
-
-
-/* This is the server-side routine for the sctp stream test. It is */
-/* implemented as one routine. I could break things-out somewhat, but */
-/* didn't feel it was necessary. */
-
-void
-recv_sctp_stream_1toMany()
-{
-
- struct sockaddr_in myaddr_in;
- int s_recv;
- int addrlen;
- int len;
- unsigned int receive_calls;
- float elapsed_time;
- double bytes_received;
- int msg_flags = 0;
-
- struct ring_elt *recv_ring;
-
- struct addrinfo *local_res;
- char local_name[BUFSIZ];
- char port_buffer[PORTBUFSIZE];
-
-#ifdef DIRTY
- int *message_int_ptr;
- int dirty_count;
- int clean_count;
- int i;
-#endif
-
-#ifdef DO_SELECT
- fd_set readfds;
- struct timeval timeout;
-#endif
-
- struct sctp_stream_request_struct *sctp_stream_request;
- struct sctp_stream_response_struct *sctp_stream_response;
- struct sctp_stream_results_struct *sctp_stream_results;
-
-#ifdef DO_SELECT
- FD_ZERO(&readfds);
- timeout.tv_sec = 1;
- timeout.tv_usec = 0;
-#endif
-
- sctp_stream_request =
- (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data;
- sctp_stream_response =
- (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data;
- sctp_stream_results =
- (struct sctp_stream_results_struct *)netperf_response.content.test_specific_data;
-
- if (debug) {
- fprintf(where,"netserver: recv_sctp_stream: entered...\n");
- fflush(where);
- }
-
- /* We want to set-up the listen socket with all the desired */
- /* parameters and then let the initiator know that all is ready. If */
- /* socket size defaults are to be used, then the initiator will have */
- /* sent us 0's. If the socket sizes cannot be changed, then we will */
- /* send-back what they are. If that information cannot be determined, */
- /* then we send-back -1's for the sizes. If things go wrong for any */
- /* reason, we will drop back ten yards and punt. */
-
- /* If anything goes wrong, we want the remote to know about it. It */
- /* would be best if the error that the remote reports to the user is */
- /* the actual error we encountered, rather than some bogus unexpected */
- /* response type message. */
-
- if (debug) {
- fprintf(where,"recv_sctp_stream_1toMany: setting the response type...\n");
- fflush(where);
- }
-
- netperf_response.content.response_type = SCTP_STREAM_MANY_RESPONSE;
-
- if (debug) {
- fprintf(where,"recv_sctp_stream_1toMany: the response type is set...\n");
- fflush(where);
- }
-
- /* We now alter the message_ptr variable to be at the desired */
- /* alignment with the desired offset. */
-
- if (debug) {
- fprintf(where,"recv_sctp_stream_1toMany: requested alignment of %d\n",
- sctp_stream_request->recv_alignment);
- fflush(where);
- }
-
- /* create_data_socket expects to find some things in the global */
- /* variables, so set the globals based on the values in the request. */
- /* once the socket has been created, we will set the response values */
- /* based on the updated value of those globals. raj 7/94 */
- lss_size_req = sctp_stream_request->send_buf_size;
- lsr_size_req = sctp_stream_request->recv_buf_size;
- loc_nodelay = sctp_stream_request->no_delay;
- loc_rcvavoid = sctp_stream_request->so_rcvavoid;
- loc_sndavoid = sctp_stream_request->so_sndavoid;
- non_block = sctp_stream_request->non_blocking;
-
- set_hostname_and_port(local_name,
- port_buffer,
- nf_to_af(sctp_stream_request->ipfamily),
- sctp_stream_request->port);
-
- local_res = complete_addrinfo(local_name,
- local_name,
- port_buffer,
- nf_to_af(sctp_stream_request->ipfamily),
- SOCK_SEQPACKET,
- IPPROTO_SCTP,
- 0);
-
- s_recv = create_data_socket(local_res);
-
- if (s_recv < 0) {
- netperf_response.content.serv_errno = errno;
- send_response();
- exit(1);
- }
-
- /* what sort of sizes did we end-up with? */
- if (sctp_stream_request->receive_size == 0) {
- if (lsr_size > 0) {
- recv_size = lsr_size;
- }
- else {
- recv_size = 4096;
- }
- }
- else {
- recv_size = sctp_stream_request->receive_size;
- }
-
- /* we want to set-up our recv_ring in a manner analagous to what we */
- /* do on the sending side. this is more for the sake of symmetry */
- /* than for the needs of say copy avoidance, but it might also be */
- /* more realistic - this way one could conceivably go with a */
- /* double-buffering scheme when taking the data an putting it into */
- /* the filesystem or something like that. raj 7/94 */
-
- if (recv_width == 0) {
- recv_width = (lsr_size/recv_size) + 1;
- if (recv_width == 1) recv_width++;
- }
-
- recv_ring = allocate_buffer_ring(recv_width,
- recv_size,
- sctp_stream_request->recv_alignment,
- sctp_stream_request->recv_offset);
-
- if (debug) {
- fprintf(where,"recv_sctp_stream: receive alignment and offset set...\n");
- fflush(where);
- }
-
- /* Now, let's set-up the socket to listen for connections */
- if (listen(s_recv, 5) == -1) {
- netperf_response.content.serv_errno = errno;
- close(s_recv);
- send_response();
-
- exit(1);
- }
-
- /* now get the port number assigned by the system */
- addrlen = sizeof(myaddr_in);
- if (getsockname(s_recv,
- (struct sockaddr *)&myaddr_in,
- &addrlen) == -1){
- netperf_response.content.serv_errno = errno;
- close(s_recv);
- send_response();
-
- exit(1);
- }
-
- /* Now myaddr_in contains the port and the internet address this is */
- /* returned to the sender also implicitly telling the sender that the */
- /* socket buffer sizing has been done. */
-
- sctp_stream_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
- netperf_response.content.serv_errno = 0;
-
- /* But wait, there's more. If the initiator wanted cpu measurements, */
- /* then we must call the calibrate routine, which will return the max */
- /* rate back to the initiator. If the CPU was not to be measured, or */
- /* something went wrong with the calibration, we will return a -1 to */
- /* the initiator. */
-
- sctp_stream_response->cpu_rate = (float)0.0; /* assume no cpu */
- if (sctp_stream_request->measure_cpu) {
- sctp_stream_response->measure_cpu = 1;
- sctp_stream_response->cpu_rate =
- calibrate_local_cpu(sctp_stream_request->cpu_rate);
- }
- else {
- sctp_stream_response->measure_cpu = 0;
- }
-
- /* before we send the response back to the initiator, pull some of */
- /* the socket parms from the globals */
- sctp_stream_response->send_buf_size = lss_size;
- sctp_stream_response->recv_buf_size = lsr_size;
- sctp_stream_response->no_delay = loc_nodelay;
- sctp_stream_response->so_rcvavoid = loc_rcvavoid;
- sctp_stream_response->so_sndavoid = loc_sndavoid;
- sctp_stream_response->receive_size = recv_size;
-
- send_response();
-
-
- sctp_enable_events(s_recv, SCTP_ASSOC_CHANGE_EV | SCTP_SHUTDOWN_EV);
-
- /* now that we are connected, mark the socket as non-blocking */
- if (non_block) {
- if (!set_nonblock(s_recv)) {
- close(s_recv);
- exit(1);
- }
- }
-
-
- /* Now it's time to start receiving data on the connection. We will */
- /* first grab the apropriate counters and then start grabbing. */
-
- cpu_start(sctp_stream_request->measure_cpu);
-
- /* The loop will exit when the sender does a shutdown, which will */
- /* return a length of zero */
-
-#ifdef DIRTY
- /* we want to dirty some number of consecutive integers in the buffer */
- /* we are about to recv. we may also want to bring some number of */
- /* them cleanly into the cache. The clean ones will follow any dirty */
- /* ones into the cache. */
-
- dirty_count = sctp_stream_request->dirty_count;
- clean_count = sctp_stream_request->clean_count;
- message_int_ptr = (int *)recv_ring->buffer_ptr;
- for (i = 0; i < dirty_count; i++) {
- *message_int_ptr = rand();
- message_int_ptr++;
- }
- for (i = 0; i < clean_count; i++) {
- dirty_count = *message_int_ptr;
- message_int_ptr++;
- }
-#endif /* DIRTY */
-
- bytes_received = 0;
- receive_calls = 0;
-
- while ((len = sctp_recvmsg(s_recv, recv_ring->buffer_ptr, recv_size,
- NULL, 0, /* we don't care who it's from */
- NULL, &msg_flags)) != 0) {
- if (len < 0) {
- if (non_block && errno == EAGAIN) {
- Set_errno(0);
- continue;
- }
- netperf_response.content.serv_errno = errno;
- send_response();
- close(s_recv);
- exit(1);
- }
-
- if (msg_flags & MSG_NOTIFICATION) {
- if (sctp_process_event(s_recv, recv_ring->buffer_ptr) == SCTP_CLOSE)
- break;
-
- continue;
- }
-
- bytes_received += len;
- receive_calls++;
-
- /* more to the next buffer in the recv_ring */
- recv_ring = recv_ring->next;
-
-#ifdef PAUSE
- sleep(1);
-#endif /* PAUSE */
-
-#ifdef DIRTY
- message_int_ptr = (int *)(recv_ring->buffer_ptr);
- for (i = 0; i < dirty_count; i++) {
- *message_int_ptr = rand();
- message_int_ptr++;
- }
- for (i = 0; i < clean_count; i++) {
- dirty_count = *message_int_ptr;
- message_int_ptr++;
- }
-#endif /* DIRTY */
-
-#ifdef DO_SELECT
- FD_SET(s_recv,&readfds);
- select(s_recv+1,&readfds,NULL,NULL,&timeout);
-#endif /* DO_SELECT */
-
- }
-
- /* perform a shutdown to signal the sender. in this case, sctp
- * will close all associations on this socket
- */
- if (close(s_recv) == -1) {
- netperf_response.content.serv_errno = errno;
- send_response();
- exit(1);
- }
-
- cpu_stop(sctp_stream_request->measure_cpu,&elapsed_time);
-
- /* send the results to the sender */
-
- if (debug) {
- fprintf(where,
- "recv_sctp_stream: got %g bytes\n",
- bytes_received);
- fprintf(where,
- "recv_sctp_stream: got %d recvs\n",
- receive_calls);
- fflush(where);
- }
-
- sctp_stream_results->bytes_received = htond(bytes_received);
- sctp_stream_results->elapsed_time = elapsed_time;
- sctp_stream_results->recv_calls = receive_calls;
-
- if (sctp_stream_request->measure_cpu) {
- sctp_stream_results->cpu_util = calc_cpu_util(0.0);
- };
-
- if (debug) {
- fprintf(where,
- "recv_sctp_stream: test complete, sending results.\n");
- fprintf(where,
- " bytes_received %g receive_calls %d\n",
- bytes_received,
- receive_calls);
- fprintf(where,
- " len %d\n",
- len);
- fflush(where);
- }
-
- sctp_stream_results->cpu_method = cpu_method;
- sctp_stream_results->num_cpus = lib_num_loc_cpus;
- send_response();
-}
-
-
- /* this routine implements the sending (netperf) side of the SCTP_RR */
- /* test. */
-
-void
-send_sctp_rr(remote_host)
- char remote_host[];
-{
-
- char *tput_title = "\
-Local /Remote\n\
-Socket Size Request Resp. Elapsed Trans.\n\
-Send Recv Size Size Time Rate \n\
-bytes Bytes bytes bytes secs. per sec \n\n";
-
- char *tput_fmt_0 =
- "%7.2f\n";
-
- char *tput_fmt_1_line_1 = "\
-%-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
- char *tput_fmt_1_line_2 = "\
-%-6d %-6d\n";
-
- char *cpu_title = "\
-Local /Remote\n\
-Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
-Send Recv Size Size Time Rate local remote local remote\n\
-bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
-
- char *cpu_fmt_0 =
- "%6.3f %c\n";
-
- char *cpu_fmt_1_line_1 = "\
-%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
-
- char *cpu_fmt_1_line_2 = "\
-%-6d %-6d\n";
-
- char *ksink_fmt = "\
-Alignment Offset\n\
-Local Remote Local Remote\n\
-Send Recv Send Recv\n\
-%5d %5d %5d %5d\n";
-
-
- int timed_out = 0;
- float elapsed_time;
-
- int len;
- char *temp_message_ptr;
- int nummessages;
- int send_socket;
- int trans_remaining;
- int msg_flags = 0;
- double bytes_xferd;
-
- struct ring_elt *send_ring;
- struct ring_elt *recv_ring;
-
- int rsp_bytes_left;
- int rsp_bytes_recvd;
-
- float local_cpu_utilization;
- float local_service_demand;
- float remote_cpu_utilization;
- float remote_service_demand;
- double thruput;
-
- struct sockaddr_storage peer;
- struct addrinfo *remote_res;
- struct addrinfo *local_res;
-
- struct sctp_rr_request_struct *sctp_rr_request;
- struct sctp_rr_response_struct *sctp_rr_response;
- struct sctp_rr_results_struct *sctp_rr_result;
-
-#ifdef WANT_INTERVALS
- int interval_count;
- sigset_t signal_set;
-#endif /* WANT_INTERVALS */
-
- sctp_rr_request =
- (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data;
- sctp_rr_response =
- (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data;
- sctp_rr_result =
- (struct sctp_rr_results_struct *)netperf_response.content.test_specific_data;
-
-#ifdef WANT_HISTOGRAM
- time_hist = HIST_new();
-#endif /* WANT_HISTOGRAM */
-
- /* since we are now disconnected from the code that established the */
- /* control socket, and since we want to be able to use different */
- /* protocols and such, we are passed the name of the remote host and */
- /* must turn that into the test specific addressing information. */
-
- /* complete_addrinfos will either succede or exit the process */
- complete_addrinfos(&remote_res,
- &local_res,
- remote_host,
- SOCK_STREAM,
- IPPROTO_SCTP,
- 0);
-
- if ( print_headers ) {
- print_top_test_header("SCTP REQUEST/RESPONSE TEST", local_res, remote_res);
- }
-
- /* initialize a few counters */
-
- send_ring = NULL;
- recv_ring = NULL;
- confidence_iteration = 1;
- init_stat();
-
- /* we have a great-big while loop which controls the number of times */
- /* we run a particular test. this is for the calculation of a */
- /* confidence interval (I really should have stayed awake during */
- /* probstats :). If the user did not request confidence measurement */
- /* (no confidence is the default) then we will only go though the */
- /* loop once. the confidence stuff originates from the folks at IBM */
-
- while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
- (confidence_iteration <= iteration_min)) {
-
- /* initialize a few counters. we have to remember that we might be */
- /* going through the loop more than once. */
-
- nummessages = 0;
- bytes_xferd = 0.0;
- times_up = 0;
- timed_out = 0;
- trans_remaining = 0;
-
- /* set-up the data buffers with the requested alignment and offset. */
- /* since this is a request/response test, default the send_width and */
- /* recv_width to 1 and not two raj 7/94 */
-
- if (send_width == 0) send_width = 1;
- if (recv_width == 0) recv_width = 1;
-
- if (send_ring == NULL) {
- send_ring = allocate_buffer_ring(send_width,
- req_size,
- local_send_align,
- local_send_offset);
- }
-
- if (recv_ring == NULL) {
- recv_ring = allocate_buffer_ring(recv_width,
- rsp_size,
- local_recv_align,
- local_recv_offset);
- }
-
- /*set up the data socket */
- send_socket = create_data_socket(local_res);
-
- if (send_socket < 0){
- perror("netperf: send_sctp_rr: sctp stream data socket");
- exit(1);
- }
-
- if (debug) {
- fprintf(where,"send_sctp_rr: send_socket obtained...\n");
- }
-
- /* If the user has requested cpu utilization measurements, we must */
- /* calibrate the cpu(s). We will perform this task within the tests */
- /* themselves. If the user has specified the cpu rate, then */
- /* calibrate_local_cpu will return rather quickly as it will have */
- /* nothing to do. If local_cpu_rate is zero, then we will go through */
- /* all the "normal" calibration stuff and return the rate back.*/
-
- if (local_cpu_usage) {
- local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
- }
-
- /* Tell the remote end to do a listen. The server alters the socket */
- /* paramters on the other side at this point, hence the reason for */
- /* all the values being passed in the setup message. If the user did */
- /* not specify any of the parameters, they will be passed as 0, which */
- /* will indicate to the remote that no changes beyond the system's */
- /* default should be used. Alignment is the exception, it will */
- /* default to 8, which will be no alignment alterations. */
-
- netperf_request.content.request_type = DO_SCTP_RR;
- sctp_rr_request->recv_buf_size = rsr_size_req;
- sctp_rr_request->send_buf_size = rss_size_req;
- sctp_rr_request->recv_alignment = remote_recv_align;
- sctp_rr_request->recv_offset = remote_recv_offset;
- sctp_rr_request->send_alignment = remote_send_align;
- sctp_rr_request->send_offset = remote_send_offset;
- sctp_rr_request->request_size = req_size;
- sctp_rr_request->response_size = rsp_size;
- sctp_rr_request->no_delay = rem_nodelay;
- sctp_rr_request->measure_cpu = remote_cpu_usage;
- sctp_rr_request->cpu_rate = remote_cpu_rate;
- sctp_rr_request->so_rcvavoid = rem_rcvavoid;
- sctp_rr_request->so_sndavoid = rem_sndavoid;
- if (test_time) {
- sctp_rr_request->test_length = test_time;
- }
- else {
- sctp_rr_request->test_length = test_trans * -1;
- }
- sctp_rr_request->non_blocking = non_block;
- sctp_rr_request->ipfamily = af_to_nf(remote_res->ai_family);
-
- if (debug > 1) {
- fprintf(where,"netperf: send_sctp_rr: requesting SCTP rr test\n");
- }
-
- send_request();
-
- /* The response from the remote will contain all of the relevant */
- /* socket parameters for this test type. We will put them back into */
- /* the variables here so they can be displayed if desired. The */
- /* remote will have calibrated CPU if necessary, and will have done */
- /* all the needed set-up we will have calibrated the cpu locally */
- /* before sending the request, and will grab the counter value right*/
- /* after the connect returns. The remote will grab the counter right*/
- /* after the accept call. This saves the hassle of extra messages */
- /* being sent for the sctp tests. */
-
- recv_response();
-
- if (!netperf_response.content.serv_errno) {
- if (debug)
- fprintf(where,"remote listen done.\n");
- rsr_size = sctp_rr_response->recv_buf_size;
- rss_size = sctp_rr_response->send_buf_size;
- rem_nodelay = sctp_rr_response->no_delay;
- remote_cpu_usage = sctp_rr_response->measure_cpu;
- remote_cpu_rate = sctp_rr_response->cpu_rate;
- /* make sure that port numbers are in network order */
- set_port_number(remote_res,
- (unsigned short)sctp_rr_response->data_port_number);
- }
- else {
- Set_errno(netperf_response.content.serv_errno);
- fprintf(where,
- "netperf: remote error %d",
- netperf_response.content.serv_errno);
- perror("");
- fflush(where);
-
- exit(1);
- }
-
- /*Connect up to the remote port on the data socket */
- if (connect(send_socket,
- remote_res->ai_addr,
- remote_res->ai_addrlen) <0){
- perror("netperf: send_sctp_rr data socket connect failed");
- exit(1);
- }
-
- /* don't need events for 1-to-1 API with request-response tests */
- sctp_enable_events(send_socket, 0);
-
- /* set non-blocking if needed */
- if (non_block) {
- if (!set_nonblock(send_socket)) {
- close(send_socket);
- exit(1);
- }
- }
-
- /* Data Socket set-up is finished. If there were problems, either the */
- /* connect would have failed, or the previous response would have */
- /* indicated a problem. I failed to see the value of the extra */
- /* message after the accept on the remote. If it failed, we'll see it */
- /* here. If it didn't, we might as well start pumping data. */
-
- /* 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);
-
-#ifdef WANT_INTERVALS
- if ((interval_burst) || (demo_mode)) {
- /* zero means that we never pause, so we never should need the */
- /* interval timer, unless we are in demo_mode */
- start_itimer(interval_wate);
- }
- interval_count = interval_burst;
- /* get the signal set for the call to sigsuspend */
- if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
- fprintf(where,
- "send_sctp_rr: unable to get sigmask errno %d\n",
- errno);
- fflush(where);
- exit(1);
- }
-#endif /* WANT_INTERVALS */
-
- /* 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. I think I */
- /* just arbitrarily decrement trans_remaining for the timed test, but */
- /* will not do that just yet... One other question is whether or not */
- /* the send buffer and the receive buffer should be the same buffer. */
-
-#ifdef WANT_FIRST_BURST
- {
- int i;
- for (i = 0; i < first_burst_size; i++) {
- if((len=sctp_sendmsg(send_socket,
- send_ring->buffer_ptr, req_size,
- NULL, 0, /* don't need addrs with 1-to-1 */
- 0, 0, 0, 0, 0)) != req_size) {
- /* we should never hit the end of the test in the first burst */
- perror("send_sctp_rr: initial burst data send error");
- exit(1);
- }
- }
- }
-#endif /* WANT_FIRST_BURST */
-
- 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. */
-
-#ifdef WANT_HISTOGRAM
- /* timestamp just before our call to send, and then again just */
- /* after the receive raj 8/94 */
- HIST_timestamp(&time_one);
-#endif /* WANT_HISTOGRAM */
-
- while ((len=sctp_sendmsg(send_socket,
- send_ring->buffer_ptr, req_size,
- NULL, 0, /* don't need addrs with 1-to-1 */
- 0, 0, 0, 0, 0)) != req_size) {
- if (non_block && errno == EAGAIN) {
- /* try sending again */
- continue;
- } else if (SOCKET_EINTR(len) || (errno == 0)) {
- /* we hit the end of a */
- /* timed test. */
- timed_out = 1;
- break;
- }
- perror("send_sctp_rr: data send error");
- exit(1);
- }
-
- if (timed_out) {
- /* we timed out while sending. break out another level */
- break;
- }
- send_ring = send_ring->next;
-
- /* receive the response */
- rsp_bytes_left = rsp_size;
- temp_message_ptr = recv_ring->buffer_ptr;
- do {
- msg_flags = 0;
- if ((rsp_bytes_recvd=sctp_recvmsg(send_socket,
- temp_message_ptr, rsp_bytes_left,
- NULL, 0,
- NULL, &msg_flags)) < 0) {
- if (errno == EINTR) {
- /* We hit the end of a timed test. */
- timed_out = 1;
- break;
- } else if (non_block && errno == EAGAIN) {
- continue;
- }
- perror("send_sctp_rr: data recv error");
- exit(1);
- }
- rsp_bytes_left -= rsp_bytes_recvd;
- temp_message_ptr += rsp_bytes_recvd;
- } while (!(msg_flags & MSG_EOR));
-
- recv_ring = recv_ring->next;
-
- if (timed_out) {
- /* we may have been in a nested while loop - we need */
- /* another call to break. */
- break;
- }
-
-#ifdef WANT_HISTOGRAM
- HIST_timestamp(&time_two);
- HIST_add(time_hist,delta_micro(&time_one,&time_two));
-#endif /* WANT_HISTOGRAM */
-#ifdef WANT_INTERVALS
- if (demo_mode) {
- units_this_tick += 1;
- }
- /* in this case, the interval count is the count-down couter */
- /* to decide to sleep for a little bit */
- if ((interval_burst) && (--interval_count == 0)) {
- /* call sigsuspend and wait for the interval timer to get us */
- /* out */
- if (debug > 1) {
- fprintf(where,"about to suspend\n");
- fflush(where);
- }
- if (sigsuspend(&signal_set) == EFAULT) {
- fprintf(where,
- "send_sctp_rr: fault with signal set!\n");
- fflush(where);
- exit(1);
- }
- interval_count = interval_burst;
- }
-#endif /* WANT_INTERVALS */
-
- nummessages++;
- if (trans_remaining) {
- trans_remaining--;
- }
-
- if (debug > 3) {
- if ((nummessages % 100) == 0) {
- fprintf(where,
- "Transaction %d completed\n",
- nummessages);
- fflush(where);
- }
- }
- }
-
- /* At this point we used to call shutdown on the data socket to be */
- /* sure all the data was delivered, but this was not germane in a */
- /* request/response test, and it was causing the tests to "hang" when */
- /* they were being controlled by time. So, I have replaced this */
- /* shutdown call with a call to close that can be found later in the */
- /* procedure. */
-
- /* 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); /* was cpu being */
- /* measured? how long */
- /* did we really run? */
-
- /* Get the statistics from the remote end. The remote will have */
- /* calculated CPU utilization. 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 {
- Set_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 throughput was for the test. */
-
- bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
- thruput = nummessages/elapsed_time;
-
- if (local_cpu_usage || remote_cpu_usage) {
- /* We must now do a little math for service demand and cpu */
- /* utilization for the system(s) */
- /* Of course, some of the information might be bogus because */
- /* there was no idle counter in the kernel(s). We need to make */
- /* a note of this for the user's benefit...*/
- if (local_cpu_usage) {
- local_cpu_utilization = calc_cpu_util(0.0);
- /* since calc_service demand is doing ms/Kunit we will */
- /* multiply the number of transaction by 1024 to get */
- /* "good" numbers */
- local_service_demand = calc_service_demand((double) nummessages*1024,
- 0.0,
- 0.0,
- 0);
- }
- else {
- local_cpu_utilization = (float) -1.0;
- local_service_demand = (float) -1.0;
- }
-
- if (remote_cpu_usage) {
- remote_cpu_utilization = sctp_rr_result->cpu_util;
- /* since calc_service demand is doing ms/Kunit we will */
- /* multiply the number of transaction by 1024 to get */
- /* "good" numbers */
- remote_service_demand = calc_service_demand((double) nummessages*1024,
- 0.0,
- remote_cpu_utilization,
- sctp_rr_result->num_cpus);
- }
- else {
- remote_cpu_utilization = (float) -1.0;
- remote_service_demand = (float) -1.0;
- }
-
- }
- else {
- /* we were not measuring cpu, for the confidence stuff, we */
- /* should make it -1.0 */
- local_cpu_utilization = (float) -1.0;
- local_service_demand = (float) -1.0;
- remote_cpu_utilization = (float) -1.0;
- remote_service_demand = (float) -1.0;
- }
-
- /* at this point, we want to calculate the confidence information. */
- /* if debugging is on, calculate_confidence will print-out the */
- /* parameters we pass it */
-
- calculate_confidence(confidence_iteration,
- elapsed_time,
- thruput,
- local_cpu_utilization,
- remote_cpu_utilization,
- local_service_demand,
- remote_service_demand);
-
-
- confidence_iteration++;
-
- /* we are now done with the socket, so close it */
- close(send_socket);
-
- }
-
- retrieve_confident_values(&elapsed_time,
- &thruput,
- &local_cpu_utilization,
- &remote_cpu_utilization,
- &local_service_demand,
- &remote_service_demand);
-
- /* We are now ready to print all the information. If the user */
- /* has specified zero-level verbosity, we will just print the */
- /* local service demand, or the remote service demand. If the */
- /* user has requested verbosity level 1, he will get the basic */
- /* "streamperf" numbers. If the user has specified a verbosity */
- /* of greater than 1, we will display a veritable plethora of */
- /* background information from outside of this block as it it */
- /* not cpu_measurement specific... */
-
- if (confidence < 0) {
- /* we did not hit confidence, but were we asked to look for it? */
- if (iteration_max > 1) {
- display_confidence();
- }
- }
-
- if (local_cpu_usage || remote_cpu_usage) {
- local_cpu_method = format_cpu_method(cpu_method);
- remote_cpu_method = format_cpu_method(sctp_rr_result->cpu_method);
-
- switch (verbosity) {
- case 0:
- if (local_cpu_usage) {
- fprintf(where,
- cpu_fmt_0,
- local_service_demand,
- local_cpu_method);
- }
- else {
- fprintf(where,
- cpu_fmt_0,
- remote_service_demand,
- remote_cpu_method);
- }
- break;
- case 1:
- case 2:
- if (print_headers) {
- fprintf(where,
- cpu_title,
- local_cpu_method,
- remote_cpu_method);
- }
-
- fprintf(where,
- cpu_fmt_1_line_1, /* the format string */
- lss_size, /* local sendbuf size */
- lsr_size,
- req_size, /* how large were the requests */
- rsp_size, /* guess */
- elapsed_time, /* how long was the test */
- thruput,
- local_cpu_utilization, /* local cpu */
- remote_cpu_utilization, /* remote cpu */
- local_service_demand, /* local service demand */
- remote_service_demand); /* remote service demand */
- fprintf(where,
- cpu_fmt_1_line_2,
- rss_size,
- rsr_size);
- break;
- }
- }
- else {
- /* The tester did not wish to measure service demand. */
-
- switch (verbosity) {
- case 0:
- fprintf(where,
- tput_fmt_0,
- thruput);
- break;
- case 1:
- case 2:
- if (print_headers) {
- fprintf(where,tput_title,format_units());
- }
-
- fprintf(where,
- tput_fmt_1_line_1, /* the format string */
- lss_size,
- lsr_size,
- req_size, /* how large were the requests */
- rsp_size, /* how large were the responses */
- elapsed_time, /* how long did it take */
- thruput);
- fprintf(where,
- tput_fmt_1_line_2,
- rss_size, /* remote recvbuf size */
- rsr_size);
-
- break;
- }
- }
-
- /* it would be a good thing to include information about some of the */
- /* other parameters that may have been set for this test, but at the */
- /* moment, I do not wish to figure-out all the formatting, so I will */
- /* just put this comment here to help remind me that it is something */
- /* that should be done at a later time. */
-
- /* how to handle the verbose information in the presence of */
- /* confidence intervals is yet to be determined... raj 11/94 */
- if (verbosity > 1) {
- /* The user wanted to know it all, so we will give it to him. */
- /* This information will include as much as we can find about */
- /* TCP statistics, the alignments of the sends and receives */
- /* and all that sort of rot... */
-
- fprintf(where,
- ksink_fmt,
- local_send_align,
- remote_recv_offset,
- local_send_offset,
- remote_recv_offset);
-
-#ifdef WANT_HISTOGRAM
- fprintf(where,"\nHistogram of request/response times\n");
- fflush(where);
- HIST_report(time_hist);
-#endif /* WANT_HISTOGRAM */
-
- }
-
-}
-
-
- /* this routine implements the receive (netserver) side of a TCP_RR */
- /* test */
-void
-recv_sctp_rr()
-{
-
- struct ring_elt *send_ring;
- struct ring_elt *recv_ring;
-
- struct addrinfo *local_res;
- char local_name[BUFSIZ];
- char port_buffer[PORTBUFSIZE];
-
- struct sockaddr_in myaddr_in, peeraddr_in;
- int s_listen, s_data;
- int addrlen;
- char *temp_message_ptr;
- int trans_received;
- int trans_remaining;
- int bytes_sent;
- int request_bytes_recvd;
- int request_bytes_remaining;
- int timed_out = 0;
- float elapsed_time;
-
- struct sctp_rr_request_struct *sctp_rr_request;
- struct sctp_rr_response_struct *sctp_rr_response;
- struct sctp_rr_results_struct *sctp_rr_results;
-
- sctp_rr_request =
- (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data;
- sctp_rr_response =
- (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data;
- sctp_rr_results =
- (struct sctp_rr_results_struct *)netperf_response.content.test_specific_data;
-
- if (debug) {
- fprintf(where,"netserver: recv_sctp_rr: entered...\n");
- fflush(where);
- }
-
- /* We want to set-up the listen socket with all the desired */
- /* parameters and then let the initiator know that all is ready. If */
- /* socket size defaults are to be used, then the initiator will have */
- /* sent us 0's. If the socket sizes cannot be changed, then we will */
- /* send-back what they are. If that information cannot be determined, */
- /* then we send-back -1's for the sizes. If things go wrong for any */
- /* reason, we will drop back ten yards and punt. */
-
- /* If anything goes wrong, we want the remote to know about it. It */
- /* would be best if the error that the remote reports to the user is */
- /* the actual error we encountered, rather than some bogus unexpected */
- /* response type message. */
-
- if (debug) {
- fprintf(where,"recv_sctp_rr: setting the response type...\n");
- fflush(where);
- }
-
- netperf_response.content.response_type = SCTP_RR_RESPONSE;
-
- if (debug) {
- fprintf(where,"recv_sctp_rr: the response type is set...\n");
- fflush(where);
- }
-
- /* allocate the recv and send rings with the requested alignments */
- /* and offsets. raj 7/94 */
- if (debug) {
- fprintf(where,"recv_sctp_rr: requested recv alignment of %d offset %d\n",
- sctp_rr_request->recv_alignment,
- sctp_rr_request->recv_offset);
- fprintf(where,"recv_sctp_rr: requested send alignment of %d offset %d\n",
- sctp_rr_request->send_alignment,
- sctp_rr_request->send_offset);
- fflush(where);
- }
-
- /* at some point, these need to come to us from the remote system */
- if (send_width == 0) send_width = 1;
- if (recv_width == 0) recv_width = 1;
-
- send_ring = allocate_buffer_ring(send_width,
- sctp_rr_request->response_size,
- sctp_rr_request->send_alignment,
- sctp_rr_request->send_offset);
-
- recv_ring = allocate_buffer_ring(recv_width,
- sctp_rr_request->request_size,
- sctp_rr_request->recv_alignment,
- sctp_rr_request->recv_offset);
-
-
- /* Grab a socket to listen on, and then listen on it. */
-
- if (debug) {
- fprintf(where,"recv_sctp_rr: grabbing a socket...\n");
- fflush(where);
- }
-
- /* create_data_socket expects to find some things in the global */
- /* variables, so set the globals based on the values in the request. */
- /* once the socket has been created, we will set the response values */
- /* based on the updated value of those globals. raj 7/94 */
- lss_size_req = sctp_rr_request->send_buf_size;
- lsr_size_req = sctp_rr_request->recv_buf_size;
- loc_nodelay = sctp_rr_request->no_delay;
- loc_rcvavoid = sctp_rr_request->so_rcvavoid;
- loc_sndavoid = sctp_rr_request->so_sndavoid;
- non_block = sctp_rr_request->non_blocking;
-
- set_hostname_and_port(local_name,
- port_buffer,
- nf_to_af(sctp_rr_request->ipfamily),
- sctp_rr_request->port);
-
- local_res = complete_addrinfo(local_name,
- local_name,
- port_buffer,
- nf_to_af(sctp_rr_request->ipfamily),
- SOCK_STREAM,
- IPPROTO_SCTP,
- 0);
-
- s_listen = create_data_socket(local_res);
-
- if (s_listen < 0) {
- netperf_response.content.serv_errno = errno;
- send_response();
-
- exit(1);
- }
-
- /* 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);
- }
-
-
- /* now get the port number assigned by the system */
- addrlen = sizeof(myaddr_in);
- if (getsockname(s_listen,
- (struct sockaddr *)&myaddr_in, &addrlen) == -1){
- netperf_response.content.serv_errno = errno;
- close(s_listen);
- send_response();
-
- exit(1);
- }
-
- /* Now myaddr_in contains the port and the internet address this is */
- /* returned to the sender also implicitly telling the sender that the */
- /* socket buffer sizing has been done. */
-
- sctp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
- netperf_response.content.serv_errno = 0;
-
- /* But wait, there's more. If the initiator wanted cpu measurements, */
- /* then we must call the calibrate routine, which will return the max */
- /* rate back to the initiator. If the CPU was not to be measured, or */
- /* something went wrong with the calibration, we will return a 0.0 to */
- /* the initiator. */
-
- sctp_rr_response->cpu_rate = (float)0.0; /* assume no cpu */
- sctp_rr_response->measure_cpu = 0;
-
- if (sctp_rr_request->measure_cpu) {
- sctp_rr_response->measure_cpu = 1;
- sctp_rr_response->cpu_rate = calibrate_local_cpu(sctp_rr_request->cpu_rate);
- }
-
-
- /* before we send the response back to the initiator, pull some of */
- /* the socket parms from the globals */
- sctp_rr_response->send_buf_size = lss_size;
- sctp_rr_response->recv_buf_size = lsr_size;
- sctp_rr_response->no_delay = loc_nodelay;
- sctp_rr_response->so_rcvavoid = loc_rcvavoid;
- sctp_rr_response->so_sndavoid = loc_sndavoid;
- sctp_rr_response->test_length = sctp_rr_request->test_length;
- send_response();
-
- addrlen = sizeof(peeraddr_in);
-
- 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);
- }
-
- /* we do not need events on a 1-to-1 RR test. The test will finish
- * once all transactions are done.
- */
-
- /* now that we are connected, mark the socket as non-blocking */
- if (non_block) {
- if (!set_nonblock(s_data)) {
- perror("netperf: set_nonblock");
- exit(1);
- }
- }
-
-#ifdef KLUDGE_SOCKET_OPTIONS
- /* this is for those systems which *INCORRECTLY* fail to pass */
- /* attributes across an accept() call. Including this goes against */
- /* my better judgement :( raj 11/95 */
-
- kludge_socket_options(s_data);
-
-#endif /* KLUDGE_SOCKET_OPTIONS */
-
- if (debug) {
- fprintf(where,"recv_sctp_rr: accept completes on the data connection.\n");
- fflush(where);
- }
-
- /* Now it's time to start receiving data on the connection. We will */
- /* first grab the apropriate counters and then start grabbing. */
-
- cpu_start(sctp_rr_request->measure_cpu);
-
- /* The loop will exit when we hit the end of the test time, or when */
- /* we have exchanged the requested number of transactions. */
-
- if (sctp_rr_request->test_length > 0) {
- times_up = 0;
- trans_remaining = 0;
- start_timer(sctp_rr_request->test_length + PAD_TIME);
- }
- else {
- times_up = 1;
- trans_remaining = sctp_rr_request->test_length * -1;
- }
-
- trans_received = 0;
-
- while ((!times_up) || (trans_remaining > 0)) {
- int msg_flags = 0;
-
- temp_message_ptr = recv_ring->buffer_ptr;
- request_bytes_remaining = sctp_rr_request->request_size;
- while(!(msg_flags & MSG_EOR)) {
- if((request_bytes_recvd=sctp_recvmsg(s_data,
- temp_message_ptr,
- request_bytes_remaining,
- NULL, 0,
- NULL, &msg_flags)) < 0) {
- if (errno == EINTR) {
- /* the timer popped */
- timed_out = 1;
- break;
- } else if (non_block && errno == EAGAIN) {
- continue; /* while request_bytes_remaining */
- }
- netperf_response.content.serv_errno = errno;
- send_response();
- exit(1);
- }
- request_bytes_remaining -= request_bytes_recvd;
- temp_message_ptr += request_bytes_recvd;
- }
-
- recv_ring = recv_ring->next;
-
- if (timed_out) {
- /* we hit the end of the test based on time - lets */
- /* bail out of here now... */
- if (debug) {
- fprintf(where,"yo55\n");
- fflush(where);
- }
- break;
- }
-
-
- /* Now, send the response to the remote
- * In 1-to-1 API destination addr is not needed.
- */
- while ((bytes_sent=sctp_sendmsg(s_data,
- send_ring->buffer_ptr,
- sctp_rr_request->response_size,
- NULL, 0,
- 0, 0, 0, 0, 0)) == -1) {
- if (errno == EINTR) {
- /* the test timer has popped */
- timed_out = 1;
- break;
- } else if (non_block && errno == EAGAIN) {
- continue;
- }
-
- netperf_response.content.serv_errno = 982;
- send_response();
- exit(1);
- }
-
- if (timed_out) {
- /* we hit the end of the test based on time - lets */
- /* bail out of here now... */
- if (debug) {
- fprintf(where,"yo6\n");
- fflush(where);
- }
- break;
- }
-
- send_ring = send_ring->next;
-
- trans_received++;
- if (trans_remaining) {
- trans_remaining--;
- }
- }
-
-
- /* The loop now exits due to timeout or transaction count being */
- /* reached */
-
- cpu_stop(sctp_rr_request->measure_cpu,&elapsed_time);
-
- stop_timer();
-
- if (timed_out) {
- /* we ended the test by time, which was at least 2 seconds */
- /* longer than we wanted to run. so, we want to subtract */
- /* PAD_TIME from the elapsed_time. */
- elapsed_time -= PAD_TIME;
- }
-
- /* send the results to the sender */
-
- if (debug) {
- fprintf(where,
- "recv_sctp_rr: got %d transactions\n",
- trans_received);
- fflush(where);
- }
-
- sctp_rr_results->bytes_received = (trans_received *
- (sctp_rr_request->request_size +
- sctp_rr_request->response_size));
- sctp_rr_results->trans_received = trans_received;
- sctp_rr_results->elapsed_time = elapsed_time;
- sctp_rr_results->cpu_method = cpu_method;
- sctp_rr_results->num_cpus = lib_num_loc_cpus;
- if (sctp_rr_request->measure_cpu) {
- sctp_rr_results->cpu_util = calc_cpu_util(elapsed_time);
- }
-
- if (debug) {
- fprintf(where,
- "recv_sctp_rr: test complete, sending results.\n");
- fflush(where);
- }
-
- /* we are now done with the sockets */
- send_response();
-
- close(s_data);
- close(s_listen);
-
-}
-
-
-
-/* this routine implements the sending (netperf) side of the
- SCTP_RR_1TOMANY test */
-
-void
-send_sctp_rr_1toMany(remote_host)
- char remote_host[];
-{
-
- char *tput_title = "\
-Local /Remote\n\
-Socket Size Request Resp. Elapsed Trans.\n\
-Send Recv Size Size Time Rate \n\
-bytes Bytes bytes bytes secs. per sec \n\n";
-
- char *tput_fmt_0 =
- "%7.2f\n";
-
- char *tput_fmt_1_line_1 = "\
-%-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
- char *tput_fmt_1_line_2 = "\
-%-6d %-6d\n";
-
- char *cpu_title = "\
-Local /Remote\n\
-Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
-Send Recv Size Size Time Rate local remote local remote\n\
-bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
-
- char *cpu_fmt_0 =
- "%6.3f %c\n";
-
- char *cpu_fmt_1_line_1 = "\
-%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
-
- char *cpu_fmt_1_line_2 = "\
-%-6d %-6d\n";
-
- char *ksink_fmt = "\
-Alignment Offset\n\
-Local Remote Local Remote\n\
-Send Recv Send Recv\n\
-%5d %5d %5d %5d\n";
-
-
- int timed_out = 0;
- float elapsed_time;
-
- int len, j = 0;
- char *temp_message_ptr;
- int nummessages;
- int *send_socket;
- int trans_remaining;
- double bytes_xferd;
- int msg_flags = 0;
-
- struct ring_elt *send_ring;
- struct ring_elt *recv_ring;
-
- int rsp_bytes_left;
- int rsp_bytes_recvd;
-
- float local_cpu_utilization;
- float local_service_demand;
- float remote_cpu_utilization;
- float remote_service_demand;
- double thruput;
-
- struct sockaddr_storage peer;
- struct addrinfo *local_res;
- struct addrinfo *remote_res;
-
- struct sctp_rr_request_struct *sctp_rr_request;
- struct sctp_rr_response_struct *sctp_rr_response;
- struct sctp_rr_results_struct *sctp_rr_result;
-
-#ifdef WANT_INTERVALS
- int interval_count;
- sigset_t signal_set;
-#endif /* WANT_INTERVALS */
-
- sctp_rr_request =
- (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data;
- sctp_rr_response =
- (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data;
- sctp_rr_result =
- (struct sctp_rr_results_struct *)netperf_response.content.test_specific_data;
-
-#ifdef WANT_HISTOGRAM
- time_hist = HIST_new();
-#endif /* WANT_HISTOGRAM */
-
- /* since we are now disconnected from the code that established the */
- /* control socket, and since we want to be able to use different */
- /* protocols and such, we are passed the name of the remote host and */
- /* must turn that into the test specific addressing information. */
-
- complete_addrinfos(&remote_res,
- &local_res,
- remote_host,
- SOCK_SEQPACKET,
- IPPROTO_SCTP,
- 0);
-
- if ( print_headers ) {
- print_top_test_header("SCTP 1-TO-MANY REQUEST/RESPONSE TEST",local_res,remote_res);
- }
-
- /* initialize a few counters */
-
- send_ring = NULL;
- recv_ring = NULL;
- confidence_iteration = 1;
- init_stat();
-
- send_socket = malloc(sizeof(int) * num_associations);
- if (send_socket == NULL) {
- fprintf(where,
- "Could not create the socket array for %d associations",
- num_associations);
- fflush(where);
- exit(1);
- }
-
- /* we have a great-big while loop which controls the number of times */
- /* we run a particular test. this is for the calculation of a */
- /* confidence interval (I really should have stayed awake during */
- /* probstats :). If the user did not request confidence measurement */
- /* (no confidence is the default) then we will only go though the */
- /* loop once. the confidence stuff originates from the folks at IBM */
-
- while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
- (confidence_iteration <= iteration_min)) {
-
- /* initialize a few counters. we have to remember that we might be */
- /* going through the loop more than once. */
-
- nummessages = 0;
- bytes_xferd = 0.0;
- times_up = 0;
- timed_out = 0;
- trans_remaining = 0;
-
- /* set-up the data buffers with the requested alignment and offset. */
- /* since this is a request/response test, default the send_width and */
- /* recv_width to 1 and not two raj 7/94 */
-
- if (send_width == 0) send_width = 1;
- if (recv_width == 0) recv_width = 1;
-
- if (send_ring == NULL) {
- send_ring = allocate_buffer_ring(send_width,
- req_size,
- local_send_align,
- local_send_offset);
- }
-
- if (recv_ring == NULL) {
- recv_ring = allocate_buffer_ring(recv_width,
- rsp_size,
- local_recv_align,
- local_recv_offset);
- }
-
- /* If the user has requested cpu utilization measurements, we must */
- /* calibrate the cpu(s). We will perform this task within the tests */
- /* themselves. If the user has specified the cpu rate, then */
- /* calibrate_local_cpu will return rather quickly as it will have */
- /* nothing to do. If local_cpu_rate is zero, then we will go through */
- /* all the "normal" calibration stuff and return the rate back.*/
-
- if (local_cpu_usage) {
- local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
- }
-
- /* Tell the remote end to do a listen. The server alters the socket */
- /* paramters on the other side at this point, hence the reason for */
- /* all the values being passed in the setup message. If the user did */
- /* not specify any of the parameters, they will be passed as 0, which */
- /* will indicate to the remote that no changes beyond the system's */
- /* default should be used. Alignment is the exception, it will */
- /* default to 8, which will be no alignment alterations. */
-
- netperf_request.content.request_type = DO_SCTP_RR_MANY;
- sctp_rr_request->recv_buf_size = rsr_size_req;
- sctp_rr_request->send_buf_size = rss_size_req;
- sctp_rr_request->recv_alignment = remote_recv_align;
- sctp_rr_request->recv_offset = remote_recv_offset;
- sctp_rr_request->send_alignment = remote_send_align;
- sctp_rr_request->send_offset = remote_send_offset;
- sctp_rr_request->request_size = req_size;
- sctp_rr_request->response_size = rsp_size;
- sctp_rr_request->no_delay = rem_nodelay;
- sctp_rr_request->measure_cpu = remote_cpu_usage;
- sctp_rr_request->cpu_rate = remote_cpu_rate;
- sctp_rr_request->so_rcvavoid = rem_rcvavoid;
- sctp_rr_request->so_sndavoid = rem_sndavoid;
- if (test_time) {
- sctp_rr_request->test_length = test_time;
- }
- else {
- sctp_rr_request->test_length = test_trans * num_associations
- * -1;
- }
- sctp_rr_request->non_blocking = non_block;
- sctp_rr_request->port = atoi(remote_data_port);
- sctp_rr_request->ipfamily = af_to_nf(remote_res->ai_family);
- if (debug > 1) {
- fprintf(where,"netperf: send_sctp_rr_1toMany: requesting SCTP rr test\n");
- }
-
- send_request();
-
- /* The response from the remote will contain all of the relevant */
- /* socket parameters for this test type. We will put them back into */
- /* the variables here so they can be displayed if desired. The */
- /* remote will have calibrated CPU if necessary, and will have done */
- /* all the needed set-up we will have calibrated the cpu locally */
- /* before sending the request, and will grab the counter value right*/
- /* after the connect returns. The remote will grab the counter right*/
- /* after the accept call. This saves the hassle of extra messages */
- /* being sent for the sctp tests. */
-
- recv_response();
-
- if (!netperf_response.content.serv_errno) {
- rsr_size = sctp_rr_response->recv_buf_size;
- rss_size = sctp_rr_response->send_buf_size;
- rem_nodelay = sctp_rr_response->no_delay;
- remote_cpu_usage = sctp_rr_response->measure_cpu;
- remote_cpu_rate = sctp_rr_response->cpu_rate;
- /* make sure that port numbers are in network order */
- set_port_number(remote_res,
- (unsigned short)sctp_rr_response->data_port_number);
- }
- else {
- Set_errno(netperf_response.content.serv_errno);
- fprintf(where,
- "netperf: remote error %d",
- netperf_response.content.serv_errno);
- perror("");
- fflush(where);
-
- exit(1);
- }
-
- /*set up the data socket list */
- for (j = 0; j < num_associations; j++) {
- send_socket[j] = create_data_socket(local_res);
-
- if (send_socket < 0){
- perror("netperf: send_sctp_rr_1toMany: sctp stream data socket");
- exit(1);
- }
-
- /*Connect up to the remote port on the data socket */
- if (connect(send_socket[j],
- remote_res->ai_addr,
- remote_res->ai_addrlen) < 0){
- perror("netperf: data socket connect failed");
-
- exit(1);
- }
-
- /* The client end of the 1-to-Many test uses 1-to-1 sockets.
- * it doesn't need events.
- */
- sctp_enable_events(send_socket[j], 0);
-
- if (non_block) {
- if (!set_nonblock(send_socket[j])) {
- close(send_socket[j]);
- exit(1);
- }
- }
- }
-
- /* Data Socket set-up is finished. If there were problems, either the */
- /* connect would have failed, or the previous response would have */
- /* indicated a problem. I failed to see the value of the extra */
- /* message after the accept on the remote. If it failed, we'll see it */
- /* here. If it didn't, we might as well start pumping data. */
-
- /* 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 * num_associations;
- 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);
-
-#ifdef WANT_INTERVALS
- if ((interval_burst) || (demo_mode)) {
- /* zero means that we never pause, so we never should need the */
- /* interval timer, unless we are in demo_mode */
- start_itimer(interval_wate);
- }
- interval_count = interval_burst;
- /* get the signal set for the call to sigsuspend */
- if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
- fprintf(where,
- "send_sctp_rr_1toMany: unable to get sigmask errno %d\n",
- errno);
- fflush(where);
- exit(1);
- }
-#endif /* WANT_INTERVALS */
-
- /* 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. I think I */
- /* just arbitrarily decrement trans_remaining for the timed test, but */
- /* will not do that just yet... One other question is whether or not */
- /* the send buffer and the receive buffer should be the same buffer. */
-
-#ifdef WANT_FIRST_BURST
- {
- int i;
- for (j = 0; j < num_associations; j++) {
- for (i = 0; i < first_burst_size; i++) {
- if((len=sctp_sendmsg(send_socket[j],
- send_ring->buffer_ptr, send_size,
- remote_res->ai_addr,
- remote_res->ai_addrlen,
- 0, 0, 0, 0, 0)) != req_size) {
- /* we should never hit the end of the test in the first burst */
- perror("send_sctp_rr_1toMany: initial burst data send error");
- exit(1);
- }
- }
- }
- }
-#endif /* WANT_FIRST_BURST */
-
- 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. */
-
- /* this is a fairly poor way of testing 1toMany connections.
- * For each association we measure round trip time to account for
- * any delay in lookups and delivery. To stress the server a bit
- * more we would need a distributed client test, or at least multiple
- * processes. I want to force as much paralellism as possible, but
- * this will do for the fist take. vlad
- */
- for (j = 0; j < num_associations; j++) {
-#ifdef WANT_HISTOGRAM
- /* timestamp just before our call to send, and then again just */
- /* after the receive raj 8/94 */
- gettimeofday(&time_one,NULL);
-#endif /* WANT_HISTOGRAM */
-
- while ((len=sctp_sendmsg(send_socket[j],
- send_ring->buffer_ptr, send_size,
- remote_res->ai_addr,
- remote_res->ai_addrlen,
- 0, 0, 0, 0, 0)) != req_size) {
- if (non_block && errno == EAGAIN) {
- /* try sending again */
- continue;
- } else if ((errno == EINTR) || (errno == 0)) {
- /* we hit the end of a */
- /* timed test. */
- timed_out = 1;
- break;
- }
- perror("send_sctp_rr_1toMany: data send error");
- exit(1);
- }
-
- if (timed_out) {
- /* we may have been in a nested while loop - we need */
- /* another call to break. */
- break;
- }
-
- /* setup for the next time */
- send_ring = send_ring->next;
-
- rsp_bytes_left = rsp_size;
- temp_message_ptr = recv_ring->buffer_ptr;
- while (!(msg_flags & MSG_EOR)) {
- if((rsp_bytes_recvd = sctp_recvmsg(send_socket[j],
- temp_message_ptr,
- rsp_bytes_left,
- NULL, 0,
- NULL, &msg_flags)) < 0) {
- if (errno == EINTR) {
- /* We hit the end of a timed test. */
- timed_out = 1;
- break;
- } else if (non_block && errno == EAGAIN) {
- continue;
- }
- perror("send_sctp_rr_1toMany: 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;
- }
-
-#ifdef WANT_HISTOGRAM
- gettimeofday(&time_two,NULL);
- HIST_add(time_hist,delta_micro(&time_one,&time_two));
-#endif /* WANT_HISTOGRAM */
-
- nummessages++;
- if (trans_remaining) {
- trans_remaining--;
- }
-
- if (debug > 3) {
- if ((nummessages % 100) == 0) {
- fprintf(where,
- "Transaction %d completed\n",
- nummessages);
- fflush(where);
- }
- }
- }
- }
-
- /* At this point we used to call shutdown on the data socket to be */
- /* sure all the data was delivered, but this was not germane in a */
- /* request/response test, and it was causing the tests to "hang" when */
- /* they were being controlled by time. So, I have replaced this */
- /* shutdown call with a call to close that can be found later in the */
- /* procedure. */
-
- /* 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); /* was cpu being */
- /* measured? how long */
- /* did we really run? */
-
- /* Get the statistics from the remote end. The remote will have */
- /* calculated CPU utilization. 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 {
- Set_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 throughput was for the test. */
-
- bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
- thruput = nummessages/elapsed_time;
-
- if (local_cpu_usage || remote_cpu_usage) {
- /* We must now do a little math for service demand and cpu */
- /* utilization for the system(s) */
- /* Of course, some of the information might be bogus because */
- /* there was no idle counter in the kernel(s). We need to make */
- /* a note of this for the user's benefit...*/
- if (local_cpu_usage) {
- local_cpu_utilization = calc_cpu_util(0.0);
- /* since calc_service demand is doing ms/Kunit we will */
- /* multiply the number of transaction by 1024 to get */
- /* "good" numbers */
- local_service_demand = calc_service_demand((double) nummessages*1024,
- 0.0,
- 0.0,
- 0);
- }
- else {
- local_cpu_utilization = (float) -1.0;
- local_service_demand = (float) -1.0;
- }
-
- if (remote_cpu_usage) {
- remote_cpu_utilization = sctp_rr_result->cpu_util;
- /* since calc_service demand is doing ms/Kunit we will */
- /* multiply the number of transaction by 1024 to get */
- /* "good" numbers */
- remote_service_demand = calc_service_demand((double) nummessages*1024,
- 0.0,
- remote_cpu_utilization,
- sctp_rr_result->num_cpus);
- }
- else {
- remote_cpu_utilization = (float) -1.0;
- remote_service_demand = (float) -1.0;
- }
-
- }
- else {
- /* we were not measuring cpu, for the confidence stuff, we */
- /* should make it -1.0 */
- local_cpu_utilization = (float) -1.0;
- local_service_demand = (float) -1.0;
- remote_cpu_utilization = (float) -1.0;
- remote_service_demand = (float) -1.0;
- }
-
- /* at this point, we want to calculate the confidence information. */
- /* if debugging is on, calculate_confidence will print-out the */
- /* parameters we pass it */
-
- calculate_confidence(confidence_iteration,
- elapsed_time,
- thruput,
- local_cpu_utilization,
- remote_cpu_utilization,
- local_service_demand,
- remote_service_demand);
-
-
- confidence_iteration++;
-
- /* we are now done with the socket, so close it */
- for (j = 0; j < num_associations; j++)
- close(send_socket[j]);
- }
-
- retrieve_confident_values(&elapsed_time,
- &thruput,
- &local_cpu_utilization,
- &remote_cpu_utilization,
- &local_service_demand,
- &remote_service_demand);
-
- /* We are now ready to print all the information. If the user */
- /* has specified zero-level verbosity, we will just print the */
- /* local service demand, or the remote service demand. If the */
- /* user has requested verbosity level 1, he will get the basic */
- /* "streamperf" numbers. If the user has specified a verbosity */
- /* of greater than 1, we will display a veritable plethora of */
- /* background information from outside of this block as it it */
- /* not cpu_measurement specific... */
-
- if (confidence < 0) {
- /* we did not hit confidence, but were we asked to look for it? */
- if (iteration_max > 1) {
- display_confidence();
- }
- }
-
- if (local_cpu_usage || remote_cpu_usage) {
- local_cpu_method = format_cpu_method(cpu_method);
- remote_cpu_method = format_cpu_method(sctp_rr_result->cpu_method);
-
- switch (verbosity) {
- case 0:
- if (local_cpu_usage) {
- fprintf(where,
- cpu_fmt_0,
- local_service_demand,
- local_cpu_method);
- }
- else {
- fprintf(where,
- cpu_fmt_0,
- remote_service_demand,
- remote_cpu_method);
- }
- break;
- case 1:
- case 2:
- if (print_headers) {
- fprintf(where,
- cpu_title,
- local_cpu_method,
- remote_cpu_method);
- }
-
- fprintf(where,
- cpu_fmt_1_line_1, /* the format string */
- lss_size, /* local sendbuf size */
- lsr_size,
- req_size, /* how large were the requests */
- rsp_size, /* guess */
- elapsed_time, /* how long was the test */
- thruput,
- local_cpu_utilization, /* local cpu */
- remote_cpu_utilization, /* remote cpu */
- local_service_demand, /* local service demand */
- remote_service_demand); /* remote service demand */
- fprintf(where,
- cpu_fmt_1_line_2,
- rss_size,
- rsr_size);
- break;
- }
- }
- else {
- /* The tester did not wish to measure service demand. */
-
- switch (verbosity) {
- case 0:
- fprintf(where,
- tput_fmt_0,
- thruput);
- break;
- case 1:
- case 2:
- if (print_headers) {
- fprintf(where,tput_title,format_units());
- }
-
- fprintf(where,
- tput_fmt_1_line_1, /* the format string */
- lss_size,
- lsr_size,
- req_size, /* how large were the requests */
- rsp_size, /* how large were the responses */
- elapsed_time, /* how long did it take */
- thruput);
- fprintf(where,
- tput_fmt_1_line_2,
- rss_size, /* remote recvbuf size */
- rsr_size);
-
- break;
- }
- }
-
- /* it would be a good thing to include information about some of the */
- /* other parameters that may have been set for this test, but at the */
- /* moment, I do not wish to figure-out all the formatting, so I will */
- /* just put this comment here to help remind me that it is something */
- /* that should be done at a later time. */
-
- /* how to handle the verbose information in the presence of */
- /* confidence intervals is yet to be determined... raj 11/94 */
- if (verbosity > 1) {
- /* The user wanted to know it all, so we will give it to him. */
- /* This information will include as much as we can find about */
- /* TCP statistics, the alignments of the sends and receives */
- /* and all that sort of rot... */
-
- fprintf(where,
- ksink_fmt,
- local_send_align,
- remote_recv_offset,
- local_send_offset,
- remote_recv_offset);
-
-#ifdef WANT_HISTOGRAM
- fprintf(where,"\nHistogram of request/response times\n");
- fflush(where);
- HIST_report(time_hist);
-#endif /* WANT_HISTOGRAM */
-
- }
-
-}
-
-
- /* this routine implements the receive (netserver) side of a TCP_RR */
- /* test */
-void
-recv_sctp_rr_1toMany()
-{
-
- struct ring_elt *send_ring;
- struct ring_elt *recv_ring;
-
-
- struct sockaddr_in myaddr_in; /* needed to get the port number */
- struct sockaddr_storage peeraddr; /* to communicate with peer */
- struct addrinfo *local_res;
- char local_name[BUFSIZ];
- char port_buffer[PORTBUFSIZE];
- int msg_flags;
-
- int s_rcv;
- int addrlen;
- char *temp_message_ptr;
- int trans_received;
- int trans_remaining;
- int bytes_sent;
- int bytes_recvd;
- int recv_buf_size;
- int timed_out = 0;
- float elapsed_time;
-
- struct sctp_rr_request_struct *sctp_rr_request;
- struct sctp_rr_response_struct *sctp_rr_response;
- struct sctp_rr_results_struct *sctp_rr_results;
-
- sctp_rr_request =
- (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data;
- sctp_rr_response =
- (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data;
- sctp_rr_results =
- (struct sctp_rr_results_struct *)netperf_response.content.test_specific_data;
-
- if (debug) {
- fprintf(where,"netserver: recv_sctp_rr_1toMany: entered...\n");
- fflush(where);
- }
-
- /* We want to set-up the listen socket with all the desired */
- /* parameters and then let the initiator know that all is ready. If */
- /* socket size defaults are to be used, then the initiator will have */
- /* sent us 0's. If the socket sizes cannot be changed, then we will */
- /* send-back what they are. If that information cannot be determined, */
- /* then we send-back -1's for the sizes. If things go wrong for any */
- /* reason, we will drop back ten yards and punt. */
-
- /* If anything goes wrong, we want the remote to know about it. It */
- /* would be best if the error that the remote reports to the user is */
- /* the actual error we encountered, rather than some bogus unexpected */
- /* response type message. */
-
- if (debug) {
- fprintf(where,"recv_sctp_rr_1toMany: setting the response type...\n");
- fflush(where);
- }
-
- netperf_response.content.response_type = SCTP_RR_MANY_RESPONSE;
-
- if (debug) {
- fprintf(where,"recv_sctp_rr_1toMany: the response type is set...\n");
- fflush(where);
- }
-
- /* allocate the recv and send rings with the requested alignments */
- /* and offsets. raj 7/94 */
- if (debug) {
- fprintf(where,"recv_sctp_rr_1toMany: requested recv alignment of %d offset %d\n",
- sctp_rr_request->recv_alignment,
- sctp_rr_request->recv_offset);
- fprintf(where,"recv_sctp_rr_1toMany: requested send alignment of %d offset %d\n",
- sctp_rr_request->send_alignment,
- sctp_rr_request->send_offset);
- fflush(where);
- }
-
- /* at some point, these need to come to us from the remote system */
- if (send_width == 0) send_width = 1;
- if (recv_width == 0) recv_width = 1;
-
- send_ring = allocate_buffer_ring(send_width,
- sctp_rr_request->response_size,
- sctp_rr_request->send_alignment,
- sctp_rr_request->send_offset);
-
- recv_ring = allocate_buffer_ring(recv_width,
- sctp_rr_request->request_size,
- sctp_rr_request->recv_alignment,
- sctp_rr_request->recv_offset);
-
-
- /* create_data_socket expects to find some things in the global */
- /* variables, so set the globals based on the values in the request. */
- /* once the socket has been created, we will set the response values */
- /* based on the updated value of those globals. raj 7/94 */
- lss_size_req = sctp_rr_request->send_buf_size;
- lsr_size_req = sctp_rr_request->recv_buf_size;
- loc_nodelay = sctp_rr_request->no_delay;
- loc_rcvavoid = sctp_rr_request->so_rcvavoid;
- loc_sndavoid = sctp_rr_request->so_sndavoid;
- non_block = sctp_rr_request->non_blocking;
-
- set_hostname_and_port(local_name,
- port_buffer,
- nf_to_af(sctp_rr_request->ipfamily),
- sctp_rr_request->port);
-
- local_res = complete_addrinfo(local_name,
- local_name,
- port_buffer,
- nf_to_af(sctp_rr_request->ipfamily),
- SOCK_SEQPACKET,
- IPPROTO_SCTP,
- 0);
-
- /* Grab a socket to listen on, and then listen on it. */
- if (debug) {
- fprintf(where,"recv_sctp_rr_1toMany: grabbing a socket...\n");
- fflush(where);
- }
-
- s_rcv = create_data_socket(local_res);
-
- if (s_rcv < 0) {
- netperf_response.content.serv_errno = errno;
- send_response();
-
- exit(1);
- }
-
- /* Now, let's set-up the socket to listen for connections */
- if (listen(s_rcv, 5) == -1) {
- netperf_response.content.serv_errno = errno;
- close(s_rcv);
- send_response();
-
- exit(1);
- }
-
-
- /* now get the port number assigned by the system */
- addrlen = sizeof(myaddr_in);
- if (getsockname(s_rcv,
- (struct sockaddr *)&myaddr_in, &addrlen) == -1){
- netperf_response.content.serv_errno = errno;
- close(s_rcv);
- send_response();
-
- exit(1);
- }
-
- /* Now myaddr_in contains the port and the internet address this is */
- /* returned to the sender also implicitly telling the sender that the */
- /* socket buffer sizing has been done. */
-
- sctp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
- netperf_response.content.serv_errno = 0;
-
- /* But wait, there's more. If the initiator wanted cpu measurements, */
- /* then we must call the calibrate routine, which will return the max */
- /* rate back to the initiator. If the CPU was not to be measured, or */
- /* something went wrong with the calibration, we will return a 0.0 to */
- /* the initiator. */
-
- sctp_rr_response->cpu_rate = (float)0.0; /* assume no cpu */
- sctp_rr_response->measure_cpu = 0;
-
- if (sctp_rr_request->measure_cpu) {
- sctp_rr_response->measure_cpu = 1;
- sctp_rr_response->cpu_rate = calibrate_local_cpu(sctp_rr_request->cpu_rate);
- }
-
-
- /* before we send the response back to the initiator, pull some of */
- /* the socket parms from the globals */
- sctp_rr_response->send_buf_size = lss_size;
- sctp_rr_response->recv_buf_size = lsr_size;
- sctp_rr_response->no_delay = loc_nodelay;
- sctp_rr_response->so_rcvavoid = loc_rcvavoid;
- sctp_rr_response->so_sndavoid = loc_sndavoid;
- sctp_rr_response->test_length = sctp_rr_request->test_length;
- send_response();
-
- /* Don't need events */
- sctp_enable_events(s_rcv, 0);
-
- /* now that we are connected, mark the socket as non-blocking */
- if (non_block) {
- if (!set_nonblock(s_rcv)) {
- perror("netperf: set_nonblock");
- exit(1);
- }
- }
-
- /* FIXME: The way 1-to-Many test operates right now, we are including
- * association setup time into our measurements. The reason for this
- * is that the client creates multiple endpoints and connects each
- * endpoint to us using the connect call. On this end we simply call
- * recvmsg() to get data becuase there is no equivalen of accept() for
- * 1-to-Many API.
- * I think this is OK, but if it were to be fixed, the server side
- * would need to know how many associations are being setup and
- * have a recvmsg() loop with SCTP_ASSOC_CHANGE events waiting for
- * all the associations to be be established.
- * I am punting on this for now.
- */
-
-
- addrlen = sizeof(peeraddr);
-
- /* Now it's time to start receiving data on the connection. We will */
- /* first grab the apropriate counters and then start grabbing. */
-
- cpu_start(sctp_rr_request->measure_cpu);
-
- /* The loop will exit when we hit the end of the test time, or when */
- /* we have exchanged the requested number of transactions. */
-
- if (sctp_rr_request->test_length > 0) {
- times_up = 0;
- trans_remaining = 0;
- start_timer(sctp_rr_request->test_length + PAD_TIME);
- }
- else {
- times_up = 1;
- trans_remaining = sctp_rr_request->test_length * -1;
- }
-
- trans_received = 0;
-
- while ((!times_up) || (trans_remaining > 0)) {
-
- recv_buf_size = sctp_rr_request->request_size;
-
- /* Receive the data. We don't particularly care which association
- * the data came in on. We'll simply be doing a receive untill
- * we get and MSG_EOR flag (meaning that a single transmission was
- * received) and a send to the same address, so the RR would be for
- * the same associations.
- * We can get away with this because the client will establish all
- * the associations before transmitting any data. Any partial data
- * will not have EOR thus will we will not send a response untill
- * we get everything.
- */
-
- do {
- msg_flags = 0;
- if((bytes_recvd = sctp_recvmsg(s_rcv,
- recv_ring->buffer_ptr,
- recv_buf_size,
- (struct sockaddr *)&peeraddr, &addrlen,
- 0, &msg_flags)) == SOCKET_ERROR) {
- if (SOCKET_EINTR(bytes_recvd)) {
- /* the timer popped */
- timed_out = 1;
- break;
- } else if (non_block & errno == EAGAIN) {
- /* do recvmsg again */
- continue;
- }
- netperf_response.content.serv_errno = errno;
- send_response();
- exit(1);
- }
- } while(!(msg_flags & MSG_EOR));
-
- recv_ring = recv_ring->next;
-
- if (timed_out) {
- /* we hit the end of the test based on time - lets */
- /* bail out of here now... */
- if (debug) {
- fprintf(where,"yo5\n");
- fflush(where);
- }
- break;
- }
-
- /* Now, send the response to the remote */
- while ((bytes_sent=sctp_sendmsg(s_rcv,
- send_ring->buffer_ptr,
- sctp_rr_request->response_size,
- (struct sockaddr *)&peeraddr, addrlen,
- 0, 0, 0, 0, 0)) == SOCKET_ERROR) {
- if (SOCKET_EINTR(bytes_sent)) {
- /* the test timer has popped */
- timed_out = 1;
- break;
- } else if (non_block && errno == EAGAIN) {
- continue;
- }
-
- netperf_response.content.serv_errno = 992;
- send_response();
- exit(1);
- }
-
- if (timed_out) {
- if (debug) {
- fprintf(where,"yo6\n");
- fflush(where);
- }
- /* we hit the end of the test based on time - lets */
- /* bail out of here now... */
- break;
- }
-
- send_ring = send_ring->next;
-
- trans_received++;
- if (trans_remaining) {
- trans_remaining--;
- }
- }
-
-
- /* The loop now exits due to timeout or transaction count being */
- /* reached */
-
- cpu_stop(sctp_rr_request->measure_cpu,&elapsed_time);
-
- stop_timer();
-
- if (timed_out) {
- /* we ended the test by time, which was at least 2 seconds */
- /* longer than we wanted to run. so, we want to subtract */
- /* PAD_TIME from the elapsed_time. */
- elapsed_time -= PAD_TIME;
- }
-
- /* send the results to the sender */
-
- if (debug) {
- fprintf(where,
- "recv_sctp_rr: got %d transactions\n",
- trans_received);
- fflush(where);
- }
-
- sctp_rr_results->bytes_received = (trans_received *
- (sctp_rr_request->request_size +
- sctp_rr_request->response_size));
- sctp_rr_results->trans_received = trans_received;
- sctp_rr_results->elapsed_time = elapsed_time;
- sctp_rr_results->cpu_method = cpu_method;
- sctp_rr_results->num_cpus = lib_num_loc_cpus;
- if (sctp_rr_request->measure_cpu) {
- sctp_rr_results->cpu_util = calc_cpu_util(elapsed_time);
- }
-
- if (debug) {
- fprintf(where,
- "recv_sctp_rr: test complete, sending results.\n");
- fflush(where);
- }
-
- /* we are now done with the sockets */
- close(s_rcv);
-
- send_response();
-
-}
-
-
-void
-print_sctp_usage()
-{
-
- printf("%s",sctp_usage);
- exit(1);
-
-}
-void
-scan_sctp_args(argc, argv)
- int argc;
- char *argv[];
-
-{
-
-#define SOCKETS_ARGS "BDhH:I:L:m:M:P:r:s:S:VN:T:46"
-
- extern char *optarg; /* pointer to option string */
-
- int c;
-
- char
- arg1[BUFSIZ], /* argument holders */
- arg2[BUFSIZ];
-
- if (no_control) {
- fprintf(where,
- "The SCTP tests do not know how to deal with no control tests\n");
- exit(-1);
- }
-
- strncpy(local_data_port,"0",sizeof(local_data_port));
- strncpy(remote_data_port,"0",sizeof(remote_data_port));
-
- /* Go through all the command line arguments and break them */
- /* out. For those options that take two parms, specifying only */
- /* the first will set both to that value. Specifying only the */
- /* second will leave the first untouched. To change only the */
- /* first, use the form "first," (see the routine break_args.. */
-
- while ((c= getopt(argc, argv, SOCKETS_ARGS)) != EOF) {
- switch (c) {
- case '?':
- case '4':
- remote_data_family = AF_INET;
- local_data_family = AF_INET;
- break;
- case '6':
-#if defined(AF_INET6)
- remote_data_family = AF_INET6;
- local_data_family = AF_INET6;
-#else
- fprintf(stderr,
- "This netperf was not compiled on an IPv6 capable host!\n");
- fflush(stderr);
- exit(-1);
-#endif
- break;
- case 'h':
- print_sctp_usage();
- exit(1);
- case 'b':
-#ifdef WANT_FIRST_BURST
- first_burst_size = atoi(optarg);
-#else /* WANT_FIRST_BURST */
- printf("Initial request burst functionality not compiled-in!\n");
-#endif /* WANT_FIRST_BURST */
- break;
- case 'D':
- /* set the nodelay flag */
- loc_nodelay = 1;
- rem_nodelay = 1;
- break;
- case 'H':
- break_args_explicit(optarg,arg1,arg2);
- if (arg1[0]) {
- /* make sure we leave room for the NULL termination boys and
- girls. raj 2005-02-82 */
- remote_data_address = malloc(strlen(arg1)+1);
- strncpy(remote_data_address,arg1,strlen(arg1));
- }
- if (arg2[0])
- remote_data_family = parse_address_family(arg2);
- break;
- case 'L':
- break_args_explicit(optarg,arg1,arg2);
- if (arg1[0]) {
- /* make sure we leave room for the NULL termination boys and
- girls. raj 2005-02-82 */
- local_data_address = malloc(strlen(arg1)+1);
- strncpy(local_data_address,arg1,strlen(arg1));
- }
- if (arg2[0])
- local_data_family = parse_address_family(arg2);
- break;
- case 'P':
- /* set the local and remote data port numbers for the tests to
- allow them to run through those blankety blank end-to-end
- breaking firewalls. raj 2004-06-15 */
- break_args(optarg,arg1,arg2);
- if (arg1[0])
- strncpy(local_data_port,arg1,sizeof(local_data_port));
- if (arg2[0])
- strncpy(remote_data_port,arg2,sizeof(remote_data_port));
- break;
- case 's':
- /* set local socket sizes */
- break_args(optarg,arg1,arg2);
- if (arg1[0])
- lss_size_req = convert(arg1);
- if (arg2[0])
- lsr_size_req = convert(arg2);
- break;
- case 'S':
- /* set remote socket sizes */
- break_args(optarg,arg1,arg2);
- if (arg1[0])
- rss_size_req = convert(arg1);
- if (arg2[0])
- rsr_size_req = convert(arg2);
- break;
- case 'r':
- /* set the request/response sizes */
- break_args(optarg,arg1,arg2);
- if (arg1[0])
- req_size = convert(arg1);
- if (arg2[0])
- rsp_size = convert(arg2);
- break;
- case 'm':
- /* set size of the buffer for each sent message */
- send_size = convert(optarg);
- break;
- case 'M':
- /* set the size of the buffer for each received message */
- recv_size = convert(optarg);
- break;
- case 't':
- /* set the test name */
- strcpy(test_name,optarg);
- break;
- case 'W':
- /* set the "width" of the user space data */
- /* buffer. This will be the number of */
- /* send_size buffers malloc'd in the */
- /* *_STREAM test. It may be enhanced to set */
- /* both send and receive "widths" but for now */
- /* it is just the sending *_STREAM. */
- send_width = convert(optarg);
- break;
- case 'V':
- /* we want to do copy avoidance and will set */
- /* it for everything, everywhere, if we really */
- /* can. of course, we don't know anything */
- /* about the remote... */
-#ifdef SO_SND_COPYAVOID
- loc_sndavoid = 1;
-#else
- loc_sndavoid = 0;
- printf("Local send copy avoidance not available.\n");
-#endif
-#ifdef SO_RCV_COPYAVOID
- loc_rcvavoid = 1;
-#else
- loc_rcvavoid = 0;
- printf("Local recv copy avoidance not available.\n");
-#endif
- rem_sndavoid = 1;
- rem_rcvavoid = 1;
- break;
- case 'N':
- /* this opton allows the user to set the number of
- * messages to send. This in effect modifies the test
- * time. If we know the message size, then the we can
- * express the test time as message_size * number_messages
- */
- msg_count = convert (optarg);
- if (msg_count > 0)
- test_time = 0;
- break;
- case 'B':
- non_block = 1;
- break;
- case 'T':
- num_associations = atoi(optarg);
- if (num_associations <= 1) {
- printf("Number of SCTP associations must be >= 1\n");
- exit(1);
- }
- break;
- };
- }
-}
-
-#endif /* WANT_SCTP */