1 #ifndef lint
2 char nettest_sctp[]="\
3 @(#)nettest_sctp.c (c) Copyright 2005-2012 Hewlett-Packard Co. Version 2.6.0";
4 #else
5 #define DIRTY
6 #define WANT_HISTOGRAM
7 #define WANT_INTERVALS
8 #endif /* lint */
9
10 /****************************************************************/
11 /* */
12 /* nettest_sctp.c */
13 /* */
14 /* */
15 /* scan_sctp_args() get the sctp command line args */
16 /* */
17 /* the actual test routines... */
18 /* */
19 /* send_sctp_stream() perform a sctp stream test */
20 /* recv_sctp_stream() */
21 /* send_sctp_rr() perform a sctp request/response */
22 /* recv_sctp_rr() */
23 /* send_sctp_stream_udp() perform a sctp request/response */
24 /* recv_sctp_stream_upd() using UDP style API */
25 /* send_sctp_rr_udp() perform a sctp request/response */
26 /* recv_sctp_rr_upd() using UDP style API */
27 /* */
28 /* relies on create_data_socket in nettest_bsd.c */
29 /****************************************************************/
30
31 #if HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34
35 #if defined(WANT_SCTP)
36
37 #include <sys/types.h>
38 #include <fcntl.h>
39 #include <errno.h>
40 #include <signal.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <time.h>
44 #ifdef NOSTDLIBH
45 #include <malloc.h>
46 #else /* NOSTDLIBH */
47 #include <stdlib.h>
48 #endif /* NOSTDLIBH */
49
50 #if !defined(__VMS)
51 #include <sys/ipc.h>
52 #endif /* !defined(__VMS) */
53 #include <unistd.h>
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <netinet/tcp.h>
58 #include <netinet/sctp.h>
59 #include <arpa/inet.h>
60 #include <netdb.h>
61
62 /* would seem that not all sctp.h files define a MSG_EOF, but that
63 MSG_EOF can be the same as MSG_FIN so lets work with that
64 assumption. initial find by Jon Pedersen. raj 2006-02-01 */
65 #ifndef MSG_EOF
66 #ifdef MSG_FIN
67 #define MSG_EOF MSG_FIN
68 #else
69 #error Must have either MSG_EOF or MSG_FIN defined
70 #endif
71 #endif
72
73 #include "netlib.h"
74 #include "netsh.h"
75 /* get some of the functions from nettest_bsd.c */
76 #include "nettest_bsd.h"
77 #include "nettest_sctp.h"
78
79 #ifdef WANT_HISTOGRAM
80 #ifdef __sgi
81 #include <sys/time.h>
82 #endif /* __sgi */
83 #include "hist.h"
84 #endif /* WANT_HISTOGRAM */
85
86 #ifdef WANT_FIRST_BURST
87 extern int first_burst_size;
88 #endif /* WANT_FIRST_BURST */
89
90
91
92 /* these variables are specific to SCTP tests. declare */
93 /* them static to make them global only to this file. */
94
95 static int
96 msg_count = 0, /* number of messages to transmit on association */
97 non_block = 0, /* default to blocking sockets */
98 num_associations = 1; /* number of associations on the endpoint */
99
100 static int confidence_iteration;
101 static char local_cpu_method;
102 static char remote_cpu_method;
103
104 #ifdef WANT_HISTOGRAM
105 static HIST time_hist;
106 #endif /* WANT_HISTOGRAM */
107
108
109 char sctp_usage[] = "\n\
110 Usage: netperf [global options] -- [test options] \n\
111 \n\
112 SCTP Sockets Test Options:\n\
113 -b number Send number requests at the start of _RR tests\n\
114 -D [L][,R] Set SCTP_NODELAY locally and/or remotely\n\
115 -h Display this text\n\
116 -H name,fam Use name (or IP) and family as target of data connection\n\
117 -L name,fam Use name (or IP) and family as source of data connextion\n\
118 -m bytes Set the size of each sent message\n\
119 -M bytes Set the size of each received messages\n\
120 -P local[,remote] Set the local/remote port for the data socket\n\
121 -r req,[rsp] Set request/response sizes (_RR tests)\n\
122 -s send[,recv] Set local socket send/recv buffer sizes\n\
123 -S send[,recv] Set remote socket send/recv buffer sizes\n\
124 -V Enable copy avoidance if supported\n\
125 -N number Specifies the number of messages to send (_STREAM tests)\n\
126 -B run the test in non-blocking mode\n\
127 -T number Number of associations to create (_MANY tests)\n\
128 -4 Use AF_INET (eg IPv4) on both ends of the data conn\n\
129 -6 Use AF_INET6 (eg IPv6) on both ends of the data conn\n\
130 \n\
131 For those options taking two parms, at least one must be specified;\n\
132 specifying one value without a comma will set both parms to that\n\
133 value, specifying a value with a leading comma will set just the second\n\
134 parm, a value with a trailing comma will set just the first. To set\n\
135 each parm to unique values, specify both and separate them with a\n\
136 comma.\n";
137
138
139 /* This routine is intended to retrieve interesting aspects of tcp */
140 /* for the data connection. at first, it attempts to retrieve the */
141 /* maximum segment size. later, it might be modified to retrieve */
142 /* other information, but it must be information that can be */
143 /* retrieved quickly as it is called during the timing of the test. */
144 /* for that reason, a second routine may be created that can be */
145 /* called outside of the timing loop */
146 static
147 void
get_sctp_info(int socket,int * mss)148 get_sctp_info( int socket, int *mss )
149 {
150
151 socklen_t sock_opt_len;
152
153 if (sctp_opt_info(socket,
154 0,
155 SCTP_MAXSEG,
156 mss,
157 &sock_opt_len) < 0) {
158 lss_size = -1;
159 }
160 }
161
162
163 static
164 void
sctp_enable_events(int socket,int ev_mask)165 sctp_enable_events( int socket, int ev_mask )
166 {
167 struct sctp_event_subscribe ev;
168
169 bzero(&ev, sizeof(ev));
170
171 if (ev_mask & SCTP_SNDRCV_INFO_EV)
172 ev.sctp_data_io_event = 1;
173
174 if (ev_mask & SCTP_ASSOC_CHANGE_EV)
175 ev.sctp_association_event = 1;
176
177 if (ev_mask & SCTP_PEERADDR_CHANGE_EV)
178 ev.sctp_address_event = 1;
179
180 if (ev_mask & SCTP_SND_FAILED_EV)
181 ev.sctp_send_failure_event = 1;
182
183 if (ev_mask & SCTP_REMOTE_ERROR_EV)
184 ev.sctp_peer_error_event = 1;
185
186 if (ev_mask & SCTP_SHUTDOWN_EV)
187 ev.sctp_shutdown_event = 1;
188
189 if (ev_mask & SCTP_PD_EV)
190 ev.sctp_partial_delivery_event = 1;
191
192 if (ev_mask & SCTP_ADAPT_EV)
193 #ifdef HAVE_SCTP_ADAPTATION_LAYER_EVENT
194 ev.sctp_adaptation_layer_event = 1;
195 #else
196 ev.sctp_adaption_layer_event = 1;
197 #endif
198
199 if (setsockopt(socket,
200 IPPROTO_SCTP,
201 #ifdef SCTP_EVENTS
202 SCTP_EVENTS,
203 #else
204 SCTP_SET_EVENTS,
205 #endif
206 (const char*)&ev,
207 sizeof(ev)) != 0 ) {
208 fprintf(where,
209 "sctp_enable_event: could not set sctp events errno %d\n",
210 errno);
211 fflush(where);
212 exit(1);
213 }
214 }
215
216
217 static
218 sctp_disposition_t
sctp_process_event(int socket,void * buf)219 sctp_process_event( int socket, void *buf )
220 {
221
222 struct sctp_assoc_change *sac;
223 struct sctp_send_failed *ssf;
224 struct sctp_paddr_change *spc;
225 struct sctp_remote_error *sre;
226 union sctp_notification *snp;
227
228 snp = buf;
229
230 switch (snp->sn_header.sn_type) {
231 case SCTP_ASSOC_CHANGE:
232 if (debug) {
233 fprintf(where, "\tSCTP_ASSOC_CHANGE event, type:");
234 fflush(where);
235 }
236 sac = &snp->sn_assoc_change;
237 switch (sac->sac_type) {
238 case SCTP_COMM_UP:
239 if (debug) {
240 fprintf(where, " SCTP_COMM_UP\n");
241 fflush(where);
242 }
243 break;
244 case SCTP_RESTART:
245 if (debug) {
246 fprintf(where, " SCTP_RESTART\n");
247 fflush(where);
248 }
249 break;
250 case SCTP_CANT_STR_ASSOC:
251 if (debug) {
252 fprintf(where, " SCTP_CANT_STR_ASSOC\n");
253 fflush(where);
254 }
255 break; /* FIXME ignore above status changes */
256 case SCTP_COMM_LOST:
257 if (debug) {
258 fprintf(where, " SCTP_COMM_LOST\n");
259 fflush(where);
260 }
261 return SCTP_CLOSE;
262 case SCTP_SHUTDOWN_COMP:
263 if (debug) {
264 fprintf(where, " SCTP_SHUTDOWN_COMPLETE\n");
265 fflush(where);
266 }
267 return SCTP_CLOSE;
268 break;
269 }
270
271 case SCTP_SEND_FAILED:
272 if (debug) {
273 fprintf(where, "\tSCTP_SEND_FAILED event\n");
274 fflush(where);
275 }
276 ssf = &snp->sn_send_failed;
277 break; /* FIXME ??? ignore this for now */
278
279 case SCTP_PEER_ADDR_CHANGE:
280 if (debug) {
281 fprintf(where, "\tSCTP_PEER_ADDR_CHANGE event\n");
282 fflush(where);
283 }
284 spc = &snp->sn_paddr_change;
285 break; /* FIXME ??? ignore this for now */
286
287 case SCTP_REMOTE_ERROR:
288 if (debug) {
289 fprintf(where, "\tSCTP_REMOTE_ERROR event\n");
290 fflush(where);
291 }
292 sre = &snp->sn_remote_error;
293 break; /* FIXME ??? ignore this for now */
294 case SCTP_SHUTDOWN_EVENT:
295 if (debug) {
296 fprintf(where, "\tSCTP_SHUTDOWN event\n");
297 fflush(where);
298 }
299 return SCTP_CLOSE;
300 default:
301 fprintf(where, "unknown type: %hu\n", snp->sn_header.sn_type);
302 fflush(where);
303 break;
304 }
305 return SCTP_OK;
306 }
307
308
309
310 /* This routine implements the SCTP unidirectional data transfer test */
311 /* (a.k.a. stream) for the sockets interface. It receives its */
312 /* parameters via global variables from the shell and writes its */
313 /* output to the standard output. */
314
315
316 void
send_sctp_stream(char remote_host[])317 send_sctp_stream( char remote_host[] )
318 {
319
320 char *tput_title = "\
321 Recv Send Send \n\
322 Socket Socket Message Elapsed \n\
323 Size Size Size Time Throughput \n\
324 bytes bytes bytes secs. %s/sec \n\n";
325
326 char *tput_fmt_0 =
327 "%7.2f\n";
328
329 char *tput_fmt_1 =
330 "%6d %6d %6d %-6.2f %7.2f \n";
331
332 char *cpu_title = "\
333 Recv Send Send Utilization Service Demand\n\
334 Socket Socket Message Elapsed Send Recv Send Recv\n\
335 Size Size Size Time Throughput local remote local remote\n\
336 bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n";
337
338 char *cpu_fmt_0 =
339 "%6.3f %c\n";
340
341 char *cpu_fmt_1 =
342 "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
343
344 char *ksink_fmt = "\n\
345 Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\
346 Local Remote Local Remote Xfered Per Per\n\
347 Send Recv Send Recv Send (avg) Recv (avg)\n\
348 %5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n";
349
350 char *ksink_fmt2 = "\n\
351 Maximum\n\
352 Segment\n\
353 Size (bytes)\n\
354 %6d\n";
355
356
357 float elapsed_time;
358
359 #ifdef WANT_INTERVALS
360 int interval_count;
361 sigset_t signal_set;
362 #endif
363
364 /* what we want is to have a buffer space that is at least one */
365 /* send-size greater than our send window. this will insure that we */
366 /* are never trying to re-use a buffer that may still be in the hands */
367 /* of the transport. This buffer will be malloc'd after we have found */
368 /* the size of the local senc socket buffer. We will want to deal */
369 /* with alignment and offset concerns as well. */
370
371 #ifdef DIRTY
372 int *message_int_ptr;
373 #endif
374
375 struct ring_elt *send_ring;
376
377 int len;
378 unsigned int nummessages = 0;
379 int send_socket;
380 int bytes_remaining;
381 int sctp_mss;
382 int timed_out;
383
384 /* with links like fddi, one can send > 32 bits worth of bytes */
385 /* during a test... ;-) at some point, this should probably become a */
386 /* 64bit integral type, but those are not entirely common yet */
387 double bytes_sent = 0.0;
388
389 #ifdef DIRTY
390 int i;
391 #endif /* DIRTY */
392
393 float local_cpu_utilization;
394 float local_service_demand;
395 float remote_cpu_utilization;
396 float remote_service_demand;
397
398 double thruput;
399
400 struct addrinfo *remote_res;
401 struct addrinfo *local_res;
402
403 struct sctp_stream_request_struct *sctp_stream_request;
404 struct sctp_stream_response_struct *sctp_stream_response;
405 struct sctp_stream_results_struct *sctp_stream_result;
406
407 sctp_stream_request =
408 (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data;
409 sctp_stream_response =
410 (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data;
411 sctp_stream_result =
412 (struct sctp_stream_results_struct *)netperf_response.content.test_specific_data;
413
414 #ifdef WANT_HISTOGRAM
415 time_hist = HIST_new_n(1);
416 #endif /* WANT_HISTOGRAM */
417 /* since we are now disconnected from the code that established the */
418 /* control socket, and since we want to be able to use different */
419 /* protocols and such, we are passed the name of the remote host and */
420 /* must turn that into the test specific addressing information. */
421
422 /* complete_addrinfos will either succede or exit the process */
423 complete_addrinfos(&remote_res,
424 &local_res,
425 remote_host,
426 SOCK_STREAM,
427 IPPROTO_SCTP,
428 0);
429
430 if ( print_headers ) {
431 print_top_test_header("SCTP STREAM TEST", local_res, remote_res);
432 }
433
434 send_ring = NULL;
435 confidence_iteration = 1;
436 init_stat();
437
438 /* we have a great-big while loop which controls the number of times */
439 /* we run a particular test. this is for the calculation of a */
440 /* confidence interval (I really should have stayed awake during */
441 /* probstats :). If the user did not request confidence measurement */
442 /* (no confidence is the default) then we will only go though the */
443 /* loop once. the confidence stuff originates from the folks at IBM */
444
445 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
446 (confidence_iteration <= iteration_min)) {
447
448 /* initialize a few counters. we have to remember that we might be */
449 /* going through the loop more than once. */
450
451 nummessages = 0;
452 bytes_sent = 0.0;
453 times_up = 0;
454 timed_out = 0;
455
456 /*set up the data socket */
457 send_socket = create_data_socket(local_res);
458
459 if (send_socket == INVALID_SOCKET){
460 perror("netperf: send_sctp_stream: sctp stream data socket");
461 exit(1);
462 }
463
464 if (debug) {
465 fprintf(where,"send_sctp_stream: send_socket obtained...\n");
466 }
467
468 /* at this point, we have either retrieved the socket buffer sizes, */
469 /* or have tried to set them, so now, we may want to set the send */
470 /* size based on that (because the user either did not use a -m */
471 /* option, or used one with an argument of 0). If the socket buffer */
472 /* size is not available, we will set the send size to 4KB - no */
473 /* particular reason, just arbitrary... */
474 if (send_size == 0) {
475 if (lss_size > 0) {
476 send_size = lss_size;
477 }
478 else {
479 send_size = 4096;
480 }
481 }
482
483 /* set-up the data buffer ring with the requested alignment and offset. */
484 /* note also that we have allocated a quantity */
485 /* of memory that is at least one send-size greater than our socket */
486 /* buffer size. We want to be sure that there are at least two */
487 /* buffers allocated - this can be a bit of a problem when the */
488 /* send_size is bigger than the socket size, so we must check... the */
489 /* user may have wanted to explicitly set the "width" of our send */
490 /* buffers, we should respect that wish... */
491 if (send_width == 0) {
492 send_width = (lss_size/send_size) + 1;
493 if (send_width == 1) send_width++;
494 }
495
496 if (send_ring == NULL) {
497 /* only allocate the send ring once. this is a networking test, */
498 /* not a memory allocation test. this way, we do not need a */
499 /* deallocate_buffer_ring() routine, and I don't feel like */
500 /* writing one anyway :) raj 11/94 */
501 send_ring = allocate_buffer_ring(send_width,
502 send_size,
503 local_send_align,
504 local_send_offset);
505 }
506
507 /* If the user has requested cpu utilization measurements, we must */
508 /* calibrate the cpu(s). We will perform this task within the tests */
509 /* themselves. If the user has specified the cpu rate, then */
510 /* calibrate_local_cpu will return rather quickly as it will have */
511 /* nothing to do. If local_cpu_rate is zero, then we will go through */
512 /* all the "normal" calibration stuff and return the rate back. */
513
514 if (local_cpu_usage) {
515 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
516 }
517
518 /* Tell the remote end to do a listen. The server alters the socket */
519 /* paramters on the other side at this point, hence the reason for */
520 /* all the values being passed in the setup message. If the user did */
521 /* not specify any of the parameters, they will be passed as 0, which */
522 /* will indicate to the remote that no changes beyond the system's */
523 /* default should be used. Alignment is the exception, it will */
524 /* default to 1, which will be no alignment alterations. */
525
526 netperf_request.content.request_type = DO_SCTP_STREAM;
527 sctp_stream_request->send_buf_size = rss_size_req;
528 sctp_stream_request->recv_buf_size = rsr_size_req;
529 sctp_stream_request->receive_size = recv_size;
530 sctp_stream_request->no_delay = rem_nodelay;
531 sctp_stream_request->recv_alignment = remote_recv_align;
532 sctp_stream_request->recv_offset = remote_recv_offset;
533 sctp_stream_request->measure_cpu = remote_cpu_usage;
534 sctp_stream_request->cpu_rate = remote_cpu_rate;
535 if (test_time) {
536 sctp_stream_request->test_length = test_time;
537 }
538 else {
539 if (msg_count)
540 test_bytes = send_size * msg_count;
541
542 sctp_stream_request->test_length = test_bytes;
543 }
544 sctp_stream_request->so_rcvavoid = rem_rcvavoid;
545 sctp_stream_request->so_sndavoid = rem_sndavoid;
546 #ifdef DIRTY
547 sctp_stream_request->dirty_count = rem_dirty_count;
548 sctp_stream_request->clean_count = rem_clean_count;
549 #endif /* DIRTY */
550 sctp_stream_request->port = htonl(atoi(remote_data_port));
551 sctp_stream_request->ipfamily = af_to_nf(remote_res->ai_family);
552 sctp_stream_request->non_blocking = non_block;
553
554
555 if (debug > 1) {
556 fprintf(where,
557 "netperf: send_sctp_stream: requesting sctp stream test\n");
558 }
559
560 send_request();
561
562 /* The response from the remote will contain all of the relevant */
563 /* socket parameters for this test type. We will put them back into */
564 /* the variables here so they can be displayed if desired. The */
565 /* remote will have calibrated CPU if necessary, and will have done */
566 /* all the needed set-up we will have calibrated the cpu locally */
567 /* before sending the request, and will grab the counter value right*/
568 /* after the connect returns. The remote will grab the counter right*/
569 /* after the accept call. This saves the hassle of extra messages */
570 /* being sent for the sctp tests. */
571
572 recv_response();
573
574 if (!netperf_response.content.serv_errno) {
575 if (debug)
576 fprintf(where,"remote listen done.\n");
577 rsr_size = sctp_stream_response->recv_buf_size;
578 rss_size = sctp_stream_response->send_buf_size;
579 rem_nodelay = sctp_stream_response->no_delay;
580 remote_cpu_usage= sctp_stream_response->measure_cpu;
581 remote_cpu_rate = sctp_stream_response->cpu_rate;
582
583 /* we have to make sure that the server port number is in */
584 /* network order */
585 set_port_number(remote_res, (short)sctp_stream_response->data_port_number);
586
587 rem_rcvavoid = sctp_stream_response->so_rcvavoid;
588 rem_sndavoid = sctp_stream_response->so_sndavoid;
589 }
590 else {
591 Set_errno(netperf_response.content.serv_errno);
592 fprintf(where,
593 "netperf: remote error %d",
594 netperf_response.content.serv_errno);
595 perror("");
596 fflush(where);
597
598 exit(1);
599 }
600
601 /*Connect up to the remote port on the data socket */
602 if (connect(send_socket,
603 remote_res->ai_addr,
604 remote_res->ai_addrlen) == INVALID_SOCKET) {
605 perror("netperf: send_sctp_stream: data socket connect failed");
606 exit(1);
607 }
608
609 sctp_enable_events(send_socket, SCTP_ASSOC_CHANGE_EV);
610
611 if (non_block) {
612 /* now that we are connected, mark the socket as non-blocking */
613 if (!set_nonblock(send_socket)) {
614 perror("netperf: fcntl");
615 exit(1);
616 }
617 }
618
619 /* Data Socket set-up is finished. If there were problems, either */
620 /* the connect would have failed, or the previous response would */
621 /* have indicated a problem. I failed to see the value of the */
622 /* extra message after the accept on the remote. If it failed, */
623 /* we'll see it here. If it didn't, we might as well start pumping */
624 /* data. */
625
626 /* Set-up the test end conditions. For a stream test, they can be */
627 /* either time or byte-count based. */
628
629 if (test_time) {
630 /* The user wanted to end the test after a period of time. */
631 times_up = 0;
632 bytes_remaining = 0;
633 /* in previous revisions, we had the same code repeated throught */
634 /* all the test suites. this was unnecessary, and meant more */
635 /* work for me when I wanted to switch to POSIX signals, so I */
636 /* have abstracted this out into a routine in netlib.c. if you */
637 /* are experiencing signal problems, you might want to look */
638 /* there. raj 11/94 */
639 start_timer(test_time);
640 }
641 else {
642 /* The tester wanted to send a number of bytes. */
643 bytes_remaining = test_bytes;
644 times_up = 1;
645 }
646
647 /* The cpu_start routine will grab the current time and possibly */
648 /* value of the idle counter for later use in measuring cpu */
649 /* utilization and/or service demand and thruput. */
650
651 cpu_start(local_cpu_usage);
652
653 #ifdef WANT_INTERVALS
654 if ((interval_burst) || (demo_mode)) {
655 /* zero means that we never pause, so we never should need the */
656 /* interval timer, unless we are in demo_mode */
657 start_itimer(interval_wate);
658 }
659 interval_count = interval_burst;
660 /* get the signal set for the call to sigsuspend */
661 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
662 fprintf(where,
663 "send_sctp_stream: unable to get sigmask errno %d\n",
664 errno);
665 fflush(where);
666 exit(1);
667 }
668 #endif /* WANT_INTERVALS */
669
670 #ifdef DIRTY
671 /* initialize the random number generator for putting dirty stuff */
672 /* into the send buffer. raj */
673 srand((int) getpid());
674 #endif
675
676 /* before we start, initialize a few variables */
677
678 /* We use an "OR" to control test execution. When the test is */
679 /* controlled by time, the byte count check will always return false. */
680 /* When the test is controlled by byte count, the time test will */
681 /* always return false. When the test is finished, the whole */
682 /* expression will go false and we will stop sending data. */
683
684 while ((!times_up) || (bytes_remaining > 0)) {
685
686 #ifdef DIRTY
687 /* we want to dirty some number of consecutive integers in the buffer */
688 /* we are about to send. we may also want to bring some number of */
689 /* them cleanly into the cache. The clean ones will follow any dirty */
690 /* ones into the cache. at some point, we might want to replace */
691 /* the rand() call with something from a table to reduce our call */
692 /* overhead during the test, but it is not a high priority item. */
693 message_int_ptr = (int *)(send_ring->buffer_ptr);
694 for (i = 0; i < loc_dirty_count; i++) {
695 *message_int_ptr = rand();
696 message_int_ptr++;
697 }
698 for (i = 0; i < loc_clean_count; i++) {
699 loc_dirty_count = *message_int_ptr;
700 message_int_ptr++;
701 }
702 #endif /* DIRTY */
703
704 #ifdef WANT_HISTOGRAM
705 /* timestamp just before we go into send and then again just after */
706 /* we come out raj 8/94 */
707 HIST_timestamp_start(time_hist);
708 #endif /* WANT_HISTOGRAM */
709
710 while ((len=sctp_sendmsg(send_socket,
711 send_ring->buffer_ptr, send_size,
712 NULL, 0,
713 0, 0, 0, 0, 0)) != send_size) {
714 if (non_block && errno == EAGAIN)
715 continue;
716 else if ((len >=0) || SOCKET_EINTR(len)) {
717 /* the test was interrupted, must be the end of test */
718 timed_out = 1;
719 break;
720 }
721 perror("netperf: data send error");
722 printf("len was %d\n",len);
723 exit(1);
724 }
725
726 if (timed_out)
727 break; /* we timed out durint sendmsg, done with test */
728
729 #ifdef WANT_HISTOGRAM
730 /* timestamp the exit from the send call and update the histogram */
731 HIST_timestamp_stop_add(time_hist);
732 #endif /* WANT_HISTOGRAM */
733
734 #ifdef WANT_INTERVALS
735 if (demo_mode) {
736 units_this_tick += send_size;
737 }
738 /* in this case, the interval count is the count-down couter */
739 /* to decide to sleep for a little bit */
740 if ((interval_burst) && (--interval_count == 0)) {
741 /* call sigsuspend and wait for the interval timer to get us */
742 /* out */
743 if (debug > 1) {
744 fprintf(where,"about to suspend\n");
745 fflush(where);
746 }
747 if (sigsuspend(&signal_set) == EFAULT) {
748 fprintf(where,
749 "send_sctp_stream: fault with sigsuspend.\n");
750 fflush(where);
751 exit(1);
752 }
753 interval_count = interval_burst;
754 }
755 #endif /* WANT_INTERVALS */
756
757 /* now we want to move our pointer to the next position in the */
758 /* data buffer...we may also want to wrap back to the "beginning" */
759 /* of the bufferspace, so we will mod the number of messages sent */
760 /* by the send width, and use that to calculate the offset to add */
761 /* to the base pointer. */
762 nummessages++;
763 send_ring = send_ring->next;
764 if (bytes_remaining) {
765 bytes_remaining -= send_size;
766 }
767 }
768
769 /* The test is over. Flush the buffers to the remote end. We do a */
770 /* graceful release to insure that all data has been taken by the */
771 /* remote. */
772
773 /* but first, if the verbosity is greater than 1, find-out what */
774 /* the sctp maximum segment_size was (if possible) */
775 if (verbosity > 1) {
776 sctp_mss = -1;
777 get_sctp_info(send_socket, &sctp_mss);
778 }
779
780 shutdown(send_socket, SHUT_WR);
781
782 /* The test server will signal to us when it wants to shutdown.
783 * In blocking mode, we can call recvmsg. In non-blocking
784 * mode, we need to select on the socket for reading.
785 * We'll assume that all returns are succefull
786 */
787 if (non_block) {
788 fd_set readfds;
789
790 FD_ZERO(&readfds);
791 FD_SET(send_socket, &readfds);
792 select(send_socket+1, &readfds, NULL, NULL, NULL);
793 } else {
794 sctp_recvmsg(send_socket, send_ring->buffer_ptr, send_size, NULL,
795 0, NULL, 0);
796 }
797
798 /* this call will always give us the elapsed time for the test, and */
799 /* will also store-away the necessaries for cpu utilization */
800
801 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
802 /* measured and how */
803 /* long did we really */
804 /* run? */
805
806 /* we are finished with the socket, so close it to prevent hitting */
807 /* the limit on maximum open files. */
808 close(send_socket);
809
810 /* Get the statistics from the remote end. The remote will have */
811 /* calculated service demand and all those interesting things. If it */
812 /* wasn't supposed to care, it will return obvious values. */
813
814 recv_response();
815 if (!netperf_response.content.serv_errno) {
816 if (debug)
817 fprintf(where,"remote results obtained\n");
818 }
819 else {
820 Set_errno(netperf_response.content.serv_errno);
821 fprintf(where,
822 "netperf: remote error %d",
823 netperf_response.content.serv_errno);
824 perror("");
825 fflush(where);
826
827 exit(1);
828 }
829
830 /* We now calculate what our thruput was for the test. In the future, */
831 /* we may want to include a calculation of the thruput measured by */
832 /* the remote, but it should be the case that for a sctp stream test, */
833 /* that the two numbers should be *very* close... We calculate */
834 /* bytes_sent regardless of the way the test length was controlled. */
835 /* If it was time, we needed to, and if it was by bytes, the user may */
836 /* have specified a number of bytes that wasn't a multiple of the */
837 /* send_size, so we really didn't send what he asked for ;-) */
838
839 bytes_sent = ntohd(sctp_stream_result->bytes_received);
840
841 thruput = (double) calc_thruput(bytes_sent);
842
843 if (local_cpu_usage || remote_cpu_usage) {
844 /* We must now do a little math for service demand and cpu */
845 /* utilization for the system(s) */
846 /* Of course, some of the information might be bogus because */
847 /* there was no idle counter in the kernel(s). We need to make */
848 /* a note of this for the user's benefit...*/
849 if (local_cpu_usage) {
850
851 local_cpu_utilization = calc_cpu_util(0.0);
852 local_service_demand = calc_service_demand(bytes_sent,
853 0.0,
854 0.0,
855 0);
856 }
857 else {
858 local_cpu_utilization = (float) -1.0;
859 local_service_demand = (float) -1.0;
860 }
861
862 if (remote_cpu_usage) {
863
864 remote_cpu_utilization = sctp_stream_result->cpu_util;
865 remote_service_demand = calc_service_demand(bytes_sent,
866 0.0,
867 remote_cpu_utilization,
868 sctp_stream_result->num_cpus);
869 }
870 else {
871 remote_cpu_utilization = (float) -1.0;
872 remote_service_demand = (float) -1.0;
873 }
874 }
875 else {
876 /* we were not measuring cpu, for the confidence stuff, we */
877 /* should make it -1.0 */
878 local_cpu_utilization = (float) -1.0;
879 local_service_demand = (float) -1.0;
880 remote_cpu_utilization = (float) -1.0;
881 remote_service_demand = (float) -1.0;
882 }
883
884 /* at this point, we want to calculate the confidence information. */
885 /* if debugging is on, calculate_confidence will print-out the */
886 /* parameters we pass it */
887
888 calculate_confidence(confidence_iteration,
889 elapsed_time,
890 thruput,
891 local_cpu_utilization,
892 remote_cpu_utilization,
893 local_service_demand,
894 remote_service_demand);
895
896
897 confidence_iteration++;
898 }
899
900 /* at this point, we have finished making all the runs that we */
901 /* will be making. so, we should extract what the calcuated values */
902 /* are for all the confidence stuff. we could make the values */
903 /* global, but that seemed a little messy, and it did not seem worth */
904 /* all the mucking with header files. so, we create a routine much */
905 /* like calcualte_confidence, which just returns the mean values. */
906 /* raj 11/94 */
907
908 retrieve_confident_values(&elapsed_time,
909 &thruput,
910 &local_cpu_utilization,
911 &remote_cpu_utilization,
912 &local_service_demand,
913 &remote_service_demand);
914
915 /* We are now ready to print all the information. If the user */
916 /* has specified zero-level verbosity, we will just print the */
917 /* local service demand, or the remote service demand. If the */
918 /* user has requested verbosity level 1, he will get the basic */
919 /* "streamperf" numbers. If the user has specified a verbosity */
920 /* of greater than 1, we will display a veritable plethora of */
921 /* background information from outside of this block as it it */
922 /* not cpu_measurement specific... */
923
924 if (confidence < 0) {
925 /* we did not hit confidence, but were we asked to look for it? */
926 if (iteration_max > 1) {
927 display_confidence();
928 }
929 }
930
931 if (local_cpu_usage || remote_cpu_usage) {
932 local_cpu_method = format_cpu_method(cpu_method);
933 remote_cpu_method = format_cpu_method(sctp_stream_result->cpu_method);
934
935 switch (verbosity) {
936 case 0:
937 if (local_cpu_usage) {
938 fprintf(where,
939 cpu_fmt_0,
940 local_service_demand,
941 local_cpu_method);
942 }
943 else {
944 fprintf(where,
945 cpu_fmt_0,
946 remote_service_demand,
947 remote_cpu_method);
948 }
949 break;
950 case 1:
951 case 2:
952 if (print_headers) {
953 fprintf(where,
954 cpu_title,
955 format_units(),
956 local_cpu_method,
957 remote_cpu_method);
958 }
959
960 fprintf(where,
961 cpu_fmt_1, /* the format string */
962 rsr_size, /* remote recvbuf size */
963 lss_size, /* local sendbuf size */
964 send_size, /* how large were the sends */
965 elapsed_time, /* how long was the test */
966 thruput, /* what was the xfer rate */
967 local_cpu_utilization, /* local cpu */
968 remote_cpu_utilization, /* remote cpu */
969 local_service_demand, /* local service demand */
970 remote_service_demand); /* remote service demand */
971 break;
972 }
973 }
974 else {
975 /* The tester did not wish to measure service demand. */
976
977 switch (verbosity) {
978 case 0:
979 fprintf(where,
980 tput_fmt_0,
981 thruput);
982 break;
983 case 1:
984 case 2:
985 if (print_headers) {
986 fprintf(where,tput_title,format_units());
987 }
988 fprintf(where,
989 tput_fmt_1, /* the format string */
990 rsr_size, /* remote recvbuf size */
991 lss_size, /* local sendbuf size */
992 send_size, /* how large were the sends */
993 elapsed_time, /* how long did it take */
994 thruput);/* how fast did it go */
995 break;
996 }
997 }
998
999 /* it would be a good thing to include information about some of the */
1000 /* other parameters that may have been set for this test, but at the */
1001 /* moment, I do not wish to figure-out all the formatting, so I will */
1002 /* just put this comment here to help remind me that it is something */
1003 /* that should be done at a later time. */
1004
1005 if (verbosity > 1) {
1006 /* The user wanted to know it all, so we will give it to him. */
1007 /* This information will include as much as we can find about */
1008 /* sctp statistics, the alignments of the sends and receives */
1009 /* and all that sort of rot... */
1010
1011 /* this stuff needs to be worked-out in the presence of confidence */
1012 /* intervals and multiple iterations of the test... raj 11/94 */
1013
1014 fprintf(where,
1015 ksink_fmt,
1016 "Bytes",
1017 "Bytes",
1018 "Bytes",
1019 local_send_align,
1020 remote_recv_align,
1021 local_send_offset,
1022 remote_recv_offset,
1023 bytes_sent,
1024 bytes_sent / (double)nummessages,
1025 nummessages,
1026 bytes_sent / (double)sctp_stream_result->recv_calls,
1027 sctp_stream_result->recv_calls);
1028 fprintf(where,
1029 ksink_fmt2,
1030 sctp_mss);
1031 fflush(where);
1032 #ifdef WANT_HISTOGRAM
1033 fprintf(where,"\n\nHistogram of time spent in send() call.\n");
1034 fflush(where);
1035 HIST_report(time_hist);
1036 #endif /* WANT_HISTOGRAM */
1037 }
1038
1039 }
1040
1041
1042
1043
1044 /* This is the server-side routine for the sctp stream test. It is */
1045 /* implemented as one routine. I could break things-out somewhat, but */
1046 /* didn't feel it was necessary. */
1047
1048 void
recv_sctp_stream(void)1049 recv_sctp_stream( void )
1050 {
1051
1052 struct sockaddr_in myaddr_in; /* needed to get port number */
1053 struct sockaddr_storage peeraddr; /* used in accept */
1054 int s_listen,s_data;
1055 socklen_t addrlen;
1056 int len;
1057 unsigned int receive_calls;
1058 float elapsed_time;
1059 double bytes_received;
1060
1061 struct ring_elt *recv_ring;
1062
1063 struct addrinfo *local_res;
1064 char local_name[BUFSIZ];
1065 char port_buffer[PORTBUFSIZE];
1066 int msg_flags = 0;
1067
1068 #ifdef DIRTY
1069 int *message_int_ptr;
1070 int dirty_count;
1071 int clean_count;
1072 int i;
1073 #endif
1074
1075 #ifdef DO_SELECT
1076 fd_set readfds;
1077 struct timeval timeout;
1078 #endif /* DO_SELECT */
1079
1080 struct sctp_stream_request_struct *sctp_stream_request;
1081 struct sctp_stream_response_struct *sctp_stream_response;
1082 struct sctp_stream_results_struct *sctp_stream_results;
1083
1084 #ifdef DO_SELECT
1085 FD_ZERO(&readfds);
1086 timeout.tv_sec = 1;
1087 timeout.tv_usec = 0;
1088 #endif /* DO_SELECT */
1089
1090 sctp_stream_request =
1091 (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data;
1092 sctp_stream_response =
1093 (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data;
1094 sctp_stream_results =
1095 (struct sctp_stream_results_struct *)netperf_response.content.test_specific_data;
1096
1097 if (debug) {
1098 fprintf(where,"netserver: recv_sctp_stream: entered...\n");
1099 fflush(where);
1100 }
1101
1102 /* We want to set-up the listen socket with all the desired */
1103 /* parameters and then let the initiator know that all is ready. If */
1104 /* socket size defaults are to be used, then the initiator will have */
1105 /* sent us 0's. If the socket sizes cannot be changed, then we will */
1106 /* send-back what they are. If that information cannot be determined, */
1107 /* then we send-back -1's for the sizes. If things go wrong for any */
1108 /* reason, we will drop back ten yards and punt. */
1109
1110 /* If anything goes wrong, we want the remote to know about it. It */
1111 /* would be best if the error that the remote reports to the user is */
1112 /* the actual error we encountered, rather than some bogus unexpected */
1113 /* response type message. */
1114
1115 if (debug) {
1116 fprintf(where,"recv_sctp_stream: setting the response type...\n");
1117 fflush(where);
1118 }
1119
1120 netperf_response.content.response_type = SCTP_STREAM_RESPONSE;
1121
1122 if (debug) {
1123 fprintf(where,"recv_sctp_stream: the response type is set...\n");
1124 fflush(where);
1125 }
1126
1127 /* We now alter the message_ptr variable to be at the desired */
1128 /* alignment with the desired offset. */
1129
1130 if (debug) {
1131 fprintf(where,"recv_sctp_stream: requested alignment of %d\n",
1132 sctp_stream_request->recv_alignment);
1133 fflush(where);
1134 }
1135
1136 /* create_data_socket expects to find some things in the global */
1137 /* variables, so set the globals based on the values in the request. */
1138 /* once the socket has been created, we will set the response values */
1139 /* based on the updated value of those globals. raj 7/94 */
1140 lss_size_req = sctp_stream_request->send_buf_size;
1141 lsr_size_req = sctp_stream_request->recv_buf_size;
1142 loc_nodelay = sctp_stream_request->no_delay;
1143 loc_rcvavoid = sctp_stream_request->so_rcvavoid;
1144 loc_sndavoid = sctp_stream_request->so_sndavoid;
1145 non_block = sctp_stream_request->non_blocking;
1146
1147 set_hostname_and_port(local_name,
1148 port_buffer,
1149 nf_to_af(sctp_stream_request->ipfamily),
1150 sctp_stream_request->port);
1151
1152 local_res = complete_addrinfo(local_name,
1153 local_name,
1154 port_buffer,
1155 nf_to_af(sctp_stream_request->ipfamily),
1156 SOCK_STREAM,
1157 IPPROTO_SCTP,
1158 0);
1159
1160 s_listen = create_data_socket(local_res);
1161
1162 if (s_listen < 0) {
1163 netperf_response.content.serv_errno = errno;
1164 send_response();
1165 exit(1);
1166 }
1167
1168 /* what sort of sizes did we end-up with? */
1169 if (sctp_stream_request->receive_size == 0) {
1170 if (lsr_size > 0) {
1171 recv_size = lsr_size;
1172 }
1173 else {
1174 recv_size = 4096;
1175 }
1176 }
1177 else {
1178 recv_size = sctp_stream_request->receive_size;
1179 }
1180
1181 /* we want to set-up our recv_ring in a manner analagous to what we */
1182 /* do on the sending side. this is more for the sake of symmetry */
1183 /* than for the needs of say copy avoidance, but it might also be */
1184 /* more realistic - this way one could conceivably go with a */
1185 /* double-buffering scheme when taking the data an putting it into */
1186 /* the filesystem or something like that. raj 7/94 */
1187
1188 if (recv_width == 0) {
1189 recv_width = (lsr_size/recv_size) + 1;
1190 if (recv_width == 1) recv_width++;
1191 }
1192
1193 recv_ring = allocate_buffer_ring(recv_width,
1194 recv_size,
1195 sctp_stream_request->recv_alignment,
1196 sctp_stream_request->recv_offset);
1197
1198 if (debug) {
1199 fprintf(where,"recv_sctp_stream: set recv_size = %d, align = %d, offset = %d.\n",
1200 recv_size, sctp_stream_request->recv_alignment,
1201 sctp_stream_request->recv_offset);
1202 fflush(where);
1203 }
1204
1205 /* now get the port number assigned by the system */
1206 addrlen = sizeof(myaddr_in);
1207 if (getsockname(s_listen,
1208 (struct sockaddr *)&myaddr_in,
1209 &addrlen) == -1){
1210 netperf_response.content.serv_errno = errno;
1211 close(s_listen);
1212 send_response();
1213
1214 exit(1);
1215 }
1216
1217 /* Now myaddr_in contains the port and the internet address this is */
1218 /* returned to the sender also implicitly telling the sender that the */
1219 /* socket buffer sizing has been done. */
1220
1221 sctp_stream_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
1222 netperf_response.content.serv_errno = 0;
1223
1224 /* But wait, there's more. If the initiator wanted cpu measurements, */
1225 /* then we must call the calibrate routine, which will return the max */
1226 /* rate back to the initiator. If the CPU was not to be measured, or */
1227 /* something went wrong with the calibration, we will return a -1 to */
1228 /* the initiator. */
1229
1230 sctp_stream_response->cpu_rate = (float)0.0; /* assume no cpu */
1231 if (sctp_stream_request->measure_cpu) {
1232 sctp_stream_response->measure_cpu = 1;
1233 sctp_stream_response->cpu_rate =
1234 calibrate_local_cpu(sctp_stream_request->cpu_rate);
1235 }
1236 else {
1237 sctp_stream_response->measure_cpu = 0;
1238 }
1239
1240 /* before we send the response back to the initiator, pull some of */
1241 /* the socket parms from the globals */
1242 sctp_stream_response->send_buf_size = lss_size;
1243 sctp_stream_response->recv_buf_size = lsr_size;
1244 sctp_stream_response->no_delay = loc_nodelay;
1245 sctp_stream_response->so_rcvavoid = loc_rcvavoid;
1246 sctp_stream_response->so_sndavoid = loc_sndavoid;
1247 sctp_stream_response->receive_size = recv_size;
1248
1249 /* Now, let's set-up the socket to listen for connections */
1250 if (listen(s_listen, 5) == -1) {
1251 netperf_response.content.serv_errno = errno;
1252 close(s_listen);
1253 send_response();
1254
1255 exit(1);
1256 }
1257
1258 send_response();
1259
1260 addrlen = sizeof(peeraddr);
1261
1262 if ((s_data = accept(s_listen,
1263 (struct sockaddr *)&peeraddr,
1264 &addrlen)) == INVALID_SOCKET) {
1265 /* Let's just punt. The remote will be given some information */
1266 close(s_listen);
1267 exit(1);
1268 }
1269
1270 sctp_enable_events(s_data, SCTP_ASSOC_CHANGE_EV | SCTP_SHUTDOWN_EV);
1271
1272 /* now that we are connected, mark the socket as non-blocking */
1273 if (non_block) {
1274 fprintf(where, "setting socket as nonblocking\n");
1275 fflush(where);
1276 if (!set_nonblock(s_data)) {
1277 close(s_data);
1278 exit(1);
1279 }
1280 }
1281
1282 #ifdef KLUDGE_SOCKET_OPTIONS
1283 /* this is for those systems which *INCORRECTLY* fail to pass */
1284 /* attributes across an accept() call. Including this goes against */
1285 /* my better judgement :( raj 11/95 */
1286
1287 kludge_socket_options(s_data);
1288
1289 #endif /* KLUDGE_SOCKET_OPTIONS */
1290
1291 /* Now it's time to start receiving data on the connection. We will */
1292 /* first grab the apropriate counters and then start grabbing. */
1293
1294 cpu_start(sctp_stream_request->measure_cpu);
1295
1296 /* The loop will exit when the sender does a shutdown, which will */
1297 /* return a length of zero */
1298
1299 #ifdef DIRTY
1300 /* we want to dirty some number of consecutive integers in the buffer */
1301 /* we are about to recv. we may also want to bring some number of */
1302 /* them cleanly into the cache. The clean ones will follow any dirty */
1303 /* ones into the cache. */
1304
1305 dirty_count = sctp_stream_request->dirty_count;
1306 clean_count = sctp_stream_request->clean_count;
1307 message_int_ptr = (int *)recv_ring->buffer_ptr;
1308 for (i = 0; i < dirty_count; i++) {
1309 *message_int_ptr = rand();
1310 message_int_ptr++;
1311 }
1312 for (i = 0; i < clean_count; i++) {
1313 dirty_count = *message_int_ptr;
1314 message_int_ptr++;
1315 }
1316 #endif /* DIRTY */
1317
1318 bytes_received = 0;
1319 receive_calls = 0;
1320
1321 while ((len = sctp_recvmsg(s_data,
1322 recv_ring->buffer_ptr, recv_size,
1323 NULL, 0, NULL, &msg_flags)) != 0) {
1324 if (len == SOCKET_ERROR) {
1325 if (non_block && errno == EAGAIN) {
1326 if (debug){
1327 fprintf(where,
1328 "recv_sctp_stream: sctp_recvmsg timed out, trying again\n");
1329 fflush(where);
1330 }
1331 Set_errno(0);
1332 continue;
1333 }
1334 if (debug) {
1335 fprintf(where,
1336 "recv_sctp_stream: sctp_recvmsg error %d, exiting",
1337 errno);
1338 fflush(where);
1339 }
1340 netperf_response.content.serv_errno = errno;
1341 send_response();
1342 close(s_data);
1343 exit(1);
1344 }
1345
1346 if (msg_flags & MSG_NOTIFICATION) {
1347 msg_flags = 0;
1348 if (debug) {
1349 fprintf(where,
1350 "recv_sctp_stream: Got notification... processing\n");
1351 fflush(where);
1352 }
1353 if (sctp_process_event(s_data, recv_ring->buffer_ptr) == SCTP_CLOSE)
1354 break; /* break out of the recvmsg loop */
1355
1356 continue;
1357 }
1358
1359 bytes_received += len;
1360 receive_calls++;
1361
1362 /* more to the next buffer in the recv_ring */
1363 recv_ring = recv_ring->next;
1364
1365 #ifdef PAUSE
1366 sleep(1);
1367 #endif /* PAUSE */
1368
1369 #ifdef DIRTY
1370 message_int_ptr = (int *)(recv_ring->buffer_ptr);
1371 for (i = 0; i < dirty_count; i++) {
1372 *message_int_ptr = rand();
1373 message_int_ptr++;
1374 }
1375 for (i = 0; i < clean_count; i++) {
1376 dirty_count = *message_int_ptr;
1377 message_int_ptr++;
1378 }
1379 #endif /* DIRTY */
1380
1381 #ifdef DO_SELECT
1382 FD_SET(s_data,&readfds);
1383 select(s_data+1,&readfds,NULL,NULL,&timeout);
1384 #endif /* DO_SELECT */
1385
1386 }
1387
1388 /* perform a shutdown to signal the sender that */
1389 /* we have received all the data sent. raj 4/93 */
1390
1391 if (close(s_data) == -1) {
1392 netperf_response.content.serv_errno = errno;
1393 send_response();
1394 exit(1);
1395 }
1396
1397 cpu_stop(sctp_stream_request->measure_cpu,&elapsed_time);
1398
1399 /* send the results to the sender */
1400
1401 if (debug) {
1402 fprintf(where,
1403 "recv_sctp_stream: got %g bytes\n",
1404 bytes_received);
1405 fprintf(where,
1406 "recv_sctp_stream: got %d recvs\n",
1407 receive_calls);
1408 fflush(where);
1409 }
1410
1411 sctp_stream_results->bytes_received = htond(bytes_received);
1412 sctp_stream_results->elapsed_time = elapsed_time;
1413 sctp_stream_results->recv_calls = receive_calls;
1414
1415 if (sctp_stream_request->measure_cpu) {
1416 sctp_stream_results->cpu_util = calc_cpu_util(0.0);
1417 };
1418
1419 if (debug) {
1420 fprintf(where,
1421 "recv_sctp_stream: test complete, sending results.\n");
1422 fprintf(where,
1423 " bytes_received %g receive_calls %d\n",
1424 bytes_received,
1425 receive_calls);
1426 fprintf(where,
1427 " len %d\n",
1428 len);
1429 fflush(where);
1430 }
1431
1432 sctp_stream_results->cpu_method = cpu_method;
1433 sctp_stream_results->num_cpus = lib_num_loc_cpus;
1434 send_response();
1435
1436 /* we are now done with the sockets */
1437 close(s_listen);
1438
1439 }
1440
1441
1442 /* This routine implements the SCTP unidirectional data transfer test */
1443 /* (a.k.a. stream) for the sockets interface. It receives its */
1444 /* parameters via global variables from the shell and writes its */
1445 /* output to the standard output. */
1446
1447
1448 void
send_sctp_stream_1toMany(char remote_host[])1449 send_sctp_stream_1toMany( char remote_host[] )
1450 {
1451
1452 char *tput_title = "\
1453 Recv Send Send \n\
1454 Socket Socket Message Elapsed \n\
1455 Size Size Size Time Throughput \n\
1456 bytes bytes bytes secs. %s/sec \n\n";
1457
1458 char *tput_fmt_0 =
1459 "%7.2f\n";
1460
1461 char *tput_fmt_1 =
1462 "%6d %6d %6d %-6.2f %7.2f \n";
1463
1464 char *cpu_title = "\
1465 Recv Send Send Utilization Service Demand\n\
1466 Socket Socket Message Elapsed Send Recv Send Recv\n\
1467 Size Size Size Time Throughput local remote local remote\n\
1468 bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n";
1469
1470 char *cpu_fmt_0 =
1471 "%6.3f %c\n";
1472
1473 char *cpu_fmt_1 =
1474 "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
1475
1476 char *ksink_fmt = "\n\
1477 Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\
1478 Local Remote Local Remote Xfered Per Per\n\
1479 Send Recv Send Recv Send (avg) Recv (avg)\n\
1480 %5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n";
1481
1482 char *ksink_fmt2 = "\n\
1483 Maximum\n\
1484 Segment\n\
1485 Size (bytes)\n\
1486 %6d\n";
1487
1488
1489 float elapsed_time;
1490
1491 #ifdef WANT_INTERVALS
1492 int interval_count;
1493 sigset_t signal_set;
1494 #endif
1495
1496 /* what we want is to have a buffer space that is at least one */
1497 /* send-size greater than our send window. this will insure that we */
1498 /* are never trying to re-use a buffer that may still be in the hands */
1499 /* of the transport. This buffer will be malloc'd after we have found */
1500 /* the size of the local senc socket buffer. We will want to deal */
1501 /* with alignment and offset concerns as well. */
1502
1503 #ifdef DIRTY
1504 int *message_int_ptr;
1505 #endif
1506
1507 struct ring_elt *send_ring;
1508
1509 int len;
1510 unsigned int nummessages = 0;
1511 int *send_socket;
1512 int bytes_remaining;
1513 int sctp_mss;
1514
1515 /* with links like fddi, one can send > 32 bits worth of bytes */
1516 /* during a test... ;-) at some point, this should probably become a */
1517 /* 64bit integral type, but those are not entirely common yet */
1518 double bytes_sent = 0.0;
1519
1520 #ifdef DIRTY
1521 int i;
1522 #endif /* DIRTY */
1523
1524 float local_cpu_utilization;
1525 float local_service_demand;
1526 float remote_cpu_utilization;
1527 float remote_service_demand;
1528
1529 double thruput;
1530
1531 struct addrinfo *remote_res;
1532 struct addrinfo *local_res;
1533
1534 struct sctp_stream_request_struct *sctp_stream_request;
1535 struct sctp_stream_response_struct *sctp_stream_response;
1536 struct sctp_stream_results_struct *sctp_stream_result;
1537
1538 sctp_stream_request =
1539 (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data;
1540 sctp_stream_response =
1541 (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data;
1542 sctp_stream_result =
1543 (struct sctp_stream_results_struct *)netperf_response.content.test_specific_data;
1544
1545 #ifdef WANT_HISTOGRAM
1546 time_hist = HIST_new_n(1);
1547 #endif /* WANT_HISTOGRAM */
1548
1549 complete_addrinfos(&remote_res,
1550 &local_res,
1551 remote_host,
1552 SOCK_SEQPACKET,
1553 IPPROTO_SCTP,
1554 0);
1555
1556 if ( print_headers ) {
1557 print_top_test_header("SCTP 1-TO-MANY STREAM TEST",local_res,remote_res);
1558 }
1559
1560 send_ring = NULL;
1561 confidence_iteration = 1;
1562 init_stat();
1563
1564 send_socket = malloc(sizeof (int) * num_associations);
1565 if (send_socket == NULL) {
1566 fprintf(where, "send_sctp_stream_1toMany: failed to allocation sockets!\n");
1567 exit(1);
1568 }
1569
1570 /* we have a great-big while loop which controls the number of times */
1571 /* we run a particular test. this is for the calculation of a */
1572 /* confidence interval (I really should have stayed awake during */
1573 /* probstats :). If the user did not request confidence measurement */
1574 /* (no confidence is the default) then we will only go though the */
1575 /* loop once. the confidence stuff originates from the folks at IBM */
1576
1577 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
1578 (confidence_iteration <= iteration_min)) {
1579
1580 int j=0;
1581 int timed_out = 0;
1582
1583
1584 /* initialize a few counters. we have to remember that we might be */
1585 /* going through the loop more than once. */
1586
1587 nummessages = 0;
1588 bytes_sent = 0.0;
1589 times_up = 0;
1590
1591 /* at this point, we have either retrieved the socket buffer sizes, */
1592 /* or have tried to set them, so now, we may want to set the send */
1593 /* size based on that (because the user either did not use a -m */
1594 /* option, or used one with an argument of 0). If the socket buffer */
1595 /* size is not available, we will set the send size to 4KB - no */
1596 /* particular reason, just arbitrary... */
1597 if (send_size == 0) {
1598 if (lss_size > 0) {
1599 send_size = lss_size;
1600 }
1601 else {
1602 send_size = 4096;
1603 }
1604 }
1605
1606 /* set-up the data buffer ring with the requested alignment and offset. */
1607 /* note also that we have allocated a quantity */
1608 /* of memory that is at least one send-size greater than our socket */
1609 /* buffer size. We want to be sure that there are at least two */
1610 /* buffers allocated - this can be a bit of a problem when the */
1611 /* send_size is bigger than the socket size, so we must check... the */
1612 /* user may have wanted to explicitly set the "width" of our send */
1613 /* buffers, we should respect that wish... */
1614 if (send_width == 0) {
1615 send_width = (lss_size/send_size) + 1;
1616 if (send_width == 1) send_width++;
1617 }
1618
1619 if (send_ring == NULL) {
1620 /* only allocate the send ring once. this is a networking test, */
1621 /* not a memory allocation test. this way, we do not need a */
1622 /* deallocate_buffer_ring() routine, and I don't feel like */
1623 /* writing one anyway :) raj 11/94 */
1624 send_ring = allocate_buffer_ring(send_width,
1625 send_size,
1626 local_send_align,
1627 local_send_offset);
1628 }
1629
1630 /* If the user has requested cpu utilization measurements, we must */
1631 /* calibrate the cpu(s). We will perform this task within the tests */
1632 /* themselves. If the user has specified the cpu rate, then */
1633 /* calibrate_local_cpu will return rather quickly as it will have */
1634 /* nothing to do. If local_cpu_rate is zero, then we will go through */
1635 /* all the "normal" calibration stuff and return the rate back. */
1636
1637 if (local_cpu_usage) {
1638 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
1639 }
1640
1641 /* Tell the remote end to do a listen. The server alters the socket */
1642 /* paramters on the other side at this point, hence the reason for */
1643 /* all the values being passed in the setup message. If the user did */
1644 /* not specify any of the parameters, they will be passed as 0, which */
1645 /* will indicate to the remote that no changes beyond the system's */
1646 /* default should be used. Alignment is the exception, it will */
1647 /* default to 1, which will be no alignment alterations. */
1648
1649 netperf_request.content.request_type = DO_SCTP_STREAM_MANY;
1650 sctp_stream_request->send_buf_size = rss_size_req;
1651 sctp_stream_request->recv_buf_size = rsr_size_req;
1652 sctp_stream_request->receive_size = recv_size;
1653 sctp_stream_request->no_delay = rem_nodelay;
1654 sctp_stream_request->recv_alignment = remote_recv_align;
1655 sctp_stream_request->recv_offset = remote_recv_offset;
1656 sctp_stream_request->measure_cpu = remote_cpu_usage;
1657 sctp_stream_request->cpu_rate = remote_cpu_rate;
1658 if (test_time) {
1659 sctp_stream_request->test_length = test_time;
1660 }
1661 else {
1662 if (msg_count)
1663 test_bytes = send_size * msg_count;
1664
1665 sctp_stream_request->test_length = test_bytes*num_associations;
1666 }
1667 sctp_stream_request->so_rcvavoid = rem_rcvavoid;
1668 sctp_stream_request->so_sndavoid = rem_sndavoid;
1669 #ifdef DIRTY
1670 sctp_stream_request->dirty_count = rem_dirty_count;
1671 sctp_stream_request->clean_count = rem_clean_count;
1672 #endif /* DIRTY */
1673 sctp_stream_request->port = (atoi(remote_data_port));
1674 sctp_stream_request->ipfamily = af_to_nf(remote_res->ai_family);
1675 sctp_stream_request->non_blocking = non_block;
1676
1677
1678 if (debug > 1) {
1679 fprintf(where,
1680 "netperf: send_sctp_stream_1toMany: requesting sctp stream test\n");
1681 }
1682
1683 send_request();
1684
1685 /* The response from the remote will contain all of the relevant */
1686 /* socket parameters for this test type. We will put them back into */
1687 /* the variables here so they can be displayed if desired. The */
1688 /* remote will have calibrated CPU if necessary, and will have done */
1689 /* all the needed set-up we will have calibrated the cpu locally */
1690 /* before sending the request, and will grab the counter value right*/
1691 /* after the connect returns. The remote will grab the counter right*/
1692 /* after the accept call. This saves the hassle of extra messages */
1693 /* being sent for the sctp tests. */
1694
1695 recv_response();
1696
1697 if (!netperf_response.content.serv_errno) {
1698 if (debug)
1699 fprintf(where,"remote listen done.\n");
1700 rsr_size = sctp_stream_response->recv_buf_size;
1701 rss_size = sctp_stream_response->send_buf_size;
1702 rem_nodelay = sctp_stream_response->no_delay;
1703 remote_cpu_usage= sctp_stream_response->measure_cpu;
1704 remote_cpu_rate = sctp_stream_response->cpu_rate;
1705
1706 /* we have to make sure that the server port number is in */
1707 /* network order */
1708 set_port_number(remote_res, (unsigned short)sctp_stream_response->data_port_number);
1709 rem_rcvavoid = sctp_stream_response->so_rcvavoid;
1710 rem_sndavoid = sctp_stream_response->so_sndavoid;
1711 }
1712 else {
1713 Set_errno(netperf_response.content.serv_errno);
1714 fprintf(where,
1715 "netperf: remote error %d",
1716 netperf_response.content.serv_errno);
1717 perror("");
1718 fflush(where);
1719
1720 exit(1);
1721 }
1722
1723 /*set up the the array of data sockets and connect them to the server */
1724
1725 for (j = 0; j < num_associations; j++) {
1726 send_socket[j] = create_data_socket(local_res);
1727
1728 if (send_socket[j] < 0){
1729 perror("netperf: send_sctp_stream_1toMany: sctp stream data socket");
1730 exit(1);
1731 }
1732
1733 if (debug) {
1734 fprintf(where,"send_sctp_stream_1toMany: send_socket obtained...\n");
1735 }
1736
1737 /*Connect up to the remote port on the data socket */
1738 if (connect(send_socket[j],
1739 remote_res->ai_addr,
1740 remote_res->ai_addrlen) == INVALID_SOCKET){
1741 perror("netperf: send_sctp_stream_1toMany: data socket connect failed");
1742 exit(1);
1743 }
1744
1745 /* Do it after connect is successfull, so that we don't see COMM_UP */
1746 sctp_enable_events(send_socket[j], SCTP_ASSOC_CHANGE_EV);
1747
1748 if (non_block) {
1749 /* now that we are connected, mark the socket as non-blocking */
1750 if (!set_nonblock(send_socket[j])) {
1751 perror("netperf: fcntl");
1752 exit(1);
1753 }
1754 }
1755 }
1756
1757 /* Data Socket set-up is finished. If there were problems, either */
1758 /* the connect would have failed, or the previous response would */
1759 /* have indicated a problem. I failed to see the value of the */
1760 /* extra message after the accept on the remote. If it failed, */
1761 /* we'll see it here. If it didn't, we might as well start pumping */
1762 /* data. */
1763
1764 /* Set-up the test end conditions. For a stream test, they can be */
1765 /* either time or byte-count based. */
1766
1767 if (test_time) {
1768 /* The user wanted to end the test after a period of time. */
1769 times_up = 0;
1770 bytes_remaining = 0;
1771 /* in previous revisions, we had the same code repeated throught */
1772 /* all the test suites. this was unnecessary, and meant more */
1773 /* work for me when I wanted to switch to POSIX signals, so I */
1774 /* have abstracted this out into a routine in netlib.c. if you */
1775 /* are experiencing signal problems, you might want to look */
1776 /* there. raj 11/94 */
1777 start_timer(test_time);
1778 }
1779 else {
1780 /* The tester wanted to send a number of bytes. */
1781 bytes_remaining = test_bytes * num_associations;
1782 times_up = 1;
1783 }
1784
1785 /* The cpu_start routine will grab the current time and possibly */
1786 /* value of the idle counter for later use in measuring cpu */
1787 /* utilization and/or service demand and thruput. */
1788
1789 cpu_start(local_cpu_usage);
1790
1791 #ifdef WANT_INTERVALS
1792 if ((interval_burst) || (demo_mode)) {
1793 /* zero means that we never pause, so we never should need the */
1794 /* interval timer, unless we are in demo_mode */
1795 start_itimer(interval_wate);
1796 }
1797 interval_count = interval_burst;
1798 /* get the signal set for the call to sigsuspend */
1799 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
1800 fprintf(where,
1801 "send_sctp_stream_1toMany: unable to get sigmask errno %d\n",
1802 errno);
1803 fflush(where);
1804 exit(1);
1805 }
1806 #endif /* WANT_INTERVALS */
1807
1808 #ifdef DIRTY
1809 /* initialize the random number generator for putting dirty stuff */
1810 /* into the send buffer. raj */
1811 srand((int) getpid());
1812 #endif
1813
1814 /* before we start, initialize a few variables */
1815
1816 /* We use an "OR" to control test execution. When the test is */
1817 /* controlled by time, the byte count check will always return false. */
1818 /* When the test is controlled by byte count, the time test will */
1819 /* always return false. When the test is finished, the whole */
1820 /* expression will go false and we will stop sending data. */
1821
1822 while ((!times_up) || (bytes_remaining > 0)) {
1823
1824 #ifdef DIRTY
1825 /* we want to dirty some number of consecutive integers in the buffer */
1826 /* we are about to send. we may also want to bring some number of */
1827 /* them cleanly into the cache. The clean ones will follow any dirty */
1828 /* ones into the cache. at some point, we might want to replace */
1829 /* the rand() call with something from a table to reduce our call */
1830 /* overhead during the test, but it is not a high priority item. */
1831 message_int_ptr = (int *)(send_ring->buffer_ptr);
1832 for (i = 0; i < loc_dirty_count; i++) {
1833 *message_int_ptr = rand();
1834 message_int_ptr++;
1835 }
1836 for (i = 0; i < loc_clean_count; i++) {
1837 loc_dirty_count = *message_int_ptr;
1838 message_int_ptr++;
1839 }
1840 #endif /* DIRTY */
1841
1842 #ifdef WANT_HISTOGRAM
1843 /* timestamp just before we go into send and then again just after */
1844 /* we come out raj 8/94 */
1845 HIST_timestamp_start(time_hist);
1846 #endif /* WANT_HISTOGRAM */
1847
1848 for (j = 0; j < num_associations; j++) {
1849
1850 if((len=sctp_sendmsg(send_socket[j],
1851 send_ring->buffer_ptr,
1852 send_size,
1853 (struct sockaddr *)remote_res->ai_addr,
1854 remote_res->ai_addrlen,
1855 0, 0, 0, 0, 0)) != send_size) {
1856 if ((len >=0) || SOCKET_EINTR(len)) {
1857 /* the test was interrupted, must be the end of test */
1858 timed_out = 1;
1859 break;
1860 } else if (non_block && errno == EAGAIN) {
1861 j--; /* send again on the same socket */
1862 Set_errno(0);
1863 continue;
1864 }
1865 perror("netperf: data send error");
1866 printf("len was %d\n",len);
1867 exit(1);
1868 }
1869 }
1870
1871 if (timed_out)
1872 break; /* test is over, try next iteration */
1873
1874 #ifdef WANT_HISTOGRAM
1875 /* timestamp the exit from the send call and update the histogram */
1876 HIST_timestamp_stop_add(time_hist);
1877 #endif /* WANT_HISTOGRAM */
1878
1879 #ifdef WANT_INTERVALS
1880 if (demo_mode) {
1881 units_this_tick += send_size;
1882 }
1883 /* in this case, the interval count is the count-down couter */
1884 /* to decide to sleep for a little bit */
1885 if ((interval_burst) && (--interval_count == 0)) {
1886 /* call sigsuspend and wait for the interval timer to get us */
1887 /* out */
1888 if (debug > 1) {
1889 fprintf(where,"about to suspend\n");
1890 fflush(where);
1891 }
1892 if (sigsuspend(&signal_set) == EFAULT) {
1893 fprintf(where,
1894 "send_sctp_stream_1toMany: fault with sigsuspend.\n");
1895 fflush(where);
1896 exit(1);
1897 }
1898 interval_count = interval_burst;
1899 }
1900 #endif /* WANT_INTERVALS */
1901
1902 /* now we want to move our pointer to the next position in the */
1903 /* data buffer...we may also want to wrap back to the "beginning" */
1904 /* of the bufferspace, so we will mod the number of messages sent */
1905 /* by the send width, and use that to calculate the offset to add */
1906 /* to the base pointer. */
1907 nummessages++;
1908 send_ring = send_ring->next;
1909 if (bytes_remaining) {
1910 bytes_remaining -= send_size;
1911 }
1912 }
1913
1914 /* The test is over. Flush the buffers to the remote end. We do a */
1915 /* graceful release to insure that all data has been taken by the */
1916 /* remote. */
1917
1918 /* but first, if the verbosity is greater than 1, find-out what */
1919 /* the sctp maximum segment_size was (if possible) */
1920 if (verbosity > 1) {
1921 sctp_mss = -1;
1922 get_sctp_info(send_socket[0], &sctp_mss);
1923 }
1924
1925 /* signal the server that we are all done writing, this will
1926 * initiate a shutdonw of one of the associations on the
1927 * server and trigger an event telling the server it's all done
1928 */
1929 sctp_sendmsg(send_socket[0], NULL, 0, remote_res->ai_addr,
1930 remote_res->ai_addrlen, 0, MSG_EOF, 0, 0, 0);
1931
1932
1933 /* The test server will initiate closure of all associations
1934 * when it's done reading. We want a basic mechanism to catch this
1935 * and are using SCTP events for this.
1936 * In blocking mode, we can call recvmsg with the last socket we created.
1937 * In non-blocking mode, we need to select on the socket for reading.
1938 * We'll assume that all returns are succefull and signify
1939 * closure.
1940 * It is sufficient to do this on a single socket in the client.
1941 * We choose to do it on a socket other then the one that send MSG_EOF.
1942 * This means that anything comming in on that socket will be a shutdown.
1943 */
1944 if (non_block) {
1945 fd_set readfds;
1946
1947 FD_ZERO(&readfds);
1948 FD_SET(send_socket[num_associations-1], &readfds);
1949 select(send_socket[num_associations-1]+1, &readfds, NULL, NULL, NULL);
1950 } else {
1951 sctp_recvmsg(send_socket[num_associations], send_ring->buffer_ptr,
1952 send_size, NULL, 0, NULL, 0);
1953 }
1954
1955 /* this call will always give us the elapsed time for the test, and */
1956 /* will also store-away the necessaries for cpu utilization */
1957
1958 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
1959 /* measured and how */
1960 /* long did we really */
1961 /* run? */
1962
1963 /* we are finished with our sockets, so close them to prevent hitting */
1964 /* the limit on maximum open files. */
1965 for (j = 0; j < num_associations; j++)
1966 close(send_socket[j]);
1967
1968 /* Get the statistics from the remote end. The remote will have */
1969 /* calculated service demand and all those interesting things. If it */
1970 /* wasn't supposed to care, it will return obvious values. */
1971
1972 recv_response();
1973 if (!netperf_response.content.serv_errno) {
1974 if (debug)
1975 fprintf(where,"remote results obtained\n");
1976 }
1977 else {
1978 Set_errno(netperf_response.content.serv_errno);
1979 fprintf(where,
1980 "netperf: remote error %d",
1981 netperf_response.content.serv_errno);
1982 perror("");
1983 fflush(where);
1984
1985 exit(1);
1986 }
1987
1988 /* We now calculate what our thruput was for the test. In the future, */
1989 /* we may want to include a calculation of the thruput measured by */
1990 /* the remote, but it should be the case that for a sctp stream test, */
1991 /* that the two numbers should be *very* close... We calculate */
1992 /* bytes_sent regardless of the way the test length was controlled. */
1993 /* If it was time, we needed to, and if it was by bytes, the user may */
1994 /* have specified a number of bytes that wasn't a multiple of the */
1995 /* send_size, so we really didn't send what he asked for ;-) */
1996
1997 bytes_sent = ntohd(sctp_stream_result->bytes_received);
1998
1999 thruput = (double) calc_thruput(bytes_sent);
2000
2001 if (local_cpu_usage || remote_cpu_usage) {
2002 /* We must now do a little math for service demand and cpu */
2003 /* utilization for the system(s) */
2004 /* Of course, some of the information might be bogus because */
2005 /* there was no idle counter in the kernel(s). We need to make */
2006 /* a note of this for the user's benefit...*/
2007 if (local_cpu_usage) {
2008
2009 local_cpu_utilization = calc_cpu_util(0.0);
2010 local_service_demand = calc_service_demand(bytes_sent,
2011 0.0,
2012 0.0,
2013 0);
2014 }
2015 else {
2016 local_cpu_utilization = (float) -1.0;
2017 local_service_demand = (float) -1.0;
2018 }
2019
2020 if (remote_cpu_usage) {
2021
2022 remote_cpu_utilization = sctp_stream_result->cpu_util;
2023 remote_service_demand = calc_service_demand(bytes_sent,
2024 0.0,
2025 remote_cpu_utilization,
2026 sctp_stream_result->num_cpus);
2027 }
2028 else {
2029 remote_cpu_utilization = (float) -1.0;
2030 remote_service_demand = (float) -1.0;
2031 }
2032 }
2033 else {
2034 /* we were not measuring cpu, for the confidence stuff, we */
2035 /* should make it -1.0 */
2036 local_cpu_utilization = (float) -1.0;
2037 local_service_demand = (float) -1.0;
2038 remote_cpu_utilization = (float) -1.0;
2039 remote_service_demand = (float) -1.0;
2040 }
2041
2042 /* at this point, we want to calculate the confidence information. */
2043 /* if debugging is on, calculate_confidence will print-out the */
2044 /* parameters we pass it */
2045
2046 calculate_confidence(confidence_iteration,
2047 elapsed_time,
2048 thruput,
2049 local_cpu_utilization,
2050 remote_cpu_utilization,
2051 local_service_demand,
2052 remote_service_demand);
2053
2054
2055 confidence_iteration++;
2056 }
2057
2058 /* at this point, we have finished making all the runs that we */
2059 /* will be making. so, we should extract what the calcuated values */
2060 /* are for all the confidence stuff. we could make the values */
2061 /* global, but that seemed a little messy, and it did not seem worth */
2062 /* all the mucking with header files. so, we create a routine much */
2063 /* like calcualte_confidence, which just returns the mean values. */
2064 /* raj 11/94 */
2065
2066 retrieve_confident_values(&elapsed_time,
2067 &thruput,
2068 &local_cpu_utilization,
2069 &remote_cpu_utilization,
2070 &local_service_demand,
2071 &remote_service_demand);
2072
2073 /* We are now ready to print all the information. If the user */
2074 /* has specified zero-level verbosity, we will just print the */
2075 /* local service demand, or the remote service demand. If the */
2076 /* user has requested verbosity level 1, he will get the basic */
2077 /* "streamperf" numbers. If the user has specified a verbosity */
2078 /* of greater than 1, we will display a veritable plethora of */
2079 /* background information from outside of this block as it it */
2080 /* not cpu_measurement specific... */
2081
2082 if (confidence < 0) {
2083 /* we did not hit confidence, but were we asked to look for it? */
2084 if (iteration_max > 1) {
2085 display_confidence();
2086 }
2087 }
2088
2089 if (local_cpu_usage || remote_cpu_usage) {
2090 local_cpu_method = format_cpu_method(cpu_method);
2091 remote_cpu_method = format_cpu_method(sctp_stream_result->cpu_method);
2092
2093 switch (verbosity) {
2094 case 0:
2095 if (local_cpu_usage) {
2096 fprintf(where,
2097 cpu_fmt_0,
2098 local_service_demand,
2099 local_cpu_method);
2100 }
2101 else {
2102 fprintf(where,
2103 cpu_fmt_0,
2104 remote_service_demand,
2105 remote_cpu_method);
2106 }
2107 break;
2108 case 1:
2109 case 2:
2110 if (print_headers) {
2111 fprintf(where,
2112 cpu_title,
2113 format_units(),
2114 local_cpu_method,
2115 remote_cpu_method);
2116 }
2117
2118 fprintf(where,
2119 cpu_fmt_1, /* the format string */
2120 rsr_size, /* remote recvbuf size */
2121 lss_size, /* local sendbuf size */
2122 send_size, /* how large were the sends */
2123 elapsed_time, /* how long was the test */
2124 thruput, /* what was the xfer rate */
2125 local_cpu_utilization, /* local cpu */
2126 remote_cpu_utilization, /* remote cpu */
2127 local_service_demand, /* local service demand */
2128 remote_service_demand); /* remote service demand */
2129 break;
2130 }
2131 }
2132 else {
2133 /* The tester did not wish to measure service demand. */
2134
2135 switch (verbosity) {
2136 case 0:
2137 fprintf(where,
2138 tput_fmt_0,
2139 thruput);
2140 break;
2141 case 1:
2142 case 2:
2143 if (print_headers) {
2144 fprintf(where,tput_title,format_units());
2145 }
2146 fprintf(where,
2147 tput_fmt_1, /* the format string */
2148 rsr_size, /* remote recvbuf size */
2149 lss_size, /* local sendbuf size */
2150 send_size, /* how large were the sends */
2151 elapsed_time, /* how long did it take */
2152 thruput);/* how fast did it go */
2153 break;
2154 }
2155 }
2156
2157 /* it would be a good thing to include information about some of the */
2158 /* other parameters that may have been set for this test, but at the */
2159 /* moment, I do not wish to figure-out all the formatting, so I will */
2160 /* just put this comment here to help remind me that it is something */
2161 /* that should be done at a later time. */
2162
2163 if (verbosity > 1) {
2164 /* The user wanted to know it all, so we will give it to him. */
2165 /* This information will include as much as we can find about */
2166 /* sctp statistics, the alignments of the sends and receives */
2167 /* and all that sort of rot... */
2168
2169 /* this stuff needs to be worked-out in the presence of confidence */
2170 /* intervals and multiple iterations of the test... raj 11/94 */
2171
2172 fprintf(where,
2173 ksink_fmt,
2174 "Bytes",
2175 "Bytes",
2176 "Bytes",
2177 local_send_align,
2178 remote_recv_align,
2179 local_send_offset,
2180 remote_recv_offset,
2181 bytes_sent,
2182 bytes_sent / (double)nummessages,
2183 nummessages,
2184 bytes_sent / (double)sctp_stream_result->recv_calls,
2185 sctp_stream_result->recv_calls);
2186 fprintf(where,
2187 ksink_fmt2,
2188 sctp_mss);
2189 fflush(where);
2190 #ifdef WANT_HISTOGRAM
2191 fprintf(where,"\n\nHistogram of time spent in send() call.\n");
2192 fflush(where);
2193 HIST_report(time_hist);
2194 #endif /* WANT_HISTOGRAM */
2195 }
2196
2197 }
2198
2199
2200
2201 /* This is the server-side routine for the sctp stream test. It is */
2202 /* implemented as one routine. I could break things-out somewhat, but */
2203 /* didn't feel it was necessary. */
2204
2205 void
recv_sctp_stream_1toMany(void)2206 recv_sctp_stream_1toMany( void )
2207 {
2208
2209 struct sockaddr_in myaddr_in;
2210 int s_recv;
2211 socklen_t addrlen;
2212 int len;
2213 unsigned int receive_calls;
2214 float elapsed_time;
2215 double bytes_received;
2216 int msg_flags = 0;
2217
2218 struct ring_elt *recv_ring;
2219
2220 struct addrinfo *local_res;
2221 char local_name[BUFSIZ];
2222 char port_buffer[PORTBUFSIZE];
2223
2224 #ifdef DIRTY
2225 int *message_int_ptr;
2226 int dirty_count;
2227 int clean_count;
2228 int i;
2229 #endif
2230
2231 #ifdef DO_SELECT
2232 fd_set readfds;
2233 struct timeval timeout;
2234 #endif
2235
2236 struct sctp_stream_request_struct *sctp_stream_request;
2237 struct sctp_stream_response_struct *sctp_stream_response;
2238 struct sctp_stream_results_struct *sctp_stream_results;
2239
2240 #ifdef DO_SELECT
2241 FD_ZERO(&readfds);
2242 timeout.tv_sec = 1;
2243 timeout.tv_usec = 0;
2244 #endif
2245
2246 sctp_stream_request =
2247 (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data;
2248 sctp_stream_response =
2249 (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data;
2250 sctp_stream_results =
2251 (struct sctp_stream_results_struct *)netperf_response.content.test_specific_data;
2252
2253 if (debug) {
2254 fprintf(where,"netserver: recv_sctp_stream: entered...\n");
2255 fflush(where);
2256 }
2257
2258 /* We want to set-up the listen socket with all the desired */
2259 /* parameters and then let the initiator know that all is ready. If */
2260 /* socket size defaults are to be used, then the initiator will have */
2261 /* sent us 0's. If the socket sizes cannot be changed, then we will */
2262 /* send-back what they are. If that information cannot be determined, */
2263 /* then we send-back -1's for the sizes. If things go wrong for any */
2264 /* reason, we will drop back ten yards and punt. */
2265
2266 /* If anything goes wrong, we want the remote to know about it. It */
2267 /* would be best if the error that the remote reports to the user is */
2268 /* the actual error we encountered, rather than some bogus unexpected */
2269 /* response type message. */
2270
2271 if (debug) {
2272 fprintf(where,"recv_sctp_stream_1toMany: setting the response type...\n");
2273 fflush(where);
2274 }
2275
2276 netperf_response.content.response_type = SCTP_STREAM_MANY_RESPONSE;
2277
2278 if (debug) {
2279 fprintf(where,"recv_sctp_stream_1toMany: the response type is set...\n");
2280 fflush(where);
2281 }
2282
2283 /* We now alter the message_ptr variable to be at the desired */
2284 /* alignment with the desired offset. */
2285
2286 if (debug) {
2287 fprintf(where,"recv_sctp_stream_1toMany: requested alignment of %d\n",
2288 sctp_stream_request->recv_alignment);
2289 fflush(where);
2290 }
2291
2292 /* create_data_socket expects to find some things in the global */
2293 /* variables, so set the globals based on the values in the request. */
2294 /* once the socket has been created, we will set the response values */
2295 /* based on the updated value of those globals. raj 7/94 */
2296 lss_size_req = sctp_stream_request->send_buf_size;
2297 lsr_size_req = sctp_stream_request->recv_buf_size;
2298 loc_nodelay = sctp_stream_request->no_delay;
2299 loc_rcvavoid = sctp_stream_request->so_rcvavoid;
2300 loc_sndavoid = sctp_stream_request->so_sndavoid;
2301 non_block = sctp_stream_request->non_blocking;
2302
2303 set_hostname_and_port(local_name,
2304 port_buffer,
2305 nf_to_af(sctp_stream_request->ipfamily),
2306 sctp_stream_request->port);
2307
2308 local_res = complete_addrinfo(local_name,
2309 local_name,
2310 port_buffer,
2311 nf_to_af(sctp_stream_request->ipfamily),
2312 SOCK_SEQPACKET,
2313 IPPROTO_SCTP,
2314 0);
2315
2316 s_recv = create_data_socket(local_res);
2317
2318 if (s_recv < 0) {
2319 netperf_response.content.serv_errno = errno;
2320 send_response();
2321 exit(1);
2322 }
2323
2324 /* what sort of sizes did we end-up with? */
2325 if (sctp_stream_request->receive_size == 0) {
2326 if (lsr_size > 0) {
2327 recv_size = lsr_size;
2328 }
2329 else {
2330 recv_size = 4096;
2331 }
2332 }
2333 else {
2334 recv_size = sctp_stream_request->receive_size;
2335 }
2336
2337 /* we want to set-up our recv_ring in a manner analagous to what we */
2338 /* do on the sending side. this is more for the sake of symmetry */
2339 /* than for the needs of say copy avoidance, but it might also be */
2340 /* more realistic - this way one could conceivably go with a */
2341 /* double-buffering scheme when taking the data an putting it into */
2342 /* the filesystem or something like that. raj 7/94 */
2343
2344 if (recv_width == 0) {
2345 recv_width = (lsr_size/recv_size) + 1;
2346 if (recv_width == 1) recv_width++;
2347 }
2348
2349 recv_ring = allocate_buffer_ring(recv_width,
2350 recv_size,
2351 sctp_stream_request->recv_alignment,
2352 sctp_stream_request->recv_offset);
2353
2354 if (debug) {
2355 fprintf(where,"recv_sctp_stream: receive alignment and offset set...\n");
2356 fflush(where);
2357 }
2358
2359 /* Now, let's set-up the socket to listen for connections */
2360 if (listen(s_recv, 5) == -1) {
2361 netperf_response.content.serv_errno = errno;
2362 close(s_recv);
2363 send_response();
2364
2365 exit(1);
2366 }
2367
2368 /* now get the port number assigned by the system */
2369 addrlen = sizeof(myaddr_in);
2370 if (getsockname(s_recv,
2371 (struct sockaddr *)&myaddr_in,
2372 &addrlen) == -1){
2373 netperf_response.content.serv_errno = errno;
2374 close(s_recv);
2375 send_response();
2376
2377 exit(1);
2378 }
2379
2380 /* Now myaddr_in contains the port and the internet address this is */
2381 /* returned to the sender also implicitly telling the sender that the */
2382 /* socket buffer sizing has been done. */
2383
2384 sctp_stream_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
2385 netperf_response.content.serv_errno = 0;
2386
2387 /* But wait, there's more. If the initiator wanted cpu measurements, */
2388 /* then we must call the calibrate routine, which will return the max */
2389 /* rate back to the initiator. If the CPU was not to be measured, or */
2390 /* something went wrong with the calibration, we will return a -1 to */
2391 /* the initiator. */
2392
2393 sctp_stream_response->cpu_rate = (float)0.0; /* assume no cpu */
2394 if (sctp_stream_request->measure_cpu) {
2395 sctp_stream_response->measure_cpu = 1;
2396 sctp_stream_response->cpu_rate =
2397 calibrate_local_cpu(sctp_stream_request->cpu_rate);
2398 }
2399 else {
2400 sctp_stream_response->measure_cpu = 0;
2401 }
2402
2403 /* before we send the response back to the initiator, pull some of */
2404 /* the socket parms from the globals */
2405 sctp_stream_response->send_buf_size = lss_size;
2406 sctp_stream_response->recv_buf_size = lsr_size;
2407 sctp_stream_response->no_delay = loc_nodelay;
2408 sctp_stream_response->so_rcvavoid = loc_rcvavoid;
2409 sctp_stream_response->so_sndavoid = loc_sndavoid;
2410 sctp_stream_response->receive_size = recv_size;
2411
2412 send_response();
2413
2414
2415 sctp_enable_events(s_recv, SCTP_ASSOC_CHANGE_EV | SCTP_SHUTDOWN_EV);
2416
2417 /* now that we are connected, mark the socket as non-blocking */
2418 if (non_block) {
2419 if (!set_nonblock(s_recv)) {
2420 close(s_recv);
2421 exit(1);
2422 }
2423 }
2424
2425
2426 /* Now it's time to start receiving data on the connection. We will */
2427 /* first grab the apropriate counters and then start grabbing. */
2428
2429 cpu_start(sctp_stream_request->measure_cpu);
2430
2431 /* The loop will exit when the sender does a shutdown, which will */
2432 /* return a length of zero */
2433
2434 #ifdef DIRTY
2435 /* we want to dirty some number of consecutive integers in the buffer */
2436 /* we are about to recv. we may also want to bring some number of */
2437 /* them cleanly into the cache. The clean ones will follow any dirty */
2438 /* ones into the cache. */
2439
2440 dirty_count = sctp_stream_request->dirty_count;
2441 clean_count = sctp_stream_request->clean_count;
2442 message_int_ptr = (int *)recv_ring->buffer_ptr;
2443 for (i = 0; i < dirty_count; i++) {
2444 *message_int_ptr = rand();
2445 message_int_ptr++;
2446 }
2447 for (i = 0; i < clean_count; i++) {
2448 dirty_count = *message_int_ptr;
2449 message_int_ptr++;
2450 }
2451 #endif /* DIRTY */
2452
2453 bytes_received = 0;
2454 receive_calls = 0;
2455
2456 while ((len = sctp_recvmsg(s_recv, recv_ring->buffer_ptr, recv_size,
2457 NULL, 0, /* we don't care who it's from */
2458 NULL, &msg_flags)) != 0) {
2459 if (len < 0) {
2460 if (non_block && errno == EAGAIN) {
2461 Set_errno(0);
2462 continue;
2463 }
2464 netperf_response.content.serv_errno = errno;
2465 send_response();
2466 close(s_recv);
2467 exit(1);
2468 }
2469
2470 if (msg_flags & MSG_NOTIFICATION) {
2471 if (sctp_process_event(s_recv, recv_ring->buffer_ptr) == SCTP_CLOSE)
2472 break;
2473
2474 continue;
2475 }
2476
2477 bytes_received += len;
2478 receive_calls++;
2479
2480 /* more to the next buffer in the recv_ring */
2481 recv_ring = recv_ring->next;
2482
2483 #ifdef PAUSE
2484 sleep(1);
2485 #endif /* PAUSE */
2486
2487 #ifdef DIRTY
2488 message_int_ptr = (int *)(recv_ring->buffer_ptr);
2489 for (i = 0; i < dirty_count; i++) {
2490 *message_int_ptr = rand();
2491 message_int_ptr++;
2492 }
2493 for (i = 0; i < clean_count; i++) {
2494 dirty_count = *message_int_ptr;
2495 message_int_ptr++;
2496 }
2497 #endif /* DIRTY */
2498
2499 #ifdef DO_SELECT
2500 FD_SET(s_recv,&readfds);
2501 select(s_recv+1,&readfds,NULL,NULL,&timeout);
2502 #endif /* DO_SELECT */
2503
2504 }
2505
2506 /* perform a shutdown to signal the sender. in this case, sctp
2507 * will close all associations on this socket
2508 */
2509 if (close(s_recv) == -1) {
2510 netperf_response.content.serv_errno = errno;
2511 send_response();
2512 exit(1);
2513 }
2514
2515 cpu_stop(sctp_stream_request->measure_cpu,&elapsed_time);
2516
2517 /* send the results to the sender */
2518
2519 if (debug) {
2520 fprintf(where,
2521 "recv_sctp_stream: got %g bytes\n",
2522 bytes_received);
2523 fprintf(where,
2524 "recv_sctp_stream: got %d recvs\n",
2525 receive_calls);
2526 fflush(where);
2527 }
2528
2529 sctp_stream_results->bytes_received = htond(bytes_received);
2530 sctp_stream_results->elapsed_time = elapsed_time;
2531 sctp_stream_results->recv_calls = receive_calls;
2532
2533 if (sctp_stream_request->measure_cpu) {
2534 sctp_stream_results->cpu_util = calc_cpu_util(0.0);
2535 };
2536
2537 if (debug) {
2538 fprintf(where,
2539 "recv_sctp_stream: test complete, sending results.\n");
2540 fprintf(where,
2541 " bytes_received %g receive_calls %d\n",
2542 bytes_received,
2543 receive_calls);
2544 fprintf(where,
2545 " len %d\n",
2546 len);
2547 fflush(where);
2548 }
2549
2550 sctp_stream_results->cpu_method = cpu_method;
2551 sctp_stream_results->num_cpus = lib_num_loc_cpus;
2552 send_response();
2553 }
2554
2555
2556 /* this routine implements the sending (netperf) side of the SCTP_RR */
2557 /* test. */
2558
2559 void
send_sctp_rr(char remote_host[])2560 send_sctp_rr( char remote_host[] )
2561 {
2562
2563 char *tput_title = "\
2564 Local /Remote\n\
2565 Socket Size Request Resp. Elapsed Trans.\n\
2566 Send Recv Size Size Time Rate \n\
2567 bytes Bytes bytes bytes secs. per sec \n\n";
2568
2569 char *tput_fmt_0 =
2570 "%7.2f\n";
2571
2572 char *tput_fmt_1_line_1 = "\
2573 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
2574 char *tput_fmt_1_line_2 = "\
2575 %-6d %-6d\n";
2576
2577 char *cpu_title = "\
2578 Local /Remote\n\
2579 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
2580 Send Recv Size Size Time Rate local remote local remote\n\
2581 bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
2582
2583 char *cpu_fmt_0 =
2584 "%6.3f %c\n";
2585
2586 char *cpu_fmt_1_line_1 = "\
2587 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
2588
2589 char *cpu_fmt_1_line_2 = "\
2590 %-6d %-6d\n";
2591
2592 char *ksink_fmt = "\
2593 Alignment Offset\n\
2594 Local Remote Local Remote\n\
2595 Send Recv Send Recv\n\
2596 %5d %5d %5d %5d\n";
2597
2598
2599 int timed_out = 0;
2600 float elapsed_time;
2601
2602 int len;
2603 char *temp_message_ptr;
2604 int nummessages;
2605 int send_socket;
2606 int trans_remaining;
2607 int msg_flags = 0;
2608 double bytes_xferd;
2609
2610 struct ring_elt *send_ring;
2611 struct ring_elt *recv_ring;
2612
2613 int rsp_bytes_left;
2614 int rsp_bytes_recvd;
2615
2616 float local_cpu_utilization;
2617 float local_service_demand;
2618 float remote_cpu_utilization;
2619 float remote_service_demand;
2620 double thruput;
2621
2622 struct addrinfo *remote_res;
2623 struct addrinfo *local_res;
2624
2625 struct sctp_rr_request_struct *sctp_rr_request;
2626 struct sctp_rr_response_struct *sctp_rr_response;
2627 struct sctp_rr_results_struct *sctp_rr_result;
2628
2629 #ifdef WANT_INTERVALS
2630 int interval_count;
2631 sigset_t signal_set;
2632 #endif /* WANT_INTERVALS */
2633
2634 sctp_rr_request =
2635 (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data;
2636 sctp_rr_response =
2637 (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data;
2638 sctp_rr_result =
2639 (struct sctp_rr_results_struct *)netperf_response.content.test_specific_data;
2640
2641 #ifdef WANT_HISTOGRAM
2642 time_hist = HIST_new_n(1);
2643 #endif /* WANT_HISTOGRAM */
2644
2645 /* since we are now disconnected from the code that established the */
2646 /* control socket, and since we want to be able to use different */
2647 /* protocols and such, we are passed the name of the remote host and */
2648 /* must turn that into the test specific addressing information. */
2649
2650 /* complete_addrinfos will either succede or exit the process */
2651 complete_addrinfos(&remote_res,
2652 &local_res,
2653 remote_host,
2654 SOCK_STREAM,
2655 IPPROTO_SCTP,
2656 0);
2657
2658 if ( print_headers ) {
2659 print_top_test_header("SCTP REQUEST/RESPONSE TEST", local_res, remote_res);
2660 }
2661
2662 /* initialize a few counters */
2663
2664 send_ring = NULL;
2665 recv_ring = NULL;
2666 confidence_iteration = 1;
2667 init_stat();
2668
2669 /* we have a great-big while loop which controls the number of times */
2670 /* we run a particular test. this is for the calculation of a */
2671 /* confidence interval (I really should have stayed awake during */
2672 /* probstats :). If the user did not request confidence measurement */
2673 /* (no confidence is the default) then we will only go though the */
2674 /* loop once. the confidence stuff originates from the folks at IBM */
2675
2676 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
2677 (confidence_iteration <= iteration_min)) {
2678
2679 /* initialize a few counters. we have to remember that we might be */
2680 /* going through the loop more than once. */
2681
2682 nummessages = 0;
2683 bytes_xferd = 0.0;
2684 times_up = 0;
2685 timed_out = 0;
2686 trans_remaining = 0;
2687
2688 /* set-up the data buffers with the requested alignment and offset. */
2689 /* since this is a request/response test, default the send_width and */
2690 /* recv_width to 1 and not two raj 7/94 */
2691
2692 if (send_width == 0) send_width = 1;
2693 if (recv_width == 0) recv_width = 1;
2694
2695 if (send_ring == NULL) {
2696 send_ring = allocate_buffer_ring(send_width,
2697 req_size,
2698 local_send_align,
2699 local_send_offset);
2700 }
2701
2702 if (recv_ring == NULL) {
2703 recv_ring = allocate_buffer_ring(recv_width,
2704 rsp_size,
2705 local_recv_align,
2706 local_recv_offset);
2707 }
2708
2709 /*set up the data socket */
2710 send_socket = create_data_socket(local_res);
2711
2712 if (send_socket < 0){
2713 perror("netperf: send_sctp_rr: sctp stream data socket");
2714 exit(1);
2715 }
2716
2717 if (debug) {
2718 fprintf(where,"send_sctp_rr: send_socket obtained...\n");
2719 }
2720
2721 /* If the user has requested cpu utilization measurements, we must */
2722 /* calibrate the cpu(s). We will perform this task within the tests */
2723 /* themselves. If the user has specified the cpu rate, then */
2724 /* calibrate_local_cpu will return rather quickly as it will have */
2725 /* nothing to do. If local_cpu_rate is zero, then we will go through */
2726 /* all the "normal" calibration stuff and return the rate back.*/
2727
2728 if (local_cpu_usage) {
2729 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
2730 }
2731
2732 /* Tell the remote end to do a listen. The server alters the socket */
2733 /* paramters on the other side at this point, hence the reason for */
2734 /* all the values being passed in the setup message. If the user did */
2735 /* not specify any of the parameters, they will be passed as 0, which */
2736 /* will indicate to the remote that no changes beyond the system's */
2737 /* default should be used. Alignment is the exception, it will */
2738 /* default to 8, which will be no alignment alterations. */
2739
2740 netperf_request.content.request_type = DO_SCTP_RR;
2741 sctp_rr_request->recv_buf_size = rsr_size_req;
2742 sctp_rr_request->send_buf_size = rss_size_req;
2743 sctp_rr_request->recv_alignment = remote_recv_align;
2744 sctp_rr_request->recv_offset = remote_recv_offset;
2745 sctp_rr_request->send_alignment = remote_send_align;
2746 sctp_rr_request->send_offset = remote_send_offset;
2747 sctp_rr_request->request_size = req_size;
2748 sctp_rr_request->response_size = rsp_size;
2749 sctp_rr_request->no_delay = rem_nodelay;
2750 sctp_rr_request->measure_cpu = remote_cpu_usage;
2751 sctp_rr_request->cpu_rate = remote_cpu_rate;
2752 sctp_rr_request->so_rcvavoid = rem_rcvavoid;
2753 sctp_rr_request->so_sndavoid = rem_sndavoid;
2754 if (test_time) {
2755 sctp_rr_request->test_length = test_time;
2756 }
2757 else {
2758 sctp_rr_request->test_length = test_trans * -1;
2759 }
2760 sctp_rr_request->non_blocking = non_block;
2761 sctp_rr_request->ipfamily = af_to_nf(remote_res->ai_family);
2762
2763 if (debug > 1) {
2764 fprintf(where,"netperf: send_sctp_rr: requesting SCTP rr test\n");
2765 }
2766
2767 send_request();
2768
2769 /* The response from the remote will contain all of the relevant */
2770 /* socket parameters for this test type. We will put them back into */
2771 /* the variables here so they can be displayed if desired. The */
2772 /* remote will have calibrated CPU if necessary, and will have done */
2773 /* all the needed set-up we will have calibrated the cpu locally */
2774 /* before sending the request, and will grab the counter value right*/
2775 /* after the connect returns. The remote will grab the counter right*/
2776 /* after the accept call. This saves the hassle of extra messages */
2777 /* being sent for the sctp tests. */
2778
2779 recv_response();
2780
2781 if (!netperf_response.content.serv_errno) {
2782 if (debug)
2783 fprintf(where,"remote listen done.\n");
2784 rsr_size = sctp_rr_response->recv_buf_size;
2785 rss_size = sctp_rr_response->send_buf_size;
2786 rem_nodelay = sctp_rr_response->no_delay;
2787 remote_cpu_usage = sctp_rr_response->measure_cpu;
2788 remote_cpu_rate = sctp_rr_response->cpu_rate;
2789 /* make sure that port numbers are in network order */
2790 set_port_number(remote_res,
2791 (unsigned short)sctp_rr_response->data_port_number);
2792 }
2793 else {
2794 Set_errno(netperf_response.content.serv_errno);
2795 fprintf(where,
2796 "netperf: remote error %d",
2797 netperf_response.content.serv_errno);
2798 perror("");
2799 fflush(where);
2800
2801 exit(1);
2802 }
2803
2804 /*Connect up to the remote port on the data socket */
2805 if (connect(send_socket,
2806 remote_res->ai_addr,
2807 remote_res->ai_addrlen) <0){
2808 perror("netperf: send_sctp_rr data socket connect failed");
2809 exit(1);
2810 }
2811
2812 /* don't need events for 1-to-1 API with request-response tests */
2813 sctp_enable_events(send_socket, 0);
2814
2815 /* set non-blocking if needed */
2816 if (non_block) {
2817 if (!set_nonblock(send_socket)) {
2818 close(send_socket);
2819 exit(1);
2820 }
2821 }
2822
2823 /* Data Socket set-up is finished. If there were problems, either the */
2824 /* connect would have failed, or the previous response would have */
2825 /* indicated a problem. I failed to see the value of the extra */
2826 /* message after the accept on the remote. If it failed, we'll see it */
2827 /* here. If it didn't, we might as well start pumping data. */
2828
2829 /* Set-up the test end conditions. For a request/response test, they */
2830 /* can be either time or transaction based. */
2831
2832 if (test_time) {
2833 /* The user wanted to end the test after a period of time. */
2834 times_up = 0;
2835 trans_remaining = 0;
2836 start_timer(test_time);
2837 }
2838 else {
2839 /* The tester wanted to send a number of bytes. */
2840 trans_remaining = test_bytes;
2841 times_up = 1;
2842 }
2843
2844 /* The cpu_start routine will grab the current time and possibly */
2845 /* value of the idle counter for later use in measuring cpu */
2846 /* utilization and/or service demand and thruput. */
2847
2848 cpu_start(local_cpu_usage);
2849
2850 #ifdef WANT_INTERVALS
2851 if ((interval_burst) || (demo_mode)) {
2852 /* zero means that we never pause, so we never should need the */
2853 /* interval timer, unless we are in demo_mode */
2854 start_itimer(interval_wate);
2855 }
2856 interval_count = interval_burst;
2857 /* get the signal set for the call to sigsuspend */
2858 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
2859 fprintf(where,
2860 "send_sctp_rr: unable to get sigmask errno %d\n",
2861 errno);
2862 fflush(where);
2863 exit(1);
2864 }
2865 #endif /* WANT_INTERVALS */
2866
2867 /* We use an "OR" to control test execution. When the test is */
2868 /* controlled by time, the byte count check will always return false. */
2869 /* When the test is controlled by byte count, the time test will */
2870 /* always return false. When the test is finished, the whole */
2871 /* expression will go false and we will stop sending data. I think I */
2872 /* just arbitrarily decrement trans_remaining for the timed test, but */
2873 /* will not do that just yet... One other question is whether or not */
2874 /* the send buffer and the receive buffer should be the same buffer. */
2875
2876 #ifdef WANT_FIRST_BURST
2877 {
2878 int i;
2879 for (i = 0; i < first_burst_size; i++) {
2880 if((len=sctp_sendmsg(send_socket,
2881 send_ring->buffer_ptr, req_size,
2882 NULL, 0, /* don't need addrs with 1-to-1 */
2883 0, 0, 0, 0, 0)) != req_size) {
2884 /* we should never hit the end of the test in the first burst */
2885 perror("send_sctp_rr: initial burst data send error");
2886 exit(1);
2887 }
2888 }
2889 }
2890 #endif /* WANT_FIRST_BURST */
2891
2892 while ((!times_up) || (trans_remaining > 0)) {
2893 /* send the request. we assume that if we use a blocking socket, */
2894 /* the request will be sent at one shot. */
2895
2896 #ifdef WANT_HISTOGRAM
2897 /* timestamp just before our call to send, and then again just */
2898 /* after the receive raj 8/94 */
2899 HIST_timestamp_start(time_hist);
2900 #endif /* WANT_HISTOGRAM */
2901
2902 while ((len=sctp_sendmsg(send_socket,
2903 send_ring->buffer_ptr, req_size,
2904 NULL, 0, /* don't need addrs with 1-to-1 */
2905 0, 0, 0, 0, 0)) != req_size) {
2906 if (non_block && errno == EAGAIN) {
2907 /* try sending again */
2908 continue;
2909 } else if (SOCKET_EINTR(len) || (errno == 0)) {
2910 /* we hit the end of a */
2911 /* timed test. */
2912 timed_out = 1;
2913 break;
2914 }
2915 perror("send_sctp_rr: data send error");
2916 exit(1);
2917 }
2918
2919 if (timed_out) {
2920 /* we timed out while sending. break out another level */
2921 break;
2922 }
2923 send_ring = send_ring->next;
2924
2925 /* receive the response */
2926 rsp_bytes_left = rsp_size;
2927 temp_message_ptr = recv_ring->buffer_ptr;
2928 do {
2929 msg_flags = 0;
2930 if ((rsp_bytes_recvd=sctp_recvmsg(send_socket,
2931 temp_message_ptr, rsp_bytes_left,
2932 NULL, 0,
2933 NULL, &msg_flags)) < 0) {
2934 if (errno == EINTR) {
2935 /* We hit the end of a timed test. */
2936 timed_out = 1;
2937 break;
2938 } else if (non_block && errno == EAGAIN) {
2939 continue;
2940 }
2941 perror("send_sctp_rr: data recv error");
2942 exit(1);
2943 }
2944 rsp_bytes_left -= rsp_bytes_recvd;
2945 temp_message_ptr += rsp_bytes_recvd;
2946 } while (!(msg_flags & MSG_EOR));
2947
2948 recv_ring = recv_ring->next;
2949
2950 if (timed_out) {
2951 /* we may have been in a nested while loop - we need */
2952 /* another call to break. */
2953 break;
2954 }
2955
2956 #ifdef WANT_HISTOGRAM
2957 HIST_timestamp_stop_add(time_hist);
2958 #endif /* WANT_HISTOGRAM */
2959 #ifdef WANT_INTERVALS
2960 if (demo_mode) {
2961 units_this_tick += 1;
2962 }
2963 /* in this case, the interval count is the count-down couter */
2964 /* to decide to sleep for a little bit */
2965 if ((interval_burst) && (--interval_count == 0)) {
2966 /* call sigsuspend and wait for the interval timer to get us */
2967 /* out */
2968 if (debug > 1) {
2969 fprintf(where,"about to suspend\n");
2970 fflush(where);
2971 }
2972 if (sigsuspend(&signal_set) == EFAULT) {
2973 fprintf(where,
2974 "send_sctp_rr: fault with signal set!\n");
2975 fflush(where);
2976 exit(1);
2977 }
2978 interval_count = interval_burst;
2979 }
2980 #endif /* WANT_INTERVALS */
2981
2982 nummessages++;
2983 if (trans_remaining) {
2984 trans_remaining--;
2985 }
2986
2987 if (debug > 3) {
2988 if ((nummessages % 100) == 0) {
2989 fprintf(where,
2990 "Transaction %d completed\n",
2991 nummessages);
2992 fflush(where);
2993 }
2994 }
2995 }
2996
2997 /* At this point we used to call shutdown on the data socket to be */
2998 /* sure all the data was delivered, but this was not germane in a */
2999 /* request/response test, and it was causing the tests to "hang" when */
3000 /* they were being controlled by time. So, I have replaced this */
3001 /* shutdown call with a call to close that can be found later in the */
3002 /* procedure. */
3003
3004 /* this call will always give us the elapsed time for the test, and */
3005 /* will also store-away the necessaries for cpu utilization */
3006
3007 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
3008 /* measured? how long */
3009 /* did we really run? */
3010
3011 /* Get the statistics from the remote end. The remote will have */
3012 /* calculated CPU utilization. If it wasn't supposed to care, it */
3013 /* will return obvious values. */
3014
3015 recv_response();
3016 if (!netperf_response.content.serv_errno) {
3017 if (debug)
3018 fprintf(where,"remote results obtained\n");
3019 }
3020 else {
3021 Set_errno(netperf_response.content.serv_errno);
3022 fprintf(where,"netperf: remote error %d",
3023 netperf_response.content.serv_errno);
3024 perror("");
3025 fflush(where);
3026 exit(1);
3027 }
3028
3029 /* We now calculate what our throughput was for the test. */
3030
3031 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
3032 thruput = nummessages/elapsed_time;
3033
3034 if (local_cpu_usage || remote_cpu_usage) {
3035 /* We must now do a little math for service demand and cpu */
3036 /* utilization for the system(s) */
3037 /* Of course, some of the information might be bogus because */
3038 /* there was no idle counter in the kernel(s). We need to make */
3039 /* a note of this for the user's benefit...*/
3040 if (local_cpu_usage) {
3041 local_cpu_utilization = calc_cpu_util(0.0);
3042 /* since calc_service demand is doing ms/Kunit we will */
3043 /* multiply the number of transaction by 1024 to get */
3044 /* "good" numbers */
3045 local_service_demand = calc_service_demand((double) nummessages*1024,
3046 0.0,
3047 0.0,
3048 0);
3049 }
3050 else {
3051 local_cpu_utilization = (float) -1.0;
3052 local_service_demand = (float) -1.0;
3053 }
3054
3055 if (remote_cpu_usage) {
3056 remote_cpu_utilization = sctp_rr_result->cpu_util;
3057 /* since calc_service demand is doing ms/Kunit we will */
3058 /* multiply the number of transaction by 1024 to get */
3059 /* "good" numbers */
3060 remote_service_demand = calc_service_demand((double) nummessages*1024,
3061 0.0,
3062 remote_cpu_utilization,
3063 sctp_rr_result->num_cpus);
3064 }
3065 else {
3066 remote_cpu_utilization = (float) -1.0;
3067 remote_service_demand = (float) -1.0;
3068 }
3069
3070 }
3071 else {
3072 /* we were not measuring cpu, for the confidence stuff, we */
3073 /* should make it -1.0 */
3074 local_cpu_utilization = (float) -1.0;
3075 local_service_demand = (float) -1.0;
3076 remote_cpu_utilization = (float) -1.0;
3077 remote_service_demand = (float) -1.0;
3078 }
3079
3080 /* at this point, we want to calculate the confidence information. */
3081 /* if debugging is on, calculate_confidence will print-out the */
3082 /* parameters we pass it */
3083
3084 calculate_confidence(confidence_iteration,
3085 elapsed_time,
3086 thruput,
3087 local_cpu_utilization,
3088 remote_cpu_utilization,
3089 local_service_demand,
3090 remote_service_demand);
3091
3092
3093 confidence_iteration++;
3094
3095 /* we are now done with the socket, so close it */
3096 close(send_socket);
3097
3098 }
3099
3100 retrieve_confident_values(&elapsed_time,
3101 &thruput,
3102 &local_cpu_utilization,
3103 &remote_cpu_utilization,
3104 &local_service_demand,
3105 &remote_service_demand);
3106
3107 /* We are now ready to print all the information. If the user */
3108 /* has specified zero-level verbosity, we will just print the */
3109 /* local service demand, or the remote service demand. If the */
3110 /* user has requested verbosity level 1, he will get the basic */
3111 /* "streamperf" numbers. If the user has specified a verbosity */
3112 /* of greater than 1, we will display a veritable plethora of */
3113 /* background information from outside of this block as it it */
3114 /* not cpu_measurement specific... */
3115
3116 if (confidence < 0) {
3117 /* we did not hit confidence, but were we asked to look for it? */
3118 if (iteration_max > 1) {
3119 display_confidence();
3120 }
3121 }
3122
3123 if (local_cpu_usage || remote_cpu_usage) {
3124 local_cpu_method = format_cpu_method(cpu_method);
3125 remote_cpu_method = format_cpu_method(sctp_rr_result->cpu_method);
3126
3127 switch (verbosity) {
3128 case 0:
3129 if (local_cpu_usage) {
3130 fprintf(where,
3131 cpu_fmt_0,
3132 local_service_demand,
3133 local_cpu_method);
3134 }
3135 else {
3136 fprintf(where,
3137 cpu_fmt_0,
3138 remote_service_demand,
3139 remote_cpu_method);
3140 }
3141 break;
3142 case 1:
3143 case 2:
3144 if (print_headers) {
3145 fprintf(where,
3146 cpu_title,
3147 local_cpu_method,
3148 remote_cpu_method);
3149 }
3150
3151 fprintf(where,
3152 cpu_fmt_1_line_1, /* the format string */
3153 lss_size, /* local sendbuf size */
3154 lsr_size,
3155 req_size, /* how large were the requests */
3156 rsp_size, /* guess */
3157 elapsed_time, /* how long was the test */
3158 thruput,
3159 local_cpu_utilization, /* local cpu */
3160 remote_cpu_utilization, /* remote cpu */
3161 local_service_demand, /* local service demand */
3162 remote_service_demand); /* remote service demand */
3163 fprintf(where,
3164 cpu_fmt_1_line_2,
3165 rss_size,
3166 rsr_size);
3167 break;
3168 }
3169 }
3170 else {
3171 /* The tester did not wish to measure service demand. */
3172
3173 switch (verbosity) {
3174 case 0:
3175 fprintf(where,
3176 tput_fmt_0,
3177 thruput);
3178 break;
3179 case 1:
3180 case 2:
3181 if (print_headers) {
3182 fprintf(where,tput_title,format_units());
3183 }
3184
3185 fprintf(where,
3186 tput_fmt_1_line_1, /* the format string */
3187 lss_size,
3188 lsr_size,
3189 req_size, /* how large were the requests */
3190 rsp_size, /* how large were the responses */
3191 elapsed_time, /* how long did it take */
3192 thruput);
3193 fprintf(where,
3194 tput_fmt_1_line_2,
3195 rss_size, /* remote recvbuf size */
3196 rsr_size);
3197
3198 break;
3199 }
3200 }
3201
3202 /* it would be a good thing to include information about some of the */
3203 /* other parameters that may have been set for this test, but at the */
3204 /* moment, I do not wish to figure-out all the formatting, so I will */
3205 /* just put this comment here to help remind me that it is something */
3206 /* that should be done at a later time. */
3207
3208 /* how to handle the verbose information in the presence of */
3209 /* confidence intervals is yet to be determined... raj 11/94 */
3210 if (verbosity > 1) {
3211 /* The user wanted to know it all, so we will give it to him. */
3212 /* This information will include as much as we can find about */
3213 /* TCP statistics, the alignments of the sends and receives */
3214 /* and all that sort of rot... */
3215
3216 fprintf(where,
3217 ksink_fmt,
3218 local_send_align,
3219 remote_recv_offset,
3220 local_send_offset,
3221 remote_recv_offset);
3222
3223 #ifdef WANT_HISTOGRAM
3224 fprintf(where,"\nHistogram of request/response times\n");
3225 fflush(where);
3226 HIST_report(time_hist);
3227 #endif /* WANT_HISTOGRAM */
3228
3229 }
3230
3231 }
3232
3233
3234 /* this routine implements the receive (netserver) side of a TCP_RR */
3235 /* test */
3236 void
recv_sctp_rr(void)3237 recv_sctp_rr( void )
3238 {
3239
3240 struct ring_elt *send_ring;
3241 struct ring_elt *recv_ring;
3242
3243 struct addrinfo *local_res;
3244 char local_name[BUFSIZ];
3245 char port_buffer[PORTBUFSIZE];
3246
3247 struct sockaddr_in myaddr_in, peeraddr_in;
3248 int s_listen, s_data;
3249 socklen_t addrlen;
3250 char *temp_message_ptr;
3251 int trans_received;
3252 int trans_remaining;
3253 int bytes_sent;
3254 int request_bytes_recvd;
3255 int request_bytes_remaining;
3256 int timed_out = 0;
3257 float elapsed_time;
3258
3259 struct sctp_rr_request_struct *sctp_rr_request;
3260 struct sctp_rr_response_struct *sctp_rr_response;
3261 struct sctp_rr_results_struct *sctp_rr_results;
3262
3263 sctp_rr_request =
3264 (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data;
3265 sctp_rr_response =
3266 (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data;
3267 sctp_rr_results =
3268 (struct sctp_rr_results_struct *)netperf_response.content.test_specific_data;
3269
3270 if (debug) {
3271 fprintf(where,"netserver: recv_sctp_rr: entered...\n");
3272 fflush(where);
3273 }
3274
3275 /* We want to set-up the listen socket with all the desired */
3276 /* parameters and then let the initiator know that all is ready. If */
3277 /* socket size defaults are to be used, then the initiator will have */
3278 /* sent us 0's. If the socket sizes cannot be changed, then we will */
3279 /* send-back what they are. If that information cannot be determined, */
3280 /* then we send-back -1's for the sizes. If things go wrong for any */
3281 /* reason, we will drop back ten yards and punt. */
3282
3283 /* If anything goes wrong, we want the remote to know about it. It */
3284 /* would be best if the error that the remote reports to the user is */
3285 /* the actual error we encountered, rather than some bogus unexpected */
3286 /* response type message. */
3287
3288 if (debug) {
3289 fprintf(where,"recv_sctp_rr: setting the response type...\n");
3290 fflush(where);
3291 }
3292
3293 netperf_response.content.response_type = SCTP_RR_RESPONSE;
3294
3295 if (debug) {
3296 fprintf(where,"recv_sctp_rr: the response type is set...\n");
3297 fflush(where);
3298 }
3299
3300 /* allocate the recv and send rings with the requested alignments */
3301 /* and offsets. raj 7/94 */
3302 if (debug) {
3303 fprintf(where,"recv_sctp_rr: requested recv alignment of %d offset %d\n",
3304 sctp_rr_request->recv_alignment,
3305 sctp_rr_request->recv_offset);
3306 fprintf(where,"recv_sctp_rr: requested send alignment of %d offset %d\n",
3307 sctp_rr_request->send_alignment,
3308 sctp_rr_request->send_offset);
3309 fflush(where);
3310 }
3311
3312 /* at some point, these need to come to us from the remote system */
3313 if (send_width == 0) send_width = 1;
3314 if (recv_width == 0) recv_width = 1;
3315
3316 send_ring = allocate_buffer_ring(send_width,
3317 sctp_rr_request->response_size,
3318 sctp_rr_request->send_alignment,
3319 sctp_rr_request->send_offset);
3320
3321 recv_ring = allocate_buffer_ring(recv_width,
3322 sctp_rr_request->request_size,
3323 sctp_rr_request->recv_alignment,
3324 sctp_rr_request->recv_offset);
3325
3326
3327 /* Grab a socket to listen on, and then listen on it. */
3328
3329 if (debug) {
3330 fprintf(where,"recv_sctp_rr: grabbing a socket...\n");
3331 fflush(where);
3332 }
3333
3334 /* create_data_socket expects to find some things in the global */
3335 /* variables, so set the globals based on the values in the request. */
3336 /* once the socket has been created, we will set the response values */
3337 /* based on the updated value of those globals. raj 7/94 */
3338 lss_size_req = sctp_rr_request->send_buf_size;
3339 lsr_size_req = sctp_rr_request->recv_buf_size;
3340 loc_nodelay = sctp_rr_request->no_delay;
3341 loc_rcvavoid = sctp_rr_request->so_rcvavoid;
3342 loc_sndavoid = sctp_rr_request->so_sndavoid;
3343 non_block = sctp_rr_request->non_blocking;
3344
3345 set_hostname_and_port(local_name,
3346 port_buffer,
3347 nf_to_af(sctp_rr_request->ipfamily),
3348 sctp_rr_request->port);
3349
3350 local_res = complete_addrinfo(local_name,
3351 local_name,
3352 port_buffer,
3353 nf_to_af(sctp_rr_request->ipfamily),
3354 SOCK_STREAM,
3355 IPPROTO_SCTP,
3356 0);
3357
3358 s_listen = create_data_socket(local_res);
3359
3360 if (s_listen < 0) {
3361 netperf_response.content.serv_errno = errno;
3362 send_response();
3363
3364 exit(1);
3365 }
3366
3367 /* Now, let's set-up the socket to listen for connections */
3368 if (listen(s_listen, 5) == -1) {
3369 netperf_response.content.serv_errno = errno;
3370 close(s_listen);
3371 send_response();
3372
3373 exit(1);
3374 }
3375
3376
3377 /* now get the port number assigned by the system */
3378 addrlen = sizeof(myaddr_in);
3379 if (getsockname(s_listen,
3380 (struct sockaddr *)&myaddr_in, &addrlen) == -1){
3381 netperf_response.content.serv_errno = errno;
3382 close(s_listen);
3383 send_response();
3384
3385 exit(1);
3386 }
3387
3388 /* Now myaddr_in contains the port and the internet address this is */
3389 /* returned to the sender also implicitly telling the sender that the */
3390 /* socket buffer sizing has been done. */
3391
3392 sctp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
3393 netperf_response.content.serv_errno = 0;
3394
3395 /* But wait, there's more. If the initiator wanted cpu measurements, */
3396 /* then we must call the calibrate routine, which will return the max */
3397 /* rate back to the initiator. If the CPU was not to be measured, or */
3398 /* something went wrong with the calibration, we will return a 0.0 to */
3399 /* the initiator. */
3400
3401 sctp_rr_response->cpu_rate = (float)0.0; /* assume no cpu */
3402 sctp_rr_response->measure_cpu = 0;
3403
3404 if (sctp_rr_request->measure_cpu) {
3405 sctp_rr_response->measure_cpu = 1;
3406 sctp_rr_response->cpu_rate = calibrate_local_cpu(sctp_rr_request->cpu_rate);
3407 }
3408
3409
3410 /* before we send the response back to the initiator, pull some of */
3411 /* the socket parms from the globals */
3412 sctp_rr_response->send_buf_size = lss_size;
3413 sctp_rr_response->recv_buf_size = lsr_size;
3414 sctp_rr_response->no_delay = loc_nodelay;
3415 sctp_rr_response->so_rcvavoid = loc_rcvavoid;
3416 sctp_rr_response->so_sndavoid = loc_sndavoid;
3417 sctp_rr_response->test_length = sctp_rr_request->test_length;
3418 send_response();
3419
3420 addrlen = sizeof(peeraddr_in);
3421
3422 if ((s_data = accept(s_listen,
3423 (struct sockaddr *)&peeraddr_in,
3424 &addrlen)) == -1) {
3425 /* Let's just punt. The remote will be given some information */
3426 close(s_listen);
3427
3428 exit(1);
3429 }
3430
3431 /* we do not need events on a 1-to-1 RR test. The test will finish
3432 * once all transactions are done.
3433 */
3434
3435 /* now that we are connected, mark the socket as non-blocking */
3436 if (non_block) {
3437 if (!set_nonblock(s_data)) {
3438 perror("netperf: set_nonblock");
3439 exit(1);
3440 }
3441 }
3442
3443 #ifdef KLUDGE_SOCKET_OPTIONS
3444 /* this is for those systems which *INCORRECTLY* fail to pass */
3445 /* attributes across an accept() call. Including this goes against */
3446 /* my better judgement :( raj 11/95 */
3447
3448 kludge_socket_options(s_data);
3449
3450 #endif /* KLUDGE_SOCKET_OPTIONS */
3451
3452 if (debug) {
3453 fprintf(where,"recv_sctp_rr: accept completes on the data connection.\n");
3454 fflush(where);
3455 }
3456
3457 /* Now it's time to start receiving data on the connection. We will */
3458 /* first grab the apropriate counters and then start grabbing. */
3459
3460 cpu_start(sctp_rr_request->measure_cpu);
3461
3462 /* The loop will exit when we hit the end of the test time, or when */
3463 /* we have exchanged the requested number of transactions. */
3464
3465 if (sctp_rr_request->test_length > 0) {
3466 times_up = 0;
3467 trans_remaining = 0;
3468 start_timer(sctp_rr_request->test_length + PAD_TIME);
3469 }
3470 else {
3471 times_up = 1;
3472 trans_remaining = sctp_rr_request->test_length * -1;
3473 }
3474
3475 trans_received = 0;
3476
3477 while ((!times_up) || (trans_remaining > 0)) {
3478 int msg_flags = 0;
3479
3480 temp_message_ptr = recv_ring->buffer_ptr;
3481 request_bytes_remaining = sctp_rr_request->request_size;
3482 while(!(msg_flags & MSG_EOR)) {
3483 if((request_bytes_recvd=sctp_recvmsg(s_data,
3484 temp_message_ptr,
3485 request_bytes_remaining,
3486 NULL, 0,
3487 NULL, &msg_flags)) < 0) {
3488 if (errno == EINTR) {
3489 /* the timer popped */
3490 timed_out = 1;
3491 break;
3492 } else if (non_block && errno == EAGAIN) {
3493 continue; /* while request_bytes_remaining */
3494 }
3495 netperf_response.content.serv_errno = errno;
3496 send_response();
3497 exit(1);
3498 }
3499 request_bytes_remaining -= request_bytes_recvd;
3500 temp_message_ptr += request_bytes_recvd;
3501 }
3502
3503 recv_ring = recv_ring->next;
3504
3505 if (timed_out) {
3506 /* we hit the end of the test based on time - lets */
3507 /* bail out of here now... */
3508 if (debug) {
3509 fprintf(where,"yo55\n");
3510 fflush(where);
3511 }
3512 break;
3513 }
3514
3515
3516 /* Now, send the response to the remote
3517 * In 1-to-1 API destination addr is not needed.
3518 */
3519 while ((bytes_sent=sctp_sendmsg(s_data,
3520 send_ring->buffer_ptr,
3521 sctp_rr_request->response_size,
3522 NULL, 0,
3523 0, 0, 0, 0, 0)) == -1) {
3524 if (errno == EINTR) {
3525 /* the test timer has popped */
3526 timed_out = 1;
3527 break;
3528 } else if (non_block && errno == EAGAIN) {
3529 continue;
3530 }
3531
3532 netperf_response.content.serv_errno = 982;
3533 send_response();
3534 exit(1);
3535 }
3536
3537 if (timed_out) {
3538 /* we hit the end of the test based on time - lets */
3539 /* bail out of here now... */
3540 if (debug) {
3541 fprintf(where,"yo6\n");
3542 fflush(where);
3543 }
3544 break;
3545 }
3546
3547 send_ring = send_ring->next;
3548
3549 trans_received++;
3550 if (trans_remaining) {
3551 trans_remaining--;
3552 }
3553 }
3554
3555
3556 /* The loop now exits due to timeout or transaction count being */
3557 /* reached */
3558
3559 cpu_stop(sctp_rr_request->measure_cpu,&elapsed_time);
3560
3561 stop_timer();
3562
3563 if (timed_out) {
3564 /* we ended the test by time, which was at least 2 seconds */
3565 /* longer than we wanted to run. so, we want to subtract */
3566 /* PAD_TIME from the elapsed_time. */
3567 elapsed_time -= PAD_TIME;
3568 }
3569
3570 /* send the results to the sender */
3571
3572 if (debug) {
3573 fprintf(where,
3574 "recv_sctp_rr: got %d transactions\n",
3575 trans_received);
3576 fflush(where);
3577 }
3578
3579 sctp_rr_results->bytes_received = (trans_received *
3580 (sctp_rr_request->request_size +
3581 sctp_rr_request->response_size));
3582 sctp_rr_results->trans_received = trans_received;
3583 sctp_rr_results->elapsed_time = elapsed_time;
3584 sctp_rr_results->cpu_method = cpu_method;
3585 sctp_rr_results->num_cpus = lib_num_loc_cpus;
3586 if (sctp_rr_request->measure_cpu) {
3587 sctp_rr_results->cpu_util = calc_cpu_util(elapsed_time);
3588 }
3589
3590 if (debug) {
3591 fprintf(where,
3592 "recv_sctp_rr: test complete, sending results.\n");
3593 fflush(where);
3594 }
3595
3596 /* we are now done with the sockets */
3597 send_response();
3598
3599 close(s_data);
3600 close(s_listen);
3601
3602 }
3603
3604
3605
3606 /* this routine implements the sending (netperf) side of the
3607 SCTP_RR_1TOMANY test */
3608
3609 void
send_sctp_rr_1toMany(char remote_host[])3610 send_sctp_rr_1toMany( char remote_host[] )
3611 {
3612
3613 char *tput_title = "\
3614 Local /Remote\n\
3615 Socket Size Request Resp. Elapsed Trans.\n\
3616 Send Recv Size Size Time Rate \n\
3617 bytes Bytes bytes bytes secs. per sec \n\n";
3618
3619 char *tput_fmt_0 =
3620 "%7.2f\n";
3621
3622 char *tput_fmt_1_line_1 = "\
3623 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
3624 char *tput_fmt_1_line_2 = "\
3625 %-6d %-6d\n";
3626
3627 char *cpu_title = "\
3628 Local /Remote\n\
3629 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
3630 Send Recv Size Size Time Rate local remote local remote\n\
3631 bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
3632
3633 char *cpu_fmt_0 =
3634 "%6.3f %c\n";
3635
3636 char *cpu_fmt_1_line_1 = "\
3637 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
3638
3639 char *cpu_fmt_1_line_2 = "\
3640 %-6d %-6d\n";
3641
3642 char *ksink_fmt = "\
3643 Alignment Offset\n\
3644 Local Remote Local Remote\n\
3645 Send Recv Send Recv\n\
3646 %5d %5d %5d %5d\n";
3647
3648
3649 int timed_out = 0;
3650 float elapsed_time;
3651
3652 int len, j = 0;
3653 char *temp_message_ptr;
3654 int nummessages;
3655 int *send_socket;
3656 int trans_remaining;
3657 double bytes_xferd;
3658 int msg_flags = 0;
3659
3660 struct ring_elt *send_ring;
3661 struct ring_elt *recv_ring;
3662
3663 int rsp_bytes_left;
3664 int rsp_bytes_recvd;
3665
3666 float local_cpu_utilization;
3667 float local_service_demand;
3668 float remote_cpu_utilization;
3669 float remote_service_demand;
3670 double thruput;
3671
3672 struct addrinfo *local_res;
3673 struct addrinfo *remote_res;
3674
3675 struct sctp_rr_request_struct *sctp_rr_request;
3676 struct sctp_rr_response_struct *sctp_rr_response;
3677 struct sctp_rr_results_struct *sctp_rr_result;
3678
3679 #ifdef WANT_INTERVALS
3680 int interval_count;
3681 sigset_t signal_set;
3682 #endif /* WANT_INTERVALS */
3683
3684 sctp_rr_request =
3685 (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data;
3686 sctp_rr_response =
3687 (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data;
3688 sctp_rr_result =
3689 (struct sctp_rr_results_struct *)netperf_response.content.test_specific_data;
3690
3691 #ifdef WANT_HISTOGRAM
3692 time_hist = HIST_new_n(1);
3693 #endif /* WANT_HISTOGRAM */
3694
3695 /* since we are now disconnected from the code that established the */
3696 /* control socket, and since we want to be able to use different */
3697 /* protocols and such, we are passed the name of the remote host and */
3698 /* must turn that into the test specific addressing information. */
3699
3700 complete_addrinfos(&remote_res,
3701 &local_res,
3702 remote_host,
3703 SOCK_SEQPACKET,
3704 IPPROTO_SCTP,
3705 0);
3706
3707 if ( print_headers ) {
3708 print_top_test_header("SCTP 1-TO-MANY REQUEST/RESPONSE TEST",local_res,remote_res);
3709 }
3710
3711 /* initialize a few counters */
3712
3713 send_ring = NULL;
3714 recv_ring = NULL;
3715 confidence_iteration = 1;
3716 init_stat();
3717
3718 send_socket = malloc(sizeof(int) * num_associations);
3719 if (send_socket == NULL) {
3720 fprintf(where,
3721 "Could not create the socket array for %d associations",
3722 num_associations);
3723 fflush(where);
3724 exit(1);
3725 }
3726
3727 /* we have a great-big while loop which controls the number of times */
3728 /* we run a particular test. this is for the calculation of a */
3729 /* confidence interval (I really should have stayed awake during */
3730 /* probstats :). If the user did not request confidence measurement */
3731 /* (no confidence is the default) then we will only go though the */
3732 /* loop once. the confidence stuff originates from the folks at IBM */
3733
3734 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
3735 (confidence_iteration <= iteration_min)) {
3736
3737 /* initialize a few counters. we have to remember that we might be */
3738 /* going through the loop more than once. */
3739
3740 nummessages = 0;
3741 bytes_xferd = 0.0;
3742 times_up = 0;
3743 timed_out = 0;
3744 trans_remaining = 0;
3745
3746 /* set-up the data buffers with the requested alignment and offset. */
3747 /* since this is a request/response test, default the send_width and */
3748 /* recv_width to 1 and not two raj 7/94 */
3749
3750 if (send_width == 0) send_width = 1;
3751 if (recv_width == 0) recv_width = 1;
3752
3753 if (send_ring == NULL) {
3754 send_ring = allocate_buffer_ring(send_width,
3755 req_size,
3756 local_send_align,
3757 local_send_offset);
3758 }
3759
3760 if (recv_ring == NULL) {
3761 recv_ring = allocate_buffer_ring(recv_width,
3762 rsp_size,
3763 local_recv_align,
3764 local_recv_offset);
3765 }
3766
3767 /* If the user has requested cpu utilization measurements, we must */
3768 /* calibrate the cpu(s). We will perform this task within the tests */
3769 /* themselves. If the user has specified the cpu rate, then */
3770 /* calibrate_local_cpu will return rather quickly as it will have */
3771 /* nothing to do. If local_cpu_rate is zero, then we will go through */
3772 /* all the "normal" calibration stuff and return the rate back.*/
3773
3774 if (local_cpu_usage) {
3775 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
3776 }
3777
3778 /* Tell the remote end to do a listen. The server alters the socket */
3779 /* paramters on the other side at this point, hence the reason for */
3780 /* all the values being passed in the setup message. If the user did */
3781 /* not specify any of the parameters, they will be passed as 0, which */
3782 /* will indicate to the remote that no changes beyond the system's */
3783 /* default should be used. Alignment is the exception, it will */
3784 /* default to 8, which will be no alignment alterations. */
3785
3786 netperf_request.content.request_type = DO_SCTP_RR_MANY;
3787 sctp_rr_request->recv_buf_size = rsr_size_req;
3788 sctp_rr_request->send_buf_size = rss_size_req;
3789 sctp_rr_request->recv_alignment = remote_recv_align;
3790 sctp_rr_request->recv_offset = remote_recv_offset;
3791 sctp_rr_request->send_alignment = remote_send_align;
3792 sctp_rr_request->send_offset = remote_send_offset;
3793 sctp_rr_request->request_size = req_size;
3794 sctp_rr_request->response_size = rsp_size;
3795 sctp_rr_request->no_delay = rem_nodelay;
3796 sctp_rr_request->measure_cpu = remote_cpu_usage;
3797 sctp_rr_request->cpu_rate = remote_cpu_rate;
3798 sctp_rr_request->so_rcvavoid = rem_rcvavoid;
3799 sctp_rr_request->so_sndavoid = rem_sndavoid;
3800 if (test_time) {
3801 sctp_rr_request->test_length = test_time;
3802 }
3803 else {
3804 sctp_rr_request->test_length = test_trans * num_associations
3805 * -1;
3806 }
3807 sctp_rr_request->non_blocking = non_block;
3808 sctp_rr_request->port = atoi(remote_data_port);
3809 sctp_rr_request->ipfamily = af_to_nf(remote_res->ai_family);
3810 if (debug > 1) {
3811 fprintf(where,"netperf: send_sctp_rr_1toMany: requesting SCTP rr test\n");
3812 }
3813
3814 send_request();
3815
3816 /* The response from the remote will contain all of the relevant */
3817 /* socket parameters for this test type. We will put them back into */
3818 /* the variables here so they can be displayed if desired. The */
3819 /* remote will have calibrated CPU if necessary, and will have done */
3820 /* all the needed set-up we will have calibrated the cpu locally */
3821 /* before sending the request, and will grab the counter value right*/
3822 /* after the connect returns. The remote will grab the counter right*/
3823 /* after the accept call. This saves the hassle of extra messages */
3824 /* being sent for the sctp tests. */
3825
3826 recv_response();
3827
3828 if (!netperf_response.content.serv_errno) {
3829 rsr_size = sctp_rr_response->recv_buf_size;
3830 rss_size = sctp_rr_response->send_buf_size;
3831 rem_nodelay = sctp_rr_response->no_delay;
3832 remote_cpu_usage = sctp_rr_response->measure_cpu;
3833 remote_cpu_rate = sctp_rr_response->cpu_rate;
3834 /* make sure that port numbers are in network order */
3835 set_port_number(remote_res,
3836 (unsigned short)sctp_rr_response->data_port_number);
3837 }
3838 else {
3839 Set_errno(netperf_response.content.serv_errno);
3840 fprintf(where,
3841 "netperf: remote error %d",
3842 netperf_response.content.serv_errno);
3843 perror("");
3844 fflush(where);
3845
3846 exit(1);
3847 }
3848
3849 /*set up the data socket list */
3850 for (j = 0; j < num_associations; j++) {
3851 send_socket[j] = create_data_socket(local_res);
3852
3853 if (send_socket < 0){
3854 perror("netperf: send_sctp_rr_1toMany: sctp stream data socket");
3855 exit(1);
3856 }
3857
3858 /*Connect up to the remote port on the data socket */
3859 if (connect(send_socket[j],
3860 remote_res->ai_addr,
3861 remote_res->ai_addrlen) < 0){
3862 perror("netperf: data socket connect failed");
3863
3864 exit(1);
3865 }
3866
3867 /* The client end of the 1-to-Many test uses 1-to-1 sockets.
3868 * it doesn't need events.
3869 */
3870 sctp_enable_events(send_socket[j], 0);
3871
3872 if (non_block) {
3873 if (!set_nonblock(send_socket[j])) {
3874 close(send_socket[j]);
3875 exit(1);
3876 }
3877 }
3878 }
3879
3880 /* Data Socket set-up is finished. If there were problems, either the */
3881 /* connect would have failed, or the previous response would have */
3882 /* indicated a problem. I failed to see the value of the extra */
3883 /* message after the accept on the remote. If it failed, we'll see it */
3884 /* here. If it didn't, we might as well start pumping data. */
3885
3886 /* Set-up the test end conditions. For a request/response test, they */
3887 /* can be either time or transaction based. */
3888
3889 if (test_time) {
3890 /* The user wanted to end the test after a period of time. */
3891 times_up = 0;
3892 trans_remaining = 0;
3893 start_timer(test_time);
3894 }
3895 else {
3896 /* The tester wanted to send a number of bytes. */
3897 trans_remaining = test_bytes * num_associations;
3898 times_up = 1;
3899 }
3900
3901 /* The cpu_start routine will grab the current time and possibly */
3902 /* value of the idle counter for later use in measuring cpu */
3903 /* utilization and/or service demand and thruput. */
3904
3905 cpu_start(local_cpu_usage);
3906
3907 #ifdef WANT_INTERVALS
3908 if ((interval_burst) || (demo_mode)) {
3909 /* zero means that we never pause, so we never should need the */
3910 /* interval timer, unless we are in demo_mode */
3911 start_itimer(interval_wate);
3912 }
3913 interval_count = interval_burst;
3914 /* get the signal set for the call to sigsuspend */
3915 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
3916 fprintf(where,
3917 "send_sctp_rr_1toMany: unable to get sigmask errno %d\n",
3918 errno);
3919 fflush(where);
3920 exit(1);
3921 }
3922 #endif /* WANT_INTERVALS */
3923
3924 /* We use an "OR" to control test execution. When the test is */
3925 /* controlled by time, the byte count check will always return false. */
3926 /* When the test is controlled by byte count, the time test will */
3927 /* always return false. When the test is finished, the whole */
3928 /* expression will go false and we will stop sending data. I think I */
3929 /* just arbitrarily decrement trans_remaining for the timed test, but */
3930 /* will not do that just yet... One other question is whether or not */
3931 /* the send buffer and the receive buffer should be the same buffer. */
3932
3933 #ifdef WANT_FIRST_BURST
3934 {
3935 int i;
3936 for (j = 0; j < num_associations; j++) {
3937 for (i = 0; i < first_burst_size; i++) {
3938 if((len=sctp_sendmsg(send_socket[j],
3939 send_ring->buffer_ptr, send_size,
3940 remote_res->ai_addr,
3941 remote_res->ai_addrlen,
3942 0, 0, 0, 0, 0)) != req_size) {
3943 /* we should never hit the end of the test in the first burst */
3944 perror("send_sctp_rr_1toMany: initial burst data send error");
3945 exit(1);
3946 }
3947 }
3948 }
3949 }
3950 #endif /* WANT_FIRST_BURST */
3951
3952 while ((!times_up) || (trans_remaining > 0)) {
3953 /* send the request. we assume that if we use a blocking socket, */
3954 /* the request will be sent at one shot. */
3955
3956 /* this is a fairly poor way of testing 1toMany connections.
3957 * For each association we measure round trip time to account for
3958 * any delay in lookups and delivery. To stress the server a bit
3959 * more we would need a distributed client test, or at least multiple
3960 * processes. I want to force as much paralellism as possible, but
3961 * this will do for the fist take. vlad
3962 */
3963 for (j = 0; j < num_associations; j++) {
3964 #ifdef WANT_HISTOGRAM
3965 /* timestamp just before our call to send, and then again just */
3966 /* after the receive raj 8/94 */
3967 HIST_timestamp_start(time_hist);
3968 #endif /* WANT_HISTOGRAM */
3969
3970 while ((len=sctp_sendmsg(send_socket[j],
3971 send_ring->buffer_ptr, send_size,
3972 remote_res->ai_addr,
3973 remote_res->ai_addrlen,
3974 0, 0, 0, 0, 0)) != req_size) {
3975 if (non_block && errno == EAGAIN) {
3976 /* try sending again */
3977 continue;
3978 } else if ((errno == EINTR) || (errno == 0)) {
3979 /* we hit the end of a */
3980 /* timed test. */
3981 timed_out = 1;
3982 break;
3983 }
3984 perror("send_sctp_rr_1toMany: data send error");
3985 exit(1);
3986 }
3987
3988 if (timed_out) {
3989 /* we may have been in a nested while loop - we need */
3990 /* another call to break. */
3991 break;
3992 }
3993
3994 /* setup for the next time */
3995 send_ring = send_ring->next;
3996
3997 rsp_bytes_left = rsp_size;
3998 temp_message_ptr = recv_ring->buffer_ptr;
3999 while (!(msg_flags & MSG_EOR)) {
4000 if((rsp_bytes_recvd = sctp_recvmsg(send_socket[j],
4001 temp_message_ptr,
4002 rsp_bytes_left,
4003 NULL, 0,
4004 NULL, &msg_flags)) < 0) {
4005 if (errno == EINTR) {
4006 /* We hit the end of a timed test. */
4007 timed_out = 1;
4008 break;
4009 } else if (non_block && errno == EAGAIN) {
4010 continue;
4011 }
4012 perror("send_sctp_rr_1toMany: data recv error");
4013 exit(1);
4014 }
4015 rsp_bytes_left -= rsp_bytes_recvd;
4016 temp_message_ptr += rsp_bytes_recvd;
4017 }
4018 recv_ring = recv_ring->next;
4019
4020 if (timed_out) {
4021 /* we may have been in a nested while loop - we need */
4022 /* another call to break. */
4023 break;
4024 }
4025
4026 #ifdef WANT_HISTOGRAM
4027 HIST_timestamp_stop_add(time_hist);
4028 #endif /* WANT_HISTOGRAM */
4029
4030 nummessages++;
4031 if (trans_remaining) {
4032 trans_remaining--;
4033 }
4034
4035 if (debug > 3) {
4036 if ((nummessages % 100) == 0) {
4037 fprintf(where,
4038 "Transaction %d completed\n",
4039 nummessages);
4040 fflush(where);
4041 }
4042 }
4043 }
4044 }
4045
4046 /* At this point we used to call shutdown on the data socket to be */
4047 /* sure all the data was delivered, but this was not germane in a */
4048 /* request/response test, and it was causing the tests to "hang" when */
4049 /* they were being controlled by time. So, I have replaced this */
4050 /* shutdown call with a call to close that can be found later in the */
4051 /* procedure. */
4052
4053 /* this call will always give us the elapsed time for the test, and */
4054 /* will also store-away the necessaries for cpu utilization */
4055
4056 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
4057 /* measured? how long */
4058 /* did we really run? */
4059
4060 /* Get the statistics from the remote end. The remote will have */
4061 /* calculated CPU utilization. If it wasn't supposed to care, it */
4062 /* will return obvious values. */
4063
4064 recv_response();
4065 if (!netperf_response.content.serv_errno) {
4066 if (debug)
4067 fprintf(where,"remote results obtained\n");
4068 }
4069 else {
4070 Set_errno(netperf_response.content.serv_errno);
4071 fprintf(where,"netperf: remote error %d",
4072 netperf_response.content.serv_errno);
4073 perror("");
4074 fflush(where);
4075 exit(1);
4076 }
4077
4078 /* We now calculate what our throughput was for the test. */
4079
4080 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
4081 thruput = nummessages/elapsed_time;
4082
4083 if (local_cpu_usage || remote_cpu_usage) {
4084 /* We must now do a little math for service demand and cpu */
4085 /* utilization for the system(s) */
4086 /* Of course, some of the information might be bogus because */
4087 /* there was no idle counter in the kernel(s). We need to make */
4088 /* a note of this for the user's benefit...*/
4089 if (local_cpu_usage) {
4090 local_cpu_utilization = calc_cpu_util(0.0);
4091 /* since calc_service demand is doing ms/Kunit we will */
4092 /* multiply the number of transaction by 1024 to get */
4093 /* "good" numbers */
4094 local_service_demand = calc_service_demand((double) nummessages*1024,
4095 0.0,
4096 0.0,
4097 0);
4098 }
4099 else {
4100 local_cpu_utilization = (float) -1.0;
4101 local_service_demand = (float) -1.0;
4102 }
4103
4104 if (remote_cpu_usage) {
4105 remote_cpu_utilization = sctp_rr_result->cpu_util;
4106 /* since calc_service demand is doing ms/Kunit we will */
4107 /* multiply the number of transaction by 1024 to get */
4108 /* "good" numbers */
4109 remote_service_demand = calc_service_demand((double) nummessages*1024,
4110 0.0,
4111 remote_cpu_utilization,
4112 sctp_rr_result->num_cpus);
4113 }
4114 else {
4115 remote_cpu_utilization = (float) -1.0;
4116 remote_service_demand = (float) -1.0;
4117 }
4118
4119 }
4120 else {
4121 /* we were not measuring cpu, for the confidence stuff, we */
4122 /* should make it -1.0 */
4123 local_cpu_utilization = (float) -1.0;
4124 local_service_demand = (float) -1.0;
4125 remote_cpu_utilization = (float) -1.0;
4126 remote_service_demand = (float) -1.0;
4127 }
4128
4129 /* at this point, we want to calculate the confidence information. */
4130 /* if debugging is on, calculate_confidence will print-out the */
4131 /* parameters we pass it */
4132
4133 calculate_confidence(confidence_iteration,
4134 elapsed_time,
4135 thruput,
4136 local_cpu_utilization,
4137 remote_cpu_utilization,
4138 local_service_demand,
4139 remote_service_demand);
4140
4141
4142 confidence_iteration++;
4143
4144 /* we are now done with the socket, so close it */
4145 for (j = 0; j < num_associations; j++)
4146 close(send_socket[j]);
4147 }
4148
4149 retrieve_confident_values(&elapsed_time,
4150 &thruput,
4151 &local_cpu_utilization,
4152 &remote_cpu_utilization,
4153 &local_service_demand,
4154 &remote_service_demand);
4155
4156 /* We are now ready to print all the information. If the user */
4157 /* has specified zero-level verbosity, we will just print the */
4158 /* local service demand, or the remote service demand. If the */
4159 /* user has requested verbosity level 1, he will get the basic */
4160 /* "streamperf" numbers. If the user has specified a verbosity */
4161 /* of greater than 1, we will display a veritable plethora of */
4162 /* background information from outside of this block as it it */
4163 /* not cpu_measurement specific... */
4164
4165 if (confidence < 0) {
4166 /* we did not hit confidence, but were we asked to look for it? */
4167 if (iteration_max > 1) {
4168 display_confidence();
4169 }
4170 }
4171
4172 if (local_cpu_usage || remote_cpu_usage) {
4173 local_cpu_method = format_cpu_method(cpu_method);
4174 remote_cpu_method = format_cpu_method(sctp_rr_result->cpu_method);
4175
4176 switch (verbosity) {
4177 case 0:
4178 if (local_cpu_usage) {
4179 fprintf(where,
4180 cpu_fmt_0,
4181 local_service_demand,
4182 local_cpu_method);
4183 }
4184 else {
4185 fprintf(where,
4186 cpu_fmt_0,
4187 remote_service_demand,
4188 remote_cpu_method);
4189 }
4190 break;
4191 case 1:
4192 case 2:
4193 if (print_headers) {
4194 fprintf(where,
4195 cpu_title,
4196 local_cpu_method,
4197 remote_cpu_method);
4198 }
4199
4200 fprintf(where,
4201 cpu_fmt_1_line_1, /* the format string */
4202 lss_size, /* local sendbuf size */
4203 lsr_size,
4204 req_size, /* how large were the requests */
4205 rsp_size, /* guess */
4206 elapsed_time, /* how long was the test */
4207 thruput,
4208 local_cpu_utilization, /* local cpu */
4209 remote_cpu_utilization, /* remote cpu */
4210 local_service_demand, /* local service demand */
4211 remote_service_demand); /* remote service demand */
4212 fprintf(where,
4213 cpu_fmt_1_line_2,
4214 rss_size,
4215 rsr_size);
4216 break;
4217 }
4218 }
4219 else {
4220 /* The tester did not wish to measure service demand. */
4221
4222 switch (verbosity) {
4223 case 0:
4224 fprintf(where,
4225 tput_fmt_0,
4226 thruput);
4227 break;
4228 case 1:
4229 case 2:
4230 if (print_headers) {
4231 fprintf(where,tput_title,format_units());
4232 }
4233
4234 fprintf(where,
4235 tput_fmt_1_line_1, /* the format string */
4236 lss_size,
4237 lsr_size,
4238 req_size, /* how large were the requests */
4239 rsp_size, /* how large were the responses */
4240 elapsed_time, /* how long did it take */
4241 thruput);
4242 fprintf(where,
4243 tput_fmt_1_line_2,
4244 rss_size, /* remote recvbuf size */
4245 rsr_size);
4246
4247 break;
4248 }
4249 }
4250
4251 /* it would be a good thing to include information about some of the */
4252 /* other parameters that may have been set for this test, but at the */
4253 /* moment, I do not wish to figure-out all the formatting, so I will */
4254 /* just put this comment here to help remind me that it is something */
4255 /* that should be done at a later time. */
4256
4257 /* how to handle the verbose information in the presence of */
4258 /* confidence intervals is yet to be determined... raj 11/94 */
4259 if (verbosity > 1) {
4260 /* The user wanted to know it all, so we will give it to him. */
4261 /* This information will include as much as we can find about */
4262 /* TCP statistics, the alignments of the sends and receives */
4263 /* and all that sort of rot... */
4264
4265 fprintf(where,
4266 ksink_fmt,
4267 local_send_align,
4268 remote_recv_offset,
4269 local_send_offset,
4270 remote_recv_offset);
4271
4272 #ifdef WANT_HISTOGRAM
4273 fprintf(where,"\nHistogram of request/response times\n");
4274 fflush(where);
4275 HIST_report(time_hist);
4276 #endif /* WANT_HISTOGRAM */
4277
4278 }
4279
4280 }
4281
4282
4283 /* this routine implements the receive (netserver) side of a TCP_RR */
4284 /* test */
4285 void
recv_sctp_rr_1toMany(void)4286 recv_sctp_rr_1toMany( void )
4287 {
4288
4289 struct ring_elt *send_ring;
4290 struct ring_elt *recv_ring;
4291
4292
4293 struct sockaddr_in myaddr_in; /* needed to get the port number */
4294 struct sockaddr_storage peeraddr; /* to communicate with peer */
4295 struct addrinfo *local_res;
4296 char local_name[BUFSIZ];
4297 char port_buffer[PORTBUFSIZE];
4298 int msg_flags;
4299
4300 int s_rcv;
4301 socklen_t addrlen;
4302 int trans_received;
4303 int trans_remaining;
4304 int bytes_sent;
4305 int bytes_recvd;
4306 int recv_buf_size;
4307 int timed_out = 0;
4308 float elapsed_time;
4309
4310 struct sctp_rr_request_struct *sctp_rr_request;
4311 struct sctp_rr_response_struct *sctp_rr_response;
4312 struct sctp_rr_results_struct *sctp_rr_results;
4313
4314 sctp_rr_request =
4315 (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data;
4316 sctp_rr_response =
4317 (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data;
4318 sctp_rr_results =
4319 (struct sctp_rr_results_struct *)netperf_response.content.test_specific_data;
4320
4321 if (debug) {
4322 fprintf(where,"netserver: recv_sctp_rr_1toMany: entered...\n");
4323 fflush(where);
4324 }
4325
4326 /* We want to set-up the listen socket with all the desired */
4327 /* parameters and then let the initiator know that all is ready. If */
4328 /* socket size defaults are to be used, then the initiator will have */
4329 /* sent us 0's. If the socket sizes cannot be changed, then we will */
4330 /* send-back what they are. If that information cannot be determined, */
4331 /* then we send-back -1's for the sizes. If things go wrong for any */
4332 /* reason, we will drop back ten yards and punt. */
4333
4334 /* If anything goes wrong, we want the remote to know about it. It */
4335 /* would be best if the error that the remote reports to the user is */
4336 /* the actual error we encountered, rather than some bogus unexpected */
4337 /* response type message. */
4338
4339 if (debug) {
4340 fprintf(where,"recv_sctp_rr_1toMany: setting the response type...\n");
4341 fflush(where);
4342 }
4343
4344 netperf_response.content.response_type = SCTP_RR_MANY_RESPONSE;
4345
4346 if (debug) {
4347 fprintf(where,"recv_sctp_rr_1toMany: the response type is set...\n");
4348 fflush(where);
4349 }
4350
4351 /* allocate the recv and send rings with the requested alignments */
4352 /* and offsets. raj 7/94 */
4353 if (debug) {
4354 fprintf(where,"recv_sctp_rr_1toMany: requested recv alignment of %d offset %d\n",
4355 sctp_rr_request->recv_alignment,
4356 sctp_rr_request->recv_offset);
4357 fprintf(where,"recv_sctp_rr_1toMany: requested send alignment of %d offset %d\n",
4358 sctp_rr_request->send_alignment,
4359 sctp_rr_request->send_offset);
4360 fflush(where);
4361 }
4362
4363 /* at some point, these need to come to us from the remote system */
4364 if (send_width == 0) send_width = 1;
4365 if (recv_width == 0) recv_width = 1;
4366
4367 send_ring = allocate_buffer_ring(send_width,
4368 sctp_rr_request->response_size,
4369 sctp_rr_request->send_alignment,
4370 sctp_rr_request->send_offset);
4371
4372 recv_ring = allocate_buffer_ring(recv_width,
4373 sctp_rr_request->request_size,
4374 sctp_rr_request->recv_alignment,
4375 sctp_rr_request->recv_offset);
4376
4377
4378 /* create_data_socket expects to find some things in the global */
4379 /* variables, so set the globals based on the values in the request. */
4380 /* once the socket has been created, we will set the response values */
4381 /* based on the updated value of those globals. raj 7/94 */
4382 lss_size_req = sctp_rr_request->send_buf_size;
4383 lsr_size_req = sctp_rr_request->recv_buf_size;
4384 loc_nodelay = sctp_rr_request->no_delay;
4385 loc_rcvavoid = sctp_rr_request->so_rcvavoid;
4386 loc_sndavoid = sctp_rr_request->so_sndavoid;
4387 non_block = sctp_rr_request->non_blocking;
4388
4389 set_hostname_and_port(local_name,
4390 port_buffer,
4391 nf_to_af(sctp_rr_request->ipfamily),
4392 sctp_rr_request->port);
4393
4394 local_res = complete_addrinfo(local_name,
4395 local_name,
4396 port_buffer,
4397 nf_to_af(sctp_rr_request->ipfamily),
4398 SOCK_SEQPACKET,
4399 IPPROTO_SCTP,
4400 0);
4401
4402 /* Grab a socket to listen on, and then listen on it. */
4403 if (debug) {
4404 fprintf(where,"recv_sctp_rr_1toMany: grabbing a socket...\n");
4405 fflush(where);
4406 }
4407
4408 s_rcv = create_data_socket(local_res);
4409
4410 if (s_rcv < 0) {
4411 netperf_response.content.serv_errno = errno;
4412 send_response();
4413
4414 exit(1);
4415 }
4416
4417 /* Now, let's set-up the socket to listen for connections */
4418 if (listen(s_rcv, 5) == -1) {
4419 netperf_response.content.serv_errno = errno;
4420 close(s_rcv);
4421 send_response();
4422
4423 exit(1);
4424 }
4425
4426
4427 /* now get the port number assigned by the system */
4428 addrlen = sizeof(myaddr_in);
4429 if (getsockname(s_rcv,
4430 (struct sockaddr *)&myaddr_in, &addrlen) == -1){
4431 netperf_response.content.serv_errno = errno;
4432 close(s_rcv);
4433 send_response();
4434
4435 exit(1);
4436 }
4437
4438 /* Now myaddr_in contains the port and the internet address this is */
4439 /* returned to the sender also implicitly telling the sender that the */
4440 /* socket buffer sizing has been done. */
4441
4442 sctp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
4443 netperf_response.content.serv_errno = 0;
4444
4445 /* But wait, there's more. If the initiator wanted cpu measurements, */
4446 /* then we must call the calibrate routine, which will return the max */
4447 /* rate back to the initiator. If the CPU was not to be measured, or */
4448 /* something went wrong with the calibration, we will return a 0.0 to */
4449 /* the initiator. */
4450
4451 sctp_rr_response->cpu_rate = (float)0.0; /* assume no cpu */
4452 sctp_rr_response->measure_cpu = 0;
4453
4454 if (sctp_rr_request->measure_cpu) {
4455 sctp_rr_response->measure_cpu = 1;
4456 sctp_rr_response->cpu_rate = calibrate_local_cpu(sctp_rr_request->cpu_rate);
4457 }
4458
4459
4460 /* before we send the response back to the initiator, pull some of */
4461 /* the socket parms from the globals */
4462 sctp_rr_response->send_buf_size = lss_size;
4463 sctp_rr_response->recv_buf_size = lsr_size;
4464 sctp_rr_response->no_delay = loc_nodelay;
4465 sctp_rr_response->so_rcvavoid = loc_rcvavoid;
4466 sctp_rr_response->so_sndavoid = loc_sndavoid;
4467 sctp_rr_response->test_length = sctp_rr_request->test_length;
4468 send_response();
4469
4470 /* Don't need events */
4471 sctp_enable_events(s_rcv, 0);
4472
4473 /* now that we are connected, mark the socket as non-blocking */
4474 if (non_block) {
4475 if (!set_nonblock(s_rcv)) {
4476 perror("netperf: set_nonblock");
4477 exit(1);
4478 }
4479 }
4480
4481 /* FIXME: The way 1-to-Many test operates right now, we are including
4482 * association setup time into our measurements. The reason for this
4483 * is that the client creates multiple endpoints and connects each
4484 * endpoint to us using the connect call. On this end we simply call
4485 * recvmsg() to get data becuase there is no equivalen of accept() for
4486 * 1-to-Many API.
4487 * I think this is OK, but if it were to be fixed, the server side
4488 * would need to know how many associations are being setup and
4489 * have a recvmsg() loop with SCTP_ASSOC_CHANGE events waiting for
4490 * all the associations to be be established.
4491 * I am punting on this for now.
4492 */
4493
4494
4495 addrlen = sizeof(peeraddr);
4496
4497 /* Now it's time to start receiving data on the connection. We will */
4498 /* first grab the apropriate counters and then start grabbing. */
4499
4500 cpu_start(sctp_rr_request->measure_cpu);
4501
4502 /* The loop will exit when we hit the end of the test time, or when */
4503 /* we have exchanged the requested number of transactions. */
4504
4505 if (sctp_rr_request->test_length > 0) {
4506 times_up = 0;
4507 trans_remaining = 0;
4508 start_timer(sctp_rr_request->test_length + PAD_TIME);
4509 }
4510 else {
4511 times_up = 1;
4512 trans_remaining = sctp_rr_request->test_length * -1;
4513 }
4514
4515 trans_received = 0;
4516
4517 while ((!times_up) || (trans_remaining > 0)) {
4518
4519 recv_buf_size = sctp_rr_request->request_size;
4520
4521 /* Receive the data. We don't particularly care which association
4522 * the data came in on. We'll simply be doing a receive untill
4523 * we get and MSG_EOR flag (meaning that a single transmission was
4524 * received) and a send to the same address, so the RR would be for
4525 * the same associations.
4526 * We can get away with this because the client will establish all
4527 * the associations before transmitting any data. Any partial data
4528 * will not have EOR thus will we will not send a response untill
4529 * we get everything.
4530 */
4531
4532 do {
4533 msg_flags = 0;
4534 if((bytes_recvd = sctp_recvmsg(s_rcv,
4535 recv_ring->buffer_ptr,
4536 recv_buf_size,
4537 (struct sockaddr *)&peeraddr, &addrlen,
4538 0, &msg_flags)) == SOCKET_ERROR) {
4539 if (SOCKET_EINTR(bytes_recvd)) {
4540 /* the timer popped */
4541 timed_out = 1;
4542 break;
4543 } else if (non_block && errno == EAGAIN) {
4544 /* do recvmsg again */
4545 continue;
4546 }
4547 netperf_response.content.serv_errno = errno;
4548 send_response();
4549 exit(1);
4550 }
4551 } while(!(msg_flags & MSG_EOR));
4552
4553 recv_ring = recv_ring->next;
4554
4555 if (timed_out) {
4556 /* we hit the end of the test based on time - lets */
4557 /* bail out of here now... */
4558 if (debug) {
4559 fprintf(where,"yo5\n");
4560 fflush(where);
4561 }
4562 break;
4563 }
4564
4565 /* Now, send the response to the remote */
4566 while ((bytes_sent=sctp_sendmsg(s_rcv,
4567 send_ring->buffer_ptr,
4568 sctp_rr_request->response_size,
4569 (struct sockaddr *)&peeraddr, addrlen,
4570 0, 0, 0, 0, 0)) == SOCKET_ERROR) {
4571 if (SOCKET_EINTR(bytes_sent)) {
4572 /* the test timer has popped */
4573 timed_out = 1;
4574 break;
4575 } else if (non_block && errno == EAGAIN) {
4576 continue;
4577 }
4578
4579 netperf_response.content.serv_errno = 992;
4580 send_response();
4581 exit(1);
4582 }
4583
4584 if (timed_out) {
4585 if (debug) {
4586 fprintf(where,"yo6\n");
4587 fflush(where);
4588 }
4589 /* we hit the end of the test based on time - lets */
4590 /* bail out of here now... */
4591 break;
4592 }
4593
4594 send_ring = send_ring->next;
4595
4596 trans_received++;
4597 if (trans_remaining) {
4598 trans_remaining--;
4599 }
4600 }
4601
4602
4603 /* The loop now exits due to timeout or transaction count being */
4604 /* reached */
4605
4606 cpu_stop(sctp_rr_request->measure_cpu,&elapsed_time);
4607
4608 stop_timer();
4609
4610 if (timed_out) {
4611 /* we ended the test by time, which was at least 2 seconds */
4612 /* longer than we wanted to run. so, we want to subtract */
4613 /* PAD_TIME from the elapsed_time. */
4614 elapsed_time -= PAD_TIME;
4615 }
4616
4617 /* send the results to the sender */
4618
4619 if (debug) {
4620 fprintf(where,
4621 "recv_sctp_rr: got %d transactions\n",
4622 trans_received);
4623 fflush(where);
4624 }
4625
4626 sctp_rr_results->bytes_received = (trans_received *
4627 (sctp_rr_request->request_size +
4628 sctp_rr_request->response_size));
4629 sctp_rr_results->trans_received = trans_received;
4630 sctp_rr_results->elapsed_time = elapsed_time;
4631 sctp_rr_results->cpu_method = cpu_method;
4632 sctp_rr_results->num_cpus = lib_num_loc_cpus;
4633 if (sctp_rr_request->measure_cpu) {
4634 sctp_rr_results->cpu_util = calc_cpu_util(elapsed_time);
4635 }
4636
4637 if (debug) {
4638 fprintf(where,
4639 "recv_sctp_rr: test complete, sending results.\n");
4640 fflush(where);
4641 }
4642
4643 /* we are now done with the sockets */
4644 close(s_rcv);
4645
4646 send_response();
4647
4648 }
4649
4650
4651 void
print_sctp_usage(void)4652 print_sctp_usage( void )
4653 {
4654
4655 printf("%s",sctp_usage);
4656 exit(1);
4657
4658 }
4659
4660 void
scan_sctp_args(int argc,char * argv[])4661 scan_sctp_args( int argc, char *argv[] )
4662 {
4663
4664 #define SOCKETS_ARGS "BDhH:I:L:m:M:P:r:s:S:VN:T:46"
4665
4666 extern char *optarg; /* pointer to option string */
4667
4668 int c;
4669
4670 char
4671 arg1[BUFSIZ], /* argument holders */
4672 arg2[BUFSIZ];
4673
4674 if (no_control) {
4675 fprintf(where,
4676 "The SCTP tests do not know how to deal with no control tests\n");
4677 exit(-1);
4678 }
4679
4680 strncpy(local_data_port,"0",sizeof(local_data_port));
4681 strncpy(remote_data_port,"0",sizeof(remote_data_port));
4682
4683 /* Go through all the command line arguments and break them */
4684 /* out. For those options that take two parms, specifying only */
4685 /* the first will set both to that value. Specifying only the */
4686 /* second will leave the first untouched. To change only the */
4687 /* first, use the form "first," (see the routine break_args.. */
4688
4689 while ((c= getopt(argc, argv, SOCKETS_ARGS)) != EOF) {
4690 switch (c) {
4691 case '?':
4692 case '4':
4693 remote_data_family = AF_INET;
4694 local_data_family = AF_INET;
4695 break;
4696 case '6':
4697 #if defined(AF_INET6)
4698 remote_data_family = AF_INET6;
4699 local_data_family = AF_INET6;
4700 #else
4701 fprintf(stderr,
4702 "This netperf was not compiled on an IPv6 capable host!\n");
4703 fflush(stderr);
4704 exit(-1);
4705 #endif
4706 break;
4707 case 'h':
4708 print_sctp_usage();
4709 exit(1);
4710 case 'b':
4711 #ifdef WANT_FIRST_BURST
4712 first_burst_size = atoi(optarg);
4713 #else /* WANT_FIRST_BURST */
4714 printf("Initial request burst functionality not compiled-in!\n");
4715 #endif /* WANT_FIRST_BURST */
4716 break;
4717 case 'D':
4718 /* set the nodelay flag */
4719 loc_nodelay = 1;
4720 rem_nodelay = 1;
4721 break;
4722 case 'H':
4723 break_args_explicit(optarg,arg1,arg2);
4724 if (arg1[0]) {
4725 /* make sure we leave room for the NULL termination boys and
4726 girls. raj 2005-02-82 */
4727 remote_data_address = malloc(strlen(arg1)+1);
4728 strncpy(remote_data_address,arg1,strlen(arg1));
4729 }
4730 if (arg2[0])
4731 remote_data_family = parse_address_family(arg2);
4732 break;
4733 case 'L':
4734 break_args_explicit(optarg,arg1,arg2);
4735 if (arg1[0]) {
4736 /* make sure we leave room for the NULL termination boys and
4737 girls. raj 2005-02-82 */
4738 local_data_address = malloc(strlen(arg1)+1);
4739 strncpy(local_data_address,arg1,strlen(arg1));
4740 }
4741 if (arg2[0])
4742 local_data_family = parse_address_family(arg2);
4743 break;
4744 case 'P':
4745 /* set the local and remote data port numbers for the tests to
4746 allow them to run through those blankety blank end-to-end
4747 breaking firewalls. raj 2004-06-15 */
4748 break_args(optarg,arg1,arg2);
4749 if (arg1[0])
4750 strncpy(local_data_port,arg1,sizeof(local_data_port));
4751 if (arg2[0])
4752 strncpy(remote_data_port,arg2,sizeof(remote_data_port));
4753 break;
4754 case 's':
4755 /* set local socket sizes */
4756 break_args(optarg,arg1,arg2);
4757 if (arg1[0])
4758 lss_size_req = convert(arg1);
4759 if (arg2[0])
4760 lsr_size_req = convert(arg2);
4761 break;
4762 case 'S':
4763 /* set remote socket sizes */
4764 break_args(optarg,arg1,arg2);
4765 if (arg1[0])
4766 rss_size_req = convert(arg1);
4767 if (arg2[0])
4768 rsr_size_req = convert(arg2);
4769 break;
4770 case 'r':
4771 /* set the request/response sizes */
4772 break_args(optarg,arg1,arg2);
4773 if (arg1[0])
4774 req_size = convert(arg1);
4775 if (arg2[0])
4776 rsp_size = convert(arg2);
4777 break;
4778 case 'm':
4779 /* set size of the buffer for each sent message */
4780 send_size = convert(optarg);
4781 break;
4782 case 'M':
4783 /* set the size of the buffer for each received message */
4784 recv_size = convert(optarg);
4785 break;
4786 case 't':
4787 /* set the test name */
4788 strcpy(test_name,optarg);
4789 break;
4790 case 'W':
4791 /* set the "width" of the user space data */
4792 /* buffer. This will be the number of */
4793 /* send_size buffers malloc'd in the */
4794 /* *_STREAM test. It may be enhanced to set */
4795 /* both send and receive "widths" but for now */
4796 /* it is just the sending *_STREAM. */
4797 send_width = convert(optarg);
4798 break;
4799 case 'V':
4800 /* we want to do copy avoidance and will set */
4801 /* it for everything, everywhere, if we really */
4802 /* can. of course, we don't know anything */
4803 /* about the remote... */
4804 #ifdef SO_SND_COPYAVOID
4805 loc_sndavoid = 1;
4806 #else
4807 loc_sndavoid = 0;
4808 printf("Local send copy avoidance not available.\n");
4809 #endif
4810 #ifdef SO_RCV_COPYAVOID
4811 loc_rcvavoid = 1;
4812 #else
4813 loc_rcvavoid = 0;
4814 printf("Local recv copy avoidance not available.\n");
4815 #endif
4816 rem_sndavoid = 1;
4817 rem_rcvavoid = 1;
4818 break;
4819 case 'N':
4820 /* this opton allows the user to set the number of
4821 * messages to send. This in effect modifies the test
4822 * time. If we know the message size, then the we can
4823 * express the test time as message_size * number_messages
4824 */
4825 msg_count = convert (optarg);
4826 if (msg_count > 0)
4827 test_time = 0;
4828 break;
4829 case 'B':
4830 non_block = 1;
4831 break;
4832 case 'T':
4833 num_associations = atoi(optarg);
4834 if (num_associations <= 1) {
4835 printf("Number of SCTP associations must be >= 1\n");
4836 exit(1);
4837 }
4838 break;
4839 };
4840 }
4841 }
4842
4843 #endif /* WANT_SCTP */
4844