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