1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4
5 #ifdef WANT_XTI
6 #ifndef lint
7 char nettest_xti_id[]="\
8 @(#)nettest_xti.c (c) Copyright 1995-2012 Hewlett-Packard Co. Version 2.6.0";
9 #else
10 #define DIRTY
11 #define WANT_HISTOGRAM
12 #define WANT_INTERVALS
13 #endif /* lint */
14
15 #ifdef WIN32
16 #error XTI Interface tests are not available under Windows
17 #endif
18
19 /****************************************************************/
20 /* */
21 /* nettest_xti.c */
22 /* */
23 /* the XTI args parsing routine... */
24 /* */
25 /* scan_xti_args() */
26 /* */
27 /* the actual test routines... */
28 /* */
29 /* send_xti_tcp_stream() perform a tcp stream test */
30 /* recv_xti_tcp_stream() */
31 /* send_xti_tcp_rr() perform a tcp request/response */
32 /* recv_xti_tcp_rr() */
33 /* send_xti_tcp_conn_rr() an RR test including connect */
34 /* recv_xti_tcp_conn_rr() */
35 /* send_xti_udp_stream() perform a udp stream test */
36 /* recv_xti_udp_stream() */
37 /* send_xti_udp_rr() perform a udp request/response */
38 /* recv_xti_udp_rr() */
39 /* */
40 /****************************************************************/
41
42 #ifdef HAVE_CONFIG_H
43 #include <config.h>
44 #endif
45
46 #include <sys/types.h>
47 #include <fcntl.h>
48 #if defined(HAVE_SYS_IPC_H)
49 #include <sys/ipc.h>
50 #endif
51 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <netdb.h>
54 #include <errno.h>
55 #include <signal.h>
56 #include <stdio.h>
57 #include <time.h>
58 #include <malloc.h>
59 /* xti.h should be included *after* in.h because there are name */
60 /* conflicts!( Silly standards people... raj 2/95 fortuenately, the */
61 /* confilcts are on IP_TOP and IP_TTL, whcih netperf does not yet use */
62 #include <xti.h>
63
64 #include "netlib.h"
65 #include "netsh.h"
66 #include "nettest_xti.h"
67
68 #ifdef WANT_HISTOGRAM
69 #ifdef __sgi
70 #include <sys/time.h>
71 #endif /* __sgi */
72 #include "hist.h"
73 #endif /* WANT_HISTOGRAM */
74
75
76
77 /* these variables are specific to the XTI sockets tests. declare */
78 /* them static to make them global only to this file. */
79
80 static int
81 rss_size, /* remote socket send buffer size */
82 rsr_size, /* remote socket recv buffer size */
83 lss_size, /* local socket send buffer size */
84 lsr_size, /* local socket recv buffer size */
85 req_size = 1, /* request size */
86 rsp_size = 1, /* response size */
87 send_size, /* how big are individual sends */
88 recv_size; /* how big are individual receives */
89
90 static int confidence_iteration;
91 static char local_cpu_method;
92 static char remote_cpu_method;
93
94 /* different options for the xti */
95
96 static int
97 loc_nodelay, /* don't/do use NODELAY locally */
98 rem_nodelay, /* don't/do use NODELAY remotely */
99 loc_sndavoid, /* avoid send copies locally */
100 loc_rcvavoid, /* avoid recv copies locally */
101 rem_sndavoid, /* avoid send copies remotely */
102 rem_rcvavoid; /* avoid recv_copies remotely */
103
104 static struct t_info info_struct;
105
106 #ifdef WANT_HISTOGRAM
107 #ifdef HAVE_GETHRTIME
108 hrtime_t time_one;
109 hrtime_t time_two;
110 #else
111 static struct timeval time_one;
112 static struct timeval time_two;
113 #endif /* HAVE_GETHRTIME */
114 static HIST time_hist;
115 #endif /* WANT_HISTOGRAM */
116
117 static char loc_xti_device[32] = "/dev/tcp";
118 static char rem_xti_device[32] = "/dev/tcp";
119
120 static int xti_flags = 0;
121
122 char xti_usage[] = "\n\
123 Usage: netperf [global options] -- [test options] \n\
124 \n\
125 TCP/UDP XTI API Test Options:\n\
126 -D [L][,R] Set XTI_TCP_NODELAY locally and/or remotely (XTI_TCP_*)\n\
127 -h Display this text\n\
128 -m bytes Set the send size (XTI_TCP_STREAM, XTI_UDP_STREAM)\n\
129 -M bytes Set the recv size (XTI_TCP_STREAM, XTI_UDP_STREAM)\n\
130 -r bytes Set request size (XTI_TCP_RR, XTI_UDP_RR)\n\
131 -R bytes Set response size (XTI_TCP_RR, XTI_UDP_RR)\n\
132 -s send[,recv] Set local socket send/recv buffer sizes\n\
133 -S send[,recv] Set remote socket send/recv buffer sizes\n\
134 -X dev[,dev] Set the local/remote XTI device file name\n\
135 \n\
136 For those options taking two parms, at least one must be specified;\n\
137 specifying one value without a comma will set both parms to that\n\
138 value, specifying a value with a leading comma will set just the second\n\
139 parm, a value with a trailing comma will set just the first. To set\n\
140 each parm to unique values, specify both and separate them with a\n\
141 comma.\n";
142
143
144 /* This routine is intended to retrieve interesting aspects of tcp */
145 /* for the data connection. at first, it attempts to retrieve the */
146 /* maximum segment size. later, it might be modified to retrieve */
147 /* other information, but it must be information that can be */
148 /* retrieved quickly as it is called during the timing of the test. */
149 /* for that reason, a second routine may be created that can be */
150 /* called outside of the timing loop */
151 void
get_xti_info(socket,info_struct)152 get_xti_info(socket, info_struct)
153 int socket;
154 struct t_info *info_struct;
155 {
156
157 }
158
159
160 /* This routine will create a data (listen) socket with the apropriate */
161 /* options set and return it to the caller. this replaces all the */
162 /* duplicate code in each of the test routines and should help make */
163 /* things a little easier to understand. since this routine can be */
164 /* called by either the netperf or netserver programs, all output */
165 /* should be directed towards "where." family is generally AF_INET, */
166 /* and type will be either SOCK_STREAM or SOCK_DGRAM */
167 SOCKET
create_xti_endpoint(char * name)168 create_xti_endpoint(char *name)
169 {
170
171 SOCKET temp_socket;
172
173 struct t_optmgmt *opt_req; /* we request an option */
174 struct t_optmgmt *opt_ret; /* it tells us what we got */
175
176 /* we use this to pass-in BSD-like socket options through t_optmgmt. */
177 /* it ends up being about as clear as mud. raj 2/95 */
178 struct sock_option {
179 struct t_opthdr myopthdr;
180 long value;
181 } *sock_option;
182
183 if (debug) {
184 fprintf(where,"create_xti_endpoint: attempting to open %s\n",
185 name);
186 fflush(where);
187 }
188
189 /*set up the data socket */
190 temp_socket = t_open(name,O_RDWR,NULL);
191
192 if (temp_socket == INVALID_SOCKET){
193 fprintf(where,
194 "netperf: create_xti_endpoint: t_open %s: errno %d t_errno %d\n",
195 name,
196 errno,
197 t_errno);
198 fflush(where);
199 exit(1);
200 }
201
202 if (debug) {
203 fprintf(where,"create_xti_endpoint: socket %d obtained...\n",temp_socket);
204 fflush(where);
205 }
206
207 /* allocate what we need for option mgmt */
208 if ((opt_req = (struct t_optmgmt *)t_alloc(temp_socket,T_OPTMGMT,T_ALL)) ==
209 NULL) {
210 fprintf(where,
211 "netperf: create_xti_endpoint: t_alloc: opt_req errno %d\n",
212 errno);
213 fflush(where);
214 exit(1);
215 }
216
217 if (debug) {
218 fprintf(where,
219 "create_xti_endpoint: opt_req->opt.buf %x maxlen %d len %d\n",
220 opt_req->opt.buf,
221 opt_req->opt.maxlen,
222 opt_req->opt.len);
223
224 fflush(where);
225 }
226
227 if ((opt_ret = (struct t_optmgmt *) t_alloc(temp_socket,T_OPTMGMT,T_ALL)) ==
228 NULL) {
229 fprintf(where,
230 "netperf: create_xti_endpoint: t_alloc: opt_ret errno %d\n",
231 errno);
232 fflush(where);
233 exit(1);
234 }
235
236 if (debug) {
237 fprintf(where,
238 "create_xti_endpoint: opt_ret->opt.buf %x maxlen %d len %d\n",
239 opt_ret->opt.buf,
240 opt_ret->opt.maxlen,
241 opt_ret->opt.len);
242 fflush(where);
243 }
244
245 /* Modify the local socket size. The reason we alter the send buffer */
246 /* size here rather than when the connection is made is to take care */
247 /* of decreases in buffer size. Decreasing the window size after */
248 /* connection establishment is a TCP no-no. Also, by setting the */
249 /* buffer (window) size before the connection is established, we can */
250 /* control the TCP MSS (segment size). The MSS is never more that 1/2 */
251 /* the minimum receive buffer size at each half of the connection. */
252 /* This is why we are altering the receive buffer size on the sending */
253 /* size of a unidirectional transfer. If the user has not requested */
254 /* that the socket buffers be altered, we will try to find-out what */
255 /* their values are. If we cannot touch the socket buffer in any way, */
256 /* we will set the values to -1 to indicate that. */
257
258 #ifdef XTI_SNDBUF
259 if (lss_size > 0) {
260 /* we want to "negotiate" the option */
261 opt_req->flags = T_NEGOTIATE;
262 }
263 else {
264 /* we want to accept the default, and know what it is. I assume */
265 /* that when nothing has been changed, that T_CURRENT will return */
266 /* the same as T_DEFAULT raj 3/95 */
267 opt_req->flags = T_CURRENT;
268 }
269
270 /* the first part is for the netbuf that holds the option we want */
271 /* to negotiate or check */
272 /* the buffer of the netbuf points at the socket options structure */
273
274 /* we assume that the t_alloc call allocated a buffer that started */
275 /* on a proper alignment */
276 sock_option = (struct sock_option *)opt_req->opt.buf;
277
278 /* and next, set the fields in the sock_option structure */
279 sock_option->myopthdr.level = XTI_GENERIC;
280 sock_option->myopthdr.name = XTI_SNDBUF;
281 sock_option->myopthdr.len = sizeof(struct t_opthdr) + sizeof(long);
282 sock_option->value = lss_size;
283
284 opt_req->opt.len = sizeof(struct t_opthdr) + sizeof(long);
285
286 /* now, set-up the stuff to return the value in the end */
287 /* we assume that the t_alloc call allocated a buffer that started */
288 /* on a proper alignment */
289 sock_option = (struct sock_option *)opt_ret->opt.buf;
290
291 /* finally, call t_optmgmt. clear as mud. */
292 if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) {
293 fprintf(where,
294 "netperf: create_xti_endpoint: XTI_SNDBUF option: t_errno %d\n",
295 t_errno);
296 fflush(where);
297 exit(1);
298 }
299
300 if (sock_option->myopthdr.status == T_SUCCESS) {
301 lss_size = sock_option->value;
302 }
303 else {
304 fprintf(where,"create_xti_endpoint: XTI_SNDBUF option status 0x%.4x",
305 sock_option->myopthdr.status);
306 fprintf(where," value %d\n",
307 sock_option->value);
308 fflush(where);
309 lss_size = -1;
310 }
311
312 if (lsr_size > 0) {
313 /* we want to "negotiate" the option */
314 opt_req->flags = T_NEGOTIATE;
315 }
316 else {
317 /* we want to accept the default, and know what it is. I assume */
318 /* that when nothing has been changed, that T_CURRENT will return */
319 /* the same as T_DEFAULT raj 3/95 */
320 opt_req->flags = T_CURRENT;
321 }
322
323 /* the first part is for the netbuf that holds the option we want */
324 /* to negotiate or check */
325 /* the buffer of the netbuf points at the socket options structure */
326
327 /* we assume that the t_alloc call allocated a buffer that started */
328 /* on a proper alignment */
329 sock_option = (struct sock_option *)opt_req->opt.buf;
330
331 /* and next, set the fields in the sock_option structure */
332 sock_option->myopthdr.level = XTI_GENERIC;
333 sock_option->myopthdr.name = XTI_RCVBUF;
334 sock_option->myopthdr.len = sizeof(struct t_opthdr) + sizeof(long);
335 sock_option->value = lsr_size;
336
337 opt_req->opt.len = sizeof(struct t_opthdr) + sizeof(long);
338
339 /* now, set-up the stuff to return the value in the end */
340 /* we assume that the t_alloc call allocated a buffer that started */
341 /* on a proper alignment */
342 sock_option = (struct sock_option *)opt_ret->opt.buf;
343
344 /* finally, call t_optmgmt. clear as mud. */
345 if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) {
346 fprintf(where,
347 "netperf: create_xti_endpoint: XTI_RCVBUF option: t_errno %d\n",
348 t_errno);
349 fflush(where);
350 exit(1);
351 }
352 lsr_size = sock_option->value;
353
354 /* this needs code */
355
356 if (debug) {
357 fprintf(where,"netperf: create_xti_endpoint: socket sizes determined...\n");
358 fprintf(where," send: %d recv: %d\n",
359 lss_size,lsr_size);
360 fflush(where);
361 }
362
363 #else /* XTI_SNDBUF */
364
365 lss_size = -1;
366 lsr_size = -1;
367
368 #endif /* XTI_SNDBUF */
369
370 /* now, we may wish to enable the copy avoidance features on the */
371 /* local system. of course, this may not be possible... */
372
373 if (loc_rcvavoid) {
374 fprintf(where,
375 "netperf: create_xti_endpoint: Could not enable receive copy avoidance");
376 fflush(where);
377 loc_rcvavoid = 0;
378 }
379
380 if (loc_sndavoid) {
381 fprintf(where,
382 "netperf: create_xti_endpoint: Could not enable send copy avoidance");
383 fflush(where);
384 loc_sndavoid = 0;
385 }
386
387 /* Now, we will see about setting the TCP_NODELAY flag on the local */
388 /* socket. We will only do this for those systems that actually */
389 /* support the option. If it fails, note the fact, but keep going. */
390 /* If the user tries to enable TCP_NODELAY on a UDP socket, this */
391 /* will cause an error to be displayed */
392
393 #ifdef TCP_NODELAY
394 if ((strcmp(test_name,"XTI_TCP_STREAM") == 0) ||
395 (strcmp(test_name,"XTI_TCP_RR") == 0) ||
396 (strcmp(test_name,"XTI_TCP_CRR") == 0)) {
397 if (loc_nodelay) {
398 /* we want to "negotiate" the option */
399 opt_req->flags = T_NEGOTIATE;
400 }
401 else {
402 /* we want to accept the default, and know what it is. I assume */
403 /* that when nothing has been changed, that T_CURRENT will return */
404 /* the same as T_DEFAULT raj 3/95 */
405 opt_req->flags = T_CURRENT;
406 }
407
408 /* the first part is for the netbuf that holds the option we want */
409 /* to negotiate or check the buffer of the netbuf points at the */
410 /* socket options structure */
411
412 /* we assume that the t_alloc call allocated a buffer that started */
413 /* on a proper alignment */
414 sock_option = (struct sock_option *)opt_req->opt.buf;
415
416 /* and next, set the fields in the sock_option structure */
417 sock_option->myopthdr.level = INET_TCP;
418 sock_option->myopthdr.name = TCP_NODELAY;
419 sock_option->myopthdr.len = sizeof(struct t_opthdr) + sizeof(long);
420 sock_option->value = T_YES;
421
422 opt_req->opt.len = sizeof(struct t_opthdr) + sizeof(long);
423
424 /* now, set-up the stuff to return the value in the end */
425 /* we assume that the t_alloc call allocated a buffer that started */
426 /* on a proper alignment */
427 sock_option = (struct sock_option *)opt_ret->opt.buf;
428
429 /* finally, call t_optmgmt. clear as mud. */
430 if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) {
431 fprintf(where,
432 "create_xti_endpoint: TCP_NODELAY option: errno %d t_errno %d\n",
433 errno,
434 t_errno);
435 fflush(where);
436 exit(1);
437 }
438 loc_nodelay = sock_option->value;
439 }
440 #else /* TCP_NODELAY */
441
442 loc_nodelay = 0;
443
444 #endif /* TCP_NODELAY */
445
446 return(temp_socket);
447
448 }
449
450
451 /* This routine implements the TCP unidirectional data transfer test */
452 /* (a.k.a. stream) for the xti interface. It receives its */
453 /* parameters via global variables from the shell and writes its */
454 /* output to the standard output. */
455
456
457 void
send_xti_tcp_stream(char remote_host[])458 send_xti_tcp_stream(char remote_host[])
459 {
460
461 char *tput_title = "\
462 Recv Send Send \n\
463 Socket Socket Message Elapsed \n\
464 Size Size Size Time Throughput \n\
465 bytes bytes bytes secs. %s/sec \n\n";
466
467 char *tput_fmt_0 =
468 "%7.2f\n";
469
470 char *tput_fmt_1 =
471 "%6d %6d %6d %-6.2f %7.2f \n";
472
473 char *cpu_title = "\
474 Recv Send Send Utilization Service Demand\n\
475 Socket Socket Message Elapsed Send Recv Send Recv\n\
476 Size Size Size Time Throughput local remote local remote\n\
477 bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n";
478
479 char *cpu_fmt_0 =
480 "%6.3f %c\n";
481
482 char *cpu_fmt_1 =
483 "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
484
485 char *ksink_fmt = "\n\
486 Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\
487 Local Remote Local Remote Xfered Per Per\n\
488 Send Recv Send Recv Send (avg) Recv (avg)\n\
489 %5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n";
490
491 char *ksink_fmt2 = "\n\
492 Maximum\n\
493 Segment\n\
494 Size (bytes)\n\
495 %6d\n";
496
497
498 float elapsed_time;
499
500 #ifdef WANT_INTERVALS
501 int interval_count;
502 sigset_t signal_set;
503 #endif
504
505 /* what we want is to have a buffer space that is at least one */
506 /* send-size greater than our send window. this will insure that we */
507 /* are never trying to re-use a buffer that may still be in the hands */
508 /* of the transport. This buffer will be malloc'd after we have found */
509 /* the size of the local senc socket buffer. We will want to deal */
510 /* with alignment and offset concerns as well. */
511
512 int *message_int_ptr;
513
514 struct ring_elt *send_ring;
515
516 int len;
517 unsigned int nummessages;
518 SOCKET send_socket;
519 int bytes_remaining;
520 int tcp_mss = -1; /* possibly uninitialized on printf far below */
521
522 /* with links like fddi, one can send > 32 bits worth of bytes */
523 /* during a test... ;-) at some point, this should probably become a */
524 /* 64bit integral type, but those are not entirely common yet */
525
526 double bytes_sent;
527
528 float local_cpu_utilization;
529 float local_service_demand;
530 float remote_cpu_utilization;
531 float remote_service_demand;
532
533 double thruput;
534
535 /* some addressing information */
536 struct hostent *hp;
537 struct sockaddr_in server;
538 unsigned int addr;
539
540 struct t_call server_call;
541
542 struct xti_tcp_stream_request_struct *xti_tcp_stream_request;
543 struct xti_tcp_stream_response_struct *xti_tcp_stream_response;
544 struct xti_tcp_stream_results_struct *xti_tcp_stream_result;
545
546 xti_tcp_stream_request =
547 (struct xti_tcp_stream_request_struct *)netperf_request.content.test_specific_data;
548 xti_tcp_stream_response =
549 (struct xti_tcp_stream_response_struct *)netperf_response.content.test_specific_data;
550 xti_tcp_stream_result =
551 (struct xti_tcp_stream_results_struct *)netperf_response.content.test_specific_data;
552
553 #ifdef WANT_HISTOGRAM
554 time_hist = HIST_new();
555 #endif /* WANT_HISTOGRAM */
556 /* since we are now disconnected from the code that established the */
557 /* control socket, and since we want to be able to use different */
558 /* protocols and such, we are passed the name of the remote host and */
559 /* must turn that into the test specific addressing information. */
560
561 bzero((char *)&server,
562 sizeof(server));
563
564 /* it would seem that while HP-UX will allow an IP address (as a */
565 /* string) in a call to gethostbyname, other, less enlightened */
566 /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */
567 /* order changed to check for IP address first. raj 7/96 */
568
569 if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
570 /* it was not an IP address, try it as a name */
571 if ((hp = gethostbyname(remote_host)) == NULL) {
572 /* we have no idea what it is */
573 fprintf(where,
574 "establish_control: could not resolve the destination %s\n",
575 remote_host);
576 fflush(where);
577 exit(1);
578 }
579 else {
580 /* it was a valid remote_host */
581 bcopy(hp->h_addr,
582 (char *)&server.sin_addr,
583 hp->h_length);
584 server.sin_family = hp->h_addrtype;
585 }
586 }
587 else {
588 /* it was a valid IP address */
589 server.sin_addr.s_addr = addr;
590 server.sin_family = AF_INET;
591 }
592
593 if ( print_headers ) {
594 /* we want to have some additional, interesting information in */
595 /* the headers. we know some of it here, but not all, so we will */
596 /* only print the test title here and will print the results */
597 /* titles after the test is finished */
598 fprintf(where,"XTI TCP STREAM TEST");
599 fprintf(where," to %s", remote_host);
600 if (iteration_max > 1) {
601 fprintf(where,
602 " : +/-%3.1f%% @ %2d%% conf.",
603 interval/0.02,
604 confidence_level);
605 }
606 if (loc_nodelay || rem_nodelay) {
607 fprintf(where," : nodelay");
608 }
609 if (loc_sndavoid ||
610 loc_rcvavoid ||
611 rem_sndavoid ||
612 rem_rcvavoid) {
613 fprintf(where," : copy avoidance");
614 }
615 #ifdef WANT_HISTOGRAM
616 fprintf(where," : histogram");
617 #endif /* WANT_HISTOGRAM */
618 #ifdef WANT_INTERVALS
619 fprintf(where," : interval");
620 #endif /* WANT_INTERVALS */
621 #ifdef DIRTY
622 fprintf(where," : dirty data");
623 #endif /* DIRTY */
624 fprintf(where,"\n");
625 }
626
627 send_ring = NULL;
628 confidence_iteration = 1;
629 init_stat();
630
631 /* we have a great-big while loop which controls the number of times */
632 /* we run a particular test. this is for the calculation of a */
633 /* confidence interval (I really should have stayed awake during */
634 /* probstats :). If the user did not request confidence measurement */
635 /* (no confidence is the default) then we will only go though the */
636 /* loop once. the confidence stuff originates from the folks at IBM */
637
638 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
639 (confidence_iteration <= iteration_min)) {
640
641 /* initialize a few counters. we have to remember that we might be */
642 /* going through the loop more than once. */
643
644 nummessages = 0;
645 bytes_sent = 0.0;
646 times_up = 0;
647
648 /*set up the data socket */
649 send_socket = create_xti_endpoint(loc_xti_device);
650
651 if (send_socket == INVALID_SOCKET) {
652 perror("netperf: send_xti_tcp_stream: tcp stream data socket");
653 exit(1);
654 }
655
656 if (debug) {
657 fprintf(where,"send_xti_tcp_stream: send_socket obtained...\n");
658 }
659
660 /* it would seem that with XTI, there is no implicit bind on a */
661 /* connect, so we have to make a call to t_bind. this is not */
662 /* terribly convenient, but I suppose that "standard is better */
663 /* than better" :) raj 2/95 */
664
665 if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) {
666 t_error("send_xti_tcp_stream: t_bind");
667 exit(1);
668 }
669
670 /* at this point, we have either retrieved the socket buffer sizes, */
671 /* or have tried to set them, so now, we may want to set the send */
672 /* size based on that (because the user either did not use a -m */
673 /* option, or used one with an argument of 0). If the socket buffer */
674 /* size is not available, we will set the send size to 4KB - no */
675 /* particular reason, just arbitrary... */
676 if (send_size == 0) {
677 if (lss_size > 0) {
678 send_size = lss_size;
679 }
680 else {
681 send_size = 4096;
682 }
683 }
684
685 /* set-up the data buffer ring with the requested alignment and offset. */
686 /* note also that we have allocated a quantity */
687 /* of memory that is at least one send-size greater than our socket */
688 /* buffer size. We want to be sure that there are at least two */
689 /* buffers allocated - this can be a bit of a problem when the */
690 /* send_size is bigger than the socket size, so we must check... the */
691 /* user may have wanted to explicitly set the "width" of our send */
692 /* buffers, we should respect that wish... */
693
694 if (send_width == 0) {
695 send_width = (lss_size/send_size) + 1;
696 if (send_width == 1) send_width++;
697 }
698
699 if (send_ring == NULL) {
700 /* only allocate the send ring once. this is a networking test, */
701 /* not a memory allocation test. this way, we do not need a */
702 /* deallocate_buffer_ring() routine, and I don't feel like */
703 /* writing one anyway :) raj 11/94 */
704 send_ring = allocate_buffer_ring(send_width,
705 send_size,
706 local_send_align,
707 local_send_offset);
708 }
709
710 /* If the user has requested cpu utilization measurements, we must */
711 /* calibrate the cpu(s). We will perform this task within the tests */
712 /* themselves. If the user has specified the cpu rate, then */
713 /* calibrate_local_cpu will return rather quickly as it will have */
714 /* nothing to do. If local_cpu_rate is zero, then we will go through */
715 /* all the "normal" calibration stuff and return the rate back. */
716
717 if (local_cpu_usage) {
718 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
719 }
720
721 /* Tell the remote end to do a listen. The server alters the socket */
722 /* paramters on the other side at this point, hence the reason for */
723 /* all the values being passed in the setup message. If the user did */
724 /* not specify any of the parameters, they will be passed as 0, which */
725 /* will indicate to the remote that no changes beyond the system's */
726 /* default should be used. Alignment is the exception, it will */
727 /* default to 1, which will be no alignment alterations. */
728
729 netperf_request.content.request_type = DO_XTI_TCP_STREAM;
730 xti_tcp_stream_request->send_buf_size = rss_size;
731 xti_tcp_stream_request->recv_buf_size = rsr_size;
732 xti_tcp_stream_request->receive_size = recv_size;
733 xti_tcp_stream_request->no_delay = rem_nodelay;
734 xti_tcp_stream_request->recv_alignment = remote_recv_align;
735 xti_tcp_stream_request->recv_offset = remote_recv_offset;
736 xti_tcp_stream_request->measure_cpu = remote_cpu_usage;
737 xti_tcp_stream_request->cpu_rate = remote_cpu_rate;
738 if (test_time) {
739 xti_tcp_stream_request->test_length = test_time;
740 }
741 else {
742 xti_tcp_stream_request->test_length = test_bytes;
743 }
744 xti_tcp_stream_request->so_rcvavoid = rem_rcvavoid;
745 xti_tcp_stream_request->so_sndavoid = rem_sndavoid;
746
747 strcpy(xti_tcp_stream_request->xti_device, rem_xti_device);
748
749 #ifdef __alpha
750
751 /* ok - even on a DEC box, strings are strings. I didn't really want */
752 /* to ntohl the words of a string. since I don't want to teach the */
753 /* send_ and recv_ _request and _response routines about the types, */
754 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
755 /* solution would be to use XDR, but I am still leary of being able */
756 /* to find XDR libs on all platforms I want running netperf. raj */
757 {
758 int *charword;
759 int *initword;
760 int *lastword;
761
762 initword = (int *) xti_tcp_stream_request->xti_device;
763 lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
764
765 for (charword = initword;
766 charword < lastword;
767 charword++) {
768
769 *charword = ntohl(*charword);
770 }
771 }
772 #endif /* __alpha */
773
774 #ifdef DIRTY
775 xti_tcp_stream_request->dirty_count = rem_dirty_count;
776 xti_tcp_stream_request->clean_count = rem_clean_count;
777 #endif /* DIRTY */
778
779
780 if (debug > 1) {
781 fprintf(where,
782 "netperf: send_xti_tcp_stream: requesting TCP stream test\n");
783 }
784
785 send_request();
786
787 /* The response from the remote will contain all of the relevant */
788 /* socket parameters for this test type. We will put them back into */
789 /* the variables here so they can be displayed if desired. The */
790 /* remote will have calibrated CPU if necessary, and will have done */
791 /* all the needed set-up we will have calibrated the cpu locally */
792 /* before sending the request, and will grab the counter value right*/
793 /* after the connect returns. The remote will grab the counter right*/
794 /* after the accept call. This saves the hassle of extra messages */
795 /* being sent for the TCP tests. */
796
797 recv_response();
798
799 if (!netperf_response.content.serv_errno) {
800 if (debug)
801 fprintf(where,"remote listen done.\n");
802 rsr_size = xti_tcp_stream_response->recv_buf_size;
803 rss_size = xti_tcp_stream_response->send_buf_size;
804 rem_nodelay = xti_tcp_stream_response->no_delay;
805 remote_cpu_usage = xti_tcp_stream_response->measure_cpu;
806 remote_cpu_rate = xti_tcp_stream_response->cpu_rate;
807
808 /* we have to make sure that the server port number is in */
809 /* network order */
810 server.sin_port = (short)xti_tcp_stream_response->data_port_number;
811 server.sin_port = htons(server.sin_port);
812 rem_rcvavoid = xti_tcp_stream_response->so_rcvavoid;
813 rem_sndavoid = xti_tcp_stream_response->so_sndavoid;
814 }
815 else {
816 Set_errno(netperf_response.content.serv_errno);
817 perror("netperf: remote error");
818
819 exit(1);
820 }
821
822 /*Connect up to the remote port on the data socket */
823 memset (&server_call, 0, sizeof(server_call));
824 server_call.addr.maxlen = sizeof(struct sockaddr_in);
825 server_call.addr.len = sizeof(struct sockaddr_in);
826 server_call.addr.buf = (char *)&server;
827
828 if (t_connect(send_socket,
829 &server_call,
830 NULL) == INVALID_SOCKET){
831 t_error("netperf: send_xti_tcp_stream: data socket connect failed");
832 printf(" port: %d\n",ntohs(server.sin_port));
833 exit(1);
834 }
835
836 /* Data Socket set-up is finished. If there were problems, either */
837 /* the connect would have failed, or the previous response would */
838 /* have indicated a problem. I failed to see the value of the */
839 /* extra message after the accept on the remote. If it failed, */
840 /* we'll see it here. If it didn't, we might as well start pumping */
841 /* data. */
842
843 /* Set-up the test end conditions. For a stream test, they can be */
844 /* either time or byte-count based. */
845
846 if (test_time) {
847 /* The user wanted to end the test after a period of time. */
848 times_up = 0;
849 bytes_remaining = 0;
850 /* in previous revisions, we had the same code repeated throught */
851 /* all the test suites. this was unnecessary, and meant more */
852 /* work for me when I wanted to switch to POSIX signals, so I */
853 /* have abstracted this out into a routine in netlib.c. if you */
854 /* are experiencing signal problems, you might want to look */
855 /* there. raj 11/94 */
856 start_timer(test_time);
857 }
858 else {
859 /* The tester wanted to send a number of bytes. */
860 bytes_remaining = test_bytes;
861 times_up = 1;
862 }
863
864 /* The cpu_start routine will grab the current time and possibly */
865 /* value of the idle counter for later use in measuring cpu */
866 /* utilization and/or service demand and thruput. */
867
868 cpu_start(local_cpu_usage);
869
870 #ifdef WANT_INTERVALS
871 if ((interval_burst) || (demo_mode)) {
872 /* zero means that we never pause, so we never should need the */
873 /* interval timer, unless we are in demo_mode */
874 start_itimer(interval_wate);
875 }
876 interval_count = interval_burst;
877 /* get the signal set for the call to sigsuspend */
878 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
879 fprintf(where,
880 "send_xti_tcp_stream: unable to get sigmask errno %d\n",
881 errno);
882 fflush(where);
883 exit(1);
884 }
885 #endif /* WANT_INTERVALS */
886
887 /* before we start, initialize a few variables */
888
889 /* We use an "OR" to control test execution. When the test is */
890 /* controlled by time, the byte count check will always return false. */
891 /* When the test is controlled by byte count, the time test will */
892 /* always return false. When the test is finished, the whole */
893 /* expression will go false and we will stop sending data. */
894
895 while ((!times_up) || (bytes_remaining > 0)) {
896
897 #ifdef DIRTY
898 /* we want to dirty some number of consecutive integers in the buffer */
899 /* we are about to send. we may also want to bring some number of */
900 /* them cleanly into the cache. The clean ones will follow any dirty */
901 /* ones into the cache. at some point, we might want to replace */
902 /* the rand() call with something from a table to reduce our call */
903 /* overhead during the test, but it is not a high priority item. */
904 access_buffer(send_ring->buffer_ptr,
905 send_size,
906 loc_dirty_count,
907 loc_clean_count);
908 #endif /* DIRTY */
909
910 #ifdef WANT_HISTOGRAM
911 /* timestamp just before we go into send and then again just after */
912 /* we come out raj 8/94 */
913 HIST_timestamp(&time_one);
914 #endif /* WANT_HISTOGRAM */
915
916 if((len=t_snd(send_socket,
917 send_ring->buffer_ptr,
918 send_size,
919 0)) != send_size) {
920 if ((len >=0) || (errno == EINTR)) {
921 /* the test was interrupted, must be the end of test */
922 break;
923 }
924 fprintf(where,
925 "send_xti_tcp_stream: t_snd: errno %d t_errno %d t_look 0x%.4x\n",
926 errno,
927 t_errno,
928 t_look(send_socket));
929 fflush(where);
930 exit(1);
931 }
932
933 #ifdef WANT_HISTOGRAM
934 /* timestamp the exit from the send call and update the histogram */
935 HIST_timestamp(&time_two);
936 HIST_add(time_hist,delta_micro(&time_one,&time_two));
937 #endif /* WANT_HISTOGRAM */
938
939 #ifdef WANT_INTERVALS
940 if (demo_mode) {
941 units_this_tick += send_size;
942 }
943 /* in this case, the interval count is the count-down couter */
944 /* to decide to sleep for a little bit */
945 if ((interval_burst) && (--interval_count == 0)) {
946 /* call sigsuspend and wait for the interval timer to get us */
947 /* out */
948 if (debug) {
949 fprintf(where,"about to suspend\n");
950 fflush(where);
951 }
952 if (sigsuspend(&signal_set) == EFAULT) {
953 fprintf(where,
954 "send_xti_tcp_stream: fault with signal set!\n");
955 fflush(where);
956 exit(1);
957 }
958 interval_count = interval_burst;
959 }
960 #endif /* WANT_INTERVALS */
961
962 /* now we want to move our pointer to the next position in the */
963 /* data buffer...we may also want to wrap back to the "beginning" */
964 /* of the bufferspace, so we will mod the number of messages sent */
965 /* by the send width, and use that to calculate the offset to add */
966 /* to the base pointer. */
967 nummessages++;
968 send_ring = send_ring->next;
969 if (bytes_remaining) {
970 bytes_remaining -= send_size;
971 }
972 }
973
974 /* The test is over. Flush the buffers to the remote end. We do a */
975 /* graceful release to insure that all data has been taken by the */
976 /* remote. */
977
978 /* but first, if the verbosity is greater than 1, find-out what */
979 /* the TCP maximum segment_size was (if possible) */
980 if (verbosity > 1) {
981 tcp_mss = -1;
982 get_xti_info(send_socket,info_struct);
983 }
984
985 if (t_sndrel(send_socket) == -1) {
986 t_error("netperf: cannot shutdown tcp stream socket");
987 exit(1);
988 }
989
990 /* hang a t_rcvrel() off the socket to block until the remote has */
991 /* brought all the data up into the application. it will do a */
992 /* t_sedrel to cause a FIN to be sent our way. We will assume that */
993 /* any exit from the t_rcvrel() call is good... raj 2/95 */
994
995 if (debug > 1) {
996 fprintf(where,"about to hang a receive for graceful release.\n");
997 fflush(where);
998 }
999
1000 t_rcvrel(send_socket);
1001
1002 /* this call will always give us the elapsed time for the test, and */
1003 /* will also store-away the necessaries for cpu utilization */
1004
1005 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
1006 /* measured and how */
1007 /* long did we really */
1008 /* run? */
1009
1010 /* Get the statistics from the remote end. The remote will have */
1011 /* calculated service demand and all those interesting things. If it */
1012 /* wasn't supposed to care, it will return obvious values. */
1013
1014 recv_response();
1015 if (!netperf_response.content.serv_errno) {
1016 if (debug)
1017 fprintf(where,"remote results obtained\n");
1018 }
1019 else {
1020 Set_errno(netperf_response.content.serv_errno);
1021 perror("netperf: remote error");
1022
1023 exit(1);
1024 }
1025
1026 /* We now calculate what our thruput was for the test. In the future, */
1027 /* we may want to include a calculation of the thruput measured by */
1028 /* the remote, but it should be the case that for a TCP stream test, */
1029 /* that the two numbers should be *very* close... We calculate */
1030 /* bytes_sent regardless of the way the test length was controlled. */
1031 /* If it was time, we needed to, and if it was by bytes, the user may */
1032 /* have specified a number of bytes that wasn't a multiple of the */
1033 /* send_size, so we really didn't send what he asked for ;-) */
1034
1035 bytes_sent = xti_tcp_stream_result->bytes_received;
1036
1037 thruput = calc_thruput(bytes_sent);
1038
1039 if (local_cpu_usage || remote_cpu_usage) {
1040 /* We must now do a little math for service demand and cpu */
1041 /* utilization for the system(s) */
1042 /* Of course, some of the information might be bogus because */
1043 /* there was no idle counter in the kernel(s). We need to make */
1044 /* a note of this for the user's benefit...*/
1045 if (local_cpu_usage) {
1046
1047 local_cpu_utilization = calc_cpu_util(0.0);
1048 local_service_demand = calc_service_demand(bytes_sent,
1049 0.0,
1050 0.0,
1051 0);
1052 }
1053 else {
1054 local_cpu_utilization = -1.0;
1055 local_service_demand = -1.0;
1056 }
1057
1058 if (remote_cpu_usage) {
1059
1060 remote_cpu_utilization = xti_tcp_stream_result->cpu_util;
1061 remote_service_demand = calc_service_demand(bytes_sent,
1062 0.0,
1063 remote_cpu_utilization,
1064 xti_tcp_stream_result->num_cpus);
1065 }
1066 else {
1067 remote_cpu_utilization = -1.0;
1068 remote_service_demand = -1.0;
1069 }
1070 }
1071 else {
1072 /* we were not measuring cpu, for the confidence stuff, we */
1073 /* should make it -1.0 */
1074 local_cpu_utilization = -1.0;
1075 local_service_demand = -1.0;
1076 remote_cpu_utilization = -1.0;
1077 remote_service_demand = -1.0;
1078 }
1079
1080 /* at this point, we want to calculate the confidence information. */
1081 /* if debugging is on, calculate_confidence will print-out the */
1082 /* parameters we pass it */
1083
1084 calculate_confidence(confidence_iteration,
1085 elapsed_time,
1086 thruput,
1087 local_cpu_utilization,
1088 remote_cpu_utilization,
1089 local_service_demand,
1090 remote_service_demand);
1091
1092
1093 confidence_iteration++;
1094 }
1095
1096 /* at this point, we have finished making all the runs that we */
1097 /* will be making. so, we should extract what the calcuated values */
1098 /* are for all the confidence stuff. we could make the values */
1099 /* global, but that seemed a little messy, and it did not seem worth */
1100 /* all the mucking with header files. so, we create a routine much */
1101 /* like calcualte_confidence, which just returns the mean values. */
1102 /* raj 11/94 */
1103
1104 retrieve_confident_values(&elapsed_time,
1105 &thruput,
1106 &local_cpu_utilization,
1107 &remote_cpu_utilization,
1108 &local_service_demand,
1109 &remote_service_demand);
1110
1111 /* We are now ready to print all the information. If the user */
1112 /* has specified zero-level verbosity, we will just print the */
1113 /* local service demand, or the remote service demand. If the */
1114 /* user has requested verbosity level 1, he will get the basic */
1115 /* "streamperf" numbers. If the user has specified a verbosity */
1116 /* of greater than 1, we will display a veritable plethora of */
1117 /* background information from outside of this block as it it */
1118 /* not cpu_measurement specific... */
1119
1120 if (confidence < 0) {
1121 /* we did not hit confidence, but were we asked to look for it? */
1122 if (iteration_max > 1) {
1123 display_confidence();
1124 }
1125 }
1126
1127 if (local_cpu_usage || remote_cpu_usage) {
1128 local_cpu_method = format_cpu_method(cpu_method);
1129 remote_cpu_method = format_cpu_method(xti_tcp_stream_result->cpu_method);
1130
1131 switch (verbosity) {
1132 case 0:
1133 if (local_cpu_usage) {
1134 fprintf(where,
1135 cpu_fmt_0,
1136 local_service_demand,
1137 local_cpu_method);
1138 }
1139 else {
1140 fprintf(where,
1141 cpu_fmt_0,
1142 remote_service_demand,
1143 remote_cpu_method);
1144 }
1145 break;
1146 case 1:
1147 case 2:
1148 if (print_headers) {
1149 fprintf(where,
1150 cpu_title,
1151 format_units(),
1152 local_cpu_method,
1153 remote_cpu_method);
1154 }
1155
1156 fprintf(where,
1157 cpu_fmt_1, /* the format string */
1158 rsr_size, /* remote recvbuf size */
1159 lss_size, /* local sendbuf size */
1160 send_size, /* how large were the sends */
1161 elapsed_time, /* how long was the test */
1162 thruput, /* what was the xfer rate */
1163 local_cpu_utilization, /* local cpu */
1164 remote_cpu_utilization, /* remote cpu */
1165 local_service_demand, /* local service demand */
1166 remote_service_demand); /* remote service demand */
1167 break;
1168 }
1169 }
1170 else {
1171 /* The tester did not wish to measure service demand. */
1172
1173 switch (verbosity) {
1174 case 0:
1175 fprintf(where,
1176 tput_fmt_0,
1177 thruput);
1178 break;
1179 case 1:
1180 case 2:
1181 if (print_headers) {
1182 fprintf(where,tput_title,format_units());
1183 }
1184 fprintf(where,
1185 tput_fmt_1, /* the format string */
1186 rsr_size, /* remote recvbuf size */
1187 lss_size, /* local sendbuf size */
1188 send_size, /* how large were the sends */
1189 elapsed_time, /* how long did it take */
1190 thruput);/* how fast did it go */
1191 break;
1192 }
1193 }
1194
1195 /* it would be a good thing to include information about some of the */
1196 /* other parameters that may have been set for this test, but at the */
1197 /* moment, I do not wish to figure-out all the formatting, so I will */
1198 /* just put this comment here to help remind me that it is something */
1199 /* that should be done at a later time. */
1200
1201 if (verbosity > 1) {
1202 /* The user wanted to know it all, so we will give it to him. */
1203 /* This information will include as much as we can find about */
1204 /* TCP statistics, the alignments of the sends and receives */
1205 /* and all that sort of rot... */
1206
1207 /* this stuff needs to be worked-out in the presence of confidence */
1208 /* intervals and multiple iterations of the test... raj 11/94 */
1209
1210 fprintf(where,
1211 ksink_fmt,
1212 "Bytes",
1213 "Bytes",
1214 "Bytes",
1215 local_send_align,
1216 remote_recv_align,
1217 local_send_offset,
1218 remote_recv_offset,
1219 bytes_sent,
1220 bytes_sent / (double)nummessages,
1221 nummessages,
1222 bytes_sent / (double)xti_tcp_stream_result->recv_calls,
1223 xti_tcp_stream_result->recv_calls);
1224 fprintf(where,
1225 ksink_fmt2,
1226 tcp_mss);
1227 fflush(where);
1228 #ifdef WANT_HISTOGRAM
1229 fprintf(where,"\n\nHistogram of time spent in send() call.\n");
1230 fflush(where);
1231 HIST_report(time_hist);
1232 #endif /* WANT_HISTOGRAM */
1233 }
1234
1235 }
1236
1237
1238 /* This is the server-side routine for the tcp stream test. It is */
1239 /* implemented as one routine. I could break things-out somewhat, but */
1240 /* didn't feel it was necessary. */
1241
1242 void
recv_xti_tcp_stream()1243 recv_xti_tcp_stream()
1244 {
1245
1246 struct sockaddr_in myaddr_in, peeraddr_in;
1247 struct t_bind bind_req, bind_resp;
1248 struct t_call call_req;
1249
1250 SOCKET s_listen,s_data;
1251 int addrlen;
1252 int len;
1253 unsigned int receive_calls;
1254 float elapsed_time;
1255 double bytes_received;
1256
1257 struct ring_elt *recv_ring;
1258
1259 int *message_int_ptr;
1260 int i;
1261
1262 struct xti_tcp_stream_request_struct *xti_tcp_stream_request;
1263 struct xti_tcp_stream_response_struct *xti_tcp_stream_response;
1264 struct xti_tcp_stream_results_struct *xti_tcp_stream_results;
1265
1266 xti_tcp_stream_request =
1267 (struct xti_tcp_stream_request_struct *)netperf_request.content.test_specific_data;
1268 xti_tcp_stream_response =
1269 (struct xti_tcp_stream_response_struct *)netperf_response.content.test_specific_data;
1270 xti_tcp_stream_results =
1271 (struct xti_tcp_stream_results_struct *)netperf_response.content.test_specific_data;
1272
1273 if (debug) {
1274 fprintf(where,"netserver: recv_xti_tcp_stream: entered...\n");
1275 fflush(where);
1276 }
1277
1278 /* We want to set-up the listen socket with all the desired */
1279 /* parameters and then let the initiator know that all is ready. If */
1280 /* socket size defaults are to be used, then the initiator will have */
1281 /* sent us 0's. If the socket sizes cannot be changed, then we will */
1282 /* send-back what they are. If that information cannot be determined, */
1283 /* then we send-back -1's for the sizes. If things go wrong for any */
1284 /* reason, we will drop back ten yards and punt. */
1285
1286 /* If anything goes wrong, we want the remote to know about it. It */
1287 /* would be best if the error that the remote reports to the user is */
1288 /* the actual error we encountered, rather than some bogus unexpected */
1289 /* response type message. */
1290
1291 if (debug) {
1292 fprintf(where,"recv_xti_tcp_stream: setting the response type...\n");
1293 fflush(where);
1294 }
1295
1296 netperf_response.content.response_type = XTI_TCP_STREAM_RESPONSE;
1297
1298 if (debug) {
1299 fprintf(where,"recv_xti_tcp_stream: the response type is set...\n");
1300 fflush(where);
1301 }
1302
1303 /* We now alter the message_ptr variable to be at the desired */
1304 /* alignment with the desired offset. */
1305
1306 if (debug) {
1307 fprintf(where,"recv_xti_tcp_stream: requested alignment of %d\n",
1308 xti_tcp_stream_request->recv_alignment);
1309 fflush(where);
1310 }
1311
1312 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
1313 /* can put in OUR values !-) At some point, we may want to nail this */
1314 /* socket to a particular network-level address, but for now, */
1315 /* INADDR_ANY should be just fine. */
1316
1317 bzero((char *)&myaddr_in,
1318 sizeof(myaddr_in));
1319 myaddr_in.sin_family = AF_INET;
1320 myaddr_in.sin_addr.s_addr = INADDR_ANY;
1321 myaddr_in.sin_port = 0;
1322
1323 /* Grab a socket to listen on, and then listen on it. */
1324
1325 if (debug) {
1326 fprintf(where,"recv_xti_tcp_stream: grabbing a socket...\n");
1327 fflush(where);
1328 }
1329
1330 /* create_xti_endpoint expects to find some things in the global */
1331 /* variables, so set the globals based on the values in the request. */
1332 /* once the socket has been created, we will set the response values */
1333 /* based on the updated value of those globals. raj 7/94 */
1334 lss_size = xti_tcp_stream_request->send_buf_size;
1335 lsr_size = xti_tcp_stream_request->recv_buf_size;
1336 loc_nodelay = xti_tcp_stream_request->no_delay;
1337 loc_rcvavoid = xti_tcp_stream_request->so_rcvavoid;
1338 loc_sndavoid = xti_tcp_stream_request->so_sndavoid;
1339
1340 #ifdef __alpha
1341
1342 /* ok - even on a DEC box, strings are strings. I din't really want */
1343 /* to ntohl the words of a string. since I don't want to teach the */
1344 /* send_ and recv_ _request and _response routines about the types, */
1345 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
1346 /* solution would be to use XDR, but I am still leary of being able */
1347 /* to find XDR libs on all platforms I want running netperf. raj */
1348 {
1349 int *charword;
1350 int *initword;
1351 int *lastword;
1352
1353 initword = (int *) xti_tcp_stream_request->xti_device;
1354 lastword = initword + ((xti_tcp_stream_request->dev_name_len + 3) / 4);
1355
1356 for (charword = initword;
1357 charword < lastword;
1358 charword++) {
1359
1360 *charword = htonl(*charword);
1361 }
1362 }
1363
1364 #endif /* __alpha */
1365
1366 s_listen = create_xti_endpoint(xti_tcp_stream_request->xti_device);
1367
1368 if (s_listen == INVALID_SOCKET) {
1369 netperf_response.content.serv_errno = errno;
1370 send_response();
1371 exit(1);
1372 }
1373
1374 /* Let's get an address assigned to this socket so we can tell the */
1375 /* initiator how to reach the data socket. There may be a desire to */
1376 /* nail this socket to a specific IP address in a multi-homed, */
1377 /* multi-connection situation, but for now, we'll ignore the issue */
1378 /* and concentrate on single connection testing. */
1379
1380 bind_req.addr.maxlen = sizeof(struct sockaddr_in);
1381 bind_req.addr.len = sizeof(struct sockaddr_in);
1382 bind_req.addr.buf = (char *)&myaddr_in;
1383 bind_req.qlen = 1;
1384
1385 bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
1386 bind_resp.addr.len = sizeof(struct sockaddr_in);
1387 bind_resp.addr.buf = (char *)&myaddr_in;
1388 bind_resp.qlen = 1;
1389
1390 if (t_bind(s_listen,
1391 &bind_req,
1392 &bind_resp) == SOCKET_ERROR) {
1393 netperf_response.content.serv_errno = t_errno;
1394 close(s_listen);
1395 send_response();
1396
1397 exit(1);
1398 }
1399
1400 if (debug) {
1401 fprintf(where,
1402 "recv_xti_tcp_stream: t_bind complete port %d\n",
1403 ntohs(myaddr_in.sin_port));
1404 fflush(where);
1405 }
1406
1407 /* what sort of sizes did we end-up with? */
1408 if (xti_tcp_stream_request->receive_size == 0) {
1409 if (lsr_size > 0) {
1410 recv_size = lsr_size;
1411 }
1412 else {
1413 recv_size = 4096;
1414 }
1415 }
1416 else {
1417 recv_size = xti_tcp_stream_request->receive_size;
1418 }
1419
1420 /* we want to set-up our recv_ring in a manner analagous to what we */
1421 /* do on the sending side. this is more for the sake of symmetry */
1422 /* than for the needs of say copy avoidance, but it might also be */
1423 /* more realistic - this way one could conceivably go with a */
1424 /* double-buffering scheme when taking the data an putting it into */
1425 /* the filesystem or something like that. raj 7/94 */
1426
1427 if (recv_width == 0) {
1428 recv_width = (lsr_size/recv_size) + 1;
1429 if (recv_width == 1) recv_width++;
1430 }
1431
1432 recv_ring = allocate_buffer_ring(recv_width,
1433 recv_size,
1434 xti_tcp_stream_request->recv_alignment,
1435 xti_tcp_stream_request->recv_offset);
1436
1437 if (debug) {
1438 fprintf(where,"recv_xti_tcp_stream: recv alignment and offset set...\n");
1439 fflush(where);
1440 }
1441
1442 /* Now myaddr_in contains the port and the internet address this is */
1443 /* returned to the sender also implicitly telling the sender that the */
1444 /* socket buffer sizing has been done. */
1445
1446 xti_tcp_stream_response->data_port_number =
1447 (int) ntohs(myaddr_in.sin_port);
1448 netperf_response.content.serv_errno = 0;
1449
1450 /* But wait, there's more. If the initiator wanted cpu measurements, */
1451 /* then we must call the calibrate routine, which will return the max */
1452 /* rate back to the initiator. If the CPU was not to be measured, or */
1453 /* something went wrong with the calibration, we will return a -1 to */
1454 /* the initiator. */
1455
1456 xti_tcp_stream_response->cpu_rate = 0.0; /* assume no cpu */
1457 if (xti_tcp_stream_request->measure_cpu) {
1458 xti_tcp_stream_response->measure_cpu = 1;
1459 xti_tcp_stream_response->cpu_rate =
1460 calibrate_local_cpu(xti_tcp_stream_request->cpu_rate);
1461 }
1462 else {
1463 xti_tcp_stream_response->measure_cpu = 0;
1464 }
1465
1466 /* before we send the response back to the initiator, pull some of */
1467 /* the socket parms from the globals */
1468 xti_tcp_stream_response->send_buf_size = lss_size;
1469 xti_tcp_stream_response->recv_buf_size = lsr_size;
1470 xti_tcp_stream_response->no_delay = loc_nodelay;
1471 xti_tcp_stream_response->so_rcvavoid = loc_rcvavoid;
1472 xti_tcp_stream_response->so_sndavoid = loc_sndavoid;
1473 xti_tcp_stream_response->receive_size = recv_size;
1474
1475 send_response();
1476
1477 /* Now, let's set-up the socket to listen for connections. for xti, */
1478 /* the t_listen call is blocking by default - this is different */
1479 /* semantics from BSD - probably has to do with being able to reject */
1480 /* a call before an accept */
1481 call_req.addr.maxlen = sizeof(struct sockaddr_in);
1482 call_req.addr.len = sizeof(struct sockaddr_in);
1483 call_req.addr.buf = (char *)&peeraddr_in;
1484 call_req.opt.maxlen = 0;
1485 call_req.opt.len = 0;
1486 call_req.opt.buf = NULL;
1487 call_req.udata.maxlen= 0;
1488 call_req.udata.len = 0;
1489 call_req.udata.buf = 0;
1490
1491 if (t_listen(s_listen, &call_req) == -1) {
1492 fprintf(where,
1493 "recv_xti_tcp_stream: t_listen: errno %d t_errno %d\n",
1494 errno,
1495 t_errno);
1496 fflush(where);
1497 netperf_response.content.serv_errno = t_errno;
1498 close(s_listen);
1499 send_response();
1500 exit(1);
1501 }
1502
1503 if (debug) {
1504 fprintf(where,
1505 "recv_xti_tcp_stream: t_listen complete t_look 0x%.4x\n",
1506 t_look(s_listen));
1507 fflush(where);
1508 }
1509
1510 /* now just rubber stamp the thing. we want to use the same fd? so */
1511 /* we will just equate s_data with s_listen. this seems a little */
1512 /* hokey to me, but then I'm a BSD biggot still. raj 2/95 */
1513 s_data = s_listen;
1514 if (t_accept(s_listen,
1515 s_data,
1516 &call_req) == -1) {
1517 fprintf(where,
1518 "recv_xti_tcp_stream: t_accept: errno %d t_errno %d\n",
1519 errno,
1520 t_errno);
1521 fflush(where);
1522 close(s_listen);
1523 exit(1);
1524 }
1525
1526 if (debug) {
1527 fprintf(where,
1528 "recv_xti_tcp_stream: t_accept complete t_look 0x%.4x\n",
1529 t_look(s_data));
1530 fprintf(where,
1531 " remote is %s port %d\n",
1532 inet_ntoa(*(struct in_addr *)&peeraddr_in.sin_addr),
1533 ntohs(peeraddr_in.sin_port));
1534 fflush(where);
1535 }
1536
1537 /* Now it's time to start receiving data on the connection. We will */
1538 /* first grab the apropriate counters and then start grabbing. */
1539
1540 cpu_start(xti_tcp_stream_request->measure_cpu);
1541
1542 /* The loop will exit when the sender does a t_sndrel, which will */
1543 /* return T_LOOK error from the t_recv */
1544
1545 #ifdef DIRTY
1546 /* we want to dirty some number of consecutive integers in the buffer */
1547 /* we are about to recv. we may also want to bring some number of */
1548 /* them cleanly into the cache. The clean ones will follow any dirty */
1549 /* ones into the cache. */
1550
1551 access_buffer(recv_ring->buffer_ptr,
1552 recv_size,
1553 xti_tcp_stream_request->dirty_count,
1554 xti_tcp_stream_request->clean_count);
1555
1556 #endif /* DIRTY */
1557
1558 bytes_received = 0;
1559 receive_calls = 0;
1560
1561 while ((len = t_rcv(s_data,
1562 recv_ring->buffer_ptr,
1563 recv_size,
1564 &xti_flags)) != -1) {
1565 bytes_received += len;
1566 receive_calls++;
1567
1568 /* more to the next buffer in the recv_ring */
1569 recv_ring = recv_ring->next;
1570
1571 #ifdef DIRTY
1572
1573 access_buffer(recv_ring->buffer_ptr,
1574 recv_size,
1575 xti_tcp_stream_request->dirty_count,
1576 xti_tcp_stream_request->clean_count);
1577
1578 #endif /* DIRTY */
1579 }
1580
1581 if (t_look(s_data) == T_ORDREL) {
1582 /* this is a normal exit path */
1583 if (debug) {
1584 fprintf(where,
1585 "recv_xti_tcp_stream: t_rcv T_ORDREL indicated\n");
1586 fflush(where);
1587 }
1588 }
1589 else {
1590 /* something went wrong */
1591 fprintf(where,
1592 "recv_xti_tcp_stream: t_rcv: errno %d t_errno %d len %d",
1593 errno,
1594 t_errno,
1595 len);
1596 fprintf(where,
1597 " t_look 0x%.4x",
1598 t_look(s_data));
1599 fflush(where);
1600 netperf_response.content.serv_errno = t_errno;
1601 send_response();
1602 exit(1);
1603 }
1604
1605 /* receive the release and let the initiator know that we have */
1606 /* received all the data. raj 3/95 */
1607
1608 if (t_rcvrel(s_data) == -1) {
1609 netperf_response.content.serv_errno = errno;
1610 send_response();
1611 exit(1);
1612 }
1613
1614 if (debug) {
1615 fprintf(where,
1616 "recv_xti_tcp_stream: t_rcvrel complete\n");
1617 fflush(where);
1618 }
1619
1620 if (t_sndrel(s_data) == -1) {
1621 netperf_response.content.serv_errno = errno;
1622 send_response();
1623 exit(1);
1624 }
1625
1626 if (debug) {
1627 fprintf(where,
1628 "recv_xti_tcp_stream: t_sndrel complete\n");
1629 fflush(where);
1630 }
1631
1632 cpu_stop(xti_tcp_stream_request->measure_cpu,&elapsed_time);
1633
1634 /* send the results to the sender */
1635
1636 if (debug) {
1637 fprintf(where,
1638 "recv_xti_tcp_stream: got %g bytes\n",
1639 bytes_received);
1640 fprintf(where,
1641 "recv_xti_tcp_stream: got %d recvs\n",
1642 receive_calls);
1643 fflush(where);
1644 }
1645
1646 xti_tcp_stream_results->bytes_received = bytes_received;
1647 xti_tcp_stream_results->elapsed_time = elapsed_time;
1648 xti_tcp_stream_results->recv_calls = receive_calls;
1649
1650 if (xti_tcp_stream_request->measure_cpu) {
1651 xti_tcp_stream_results->cpu_util = calc_cpu_util(0.0);
1652 };
1653
1654 if (debug) {
1655 fprintf(where,
1656 "recv_xti_tcp_stream: test complete, sending results.\n");
1657 fprintf(where,
1658 " bytes_received %g receive_calls %d\n",
1659 bytes_received,
1660 receive_calls);
1661 fprintf(where,
1662 " len %d\n",
1663 len);
1664 fflush(where);
1665 }
1666
1667 xti_tcp_stream_results->cpu_method = cpu_method;
1668 send_response();
1669
1670 /* we are now done with the socket */
1671 t_close(s_data);
1672
1673 }
1674
1675
1676 /* this routine implements the sending (netperf) side of the XTI_TCP_RR */
1677 /* test. */
1678
1679 void
send_xti_tcp_rr(char remote_host[])1680 send_xti_tcp_rr(char remote_host[])
1681 {
1682
1683 char *tput_title = "\
1684 Local /Remote\n\
1685 Socket Size Request Resp. Elapsed Trans.\n\
1686 Send Recv Size Size Time Rate \n\
1687 bytes Bytes bytes bytes secs. per sec \n\n";
1688
1689 char *tput_fmt_0 =
1690 "%7.2f\n";
1691
1692 char *tput_fmt_1_line_1 = "\
1693 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
1694 char *tput_fmt_1_line_2 = "\
1695 %-6d %-6d\n";
1696
1697 char *cpu_title = "\
1698 Local /Remote\n\
1699 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
1700 Send Recv Size Size Time Rate local remote local remote\n\
1701 bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
1702
1703 char *cpu_fmt_0 =
1704 "%6.3f %c\n";
1705
1706 char *cpu_fmt_1_line_1 = "\
1707 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
1708
1709 char *cpu_fmt_1_line_2 = "\
1710 %-6d %-6d\n";
1711
1712 char *ksink_fmt = "\
1713 Alignment Offset\n\
1714 Local Remote Local Remote\n\
1715 Send Recv Send Recv\n\
1716 %5d %5d %5d %5d\n";
1717
1718
1719 int timed_out = 0;
1720 float elapsed_time;
1721
1722 int len;
1723 char *temp_message_ptr;
1724 int nummessages;
1725 SOCKET send_socket;
1726 int trans_remaining;
1727 double bytes_xferd;
1728
1729 struct ring_elt *send_ring;
1730 struct ring_elt *recv_ring;
1731
1732 int rsp_bytes_left;
1733 int rsp_bytes_recvd;
1734
1735 float local_cpu_utilization;
1736 float local_service_demand;
1737 float remote_cpu_utilization;
1738 float remote_service_demand;
1739 double thruput;
1740
1741 struct hostent *hp;
1742 struct sockaddr_in server;
1743 unsigned int addr;
1744
1745 struct t_call server_call;
1746
1747 struct xti_tcp_rr_request_struct *xti_tcp_rr_request;
1748 struct xti_tcp_rr_response_struct *xti_tcp_rr_response;
1749 struct xti_tcp_rr_results_struct *xti_tcp_rr_result;
1750
1751 #ifdef WANT_INTERVALS
1752 int interval_count;
1753 sigset_t signal_set;
1754 #endif /* WANT_INTERVALS */
1755
1756 xti_tcp_rr_request =
1757 (struct xti_tcp_rr_request_struct *)netperf_request.content.test_specific_data;
1758 xti_tcp_rr_response=
1759 (struct xti_tcp_rr_response_struct *)netperf_response.content.test_specific_data;
1760 xti_tcp_rr_result =
1761 (struct xti_tcp_rr_results_struct *)netperf_response.content.test_specific_data;
1762
1763 #ifdef WANT_HISTOGRAM
1764 time_hist = HIST_new();
1765 #endif /* WANT_HISTOGRAM */
1766
1767 /* since we are now disconnected from the code that established the */
1768 /* control socket, and since we want to be able to use different */
1769 /* protocols and such, we are passed the name of the remote host and */
1770 /* must turn that into the test specific addressing information. */
1771
1772 bzero((char *)&server,
1773 sizeof(server));
1774
1775 /* it would seem that while HP-UX will allow an IP address (as a */
1776 /* string) in a call to gethostbyname, other, less enlightened */
1777 /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */
1778 /* order changed to check for IP address first. raj 7/96 */
1779
1780 if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
1781 /* it was not an IP address, try it as a name */
1782 if ((hp = gethostbyname(remote_host)) == NULL) {
1783 /* we have no idea what it is */
1784 fprintf(where,
1785 "establish_control: could not resolve the destination %s\n",
1786 remote_host);
1787 fflush(where);
1788 exit(1);
1789 }
1790 else {
1791 /* it was a valid remote_host */
1792 bcopy(hp->h_addr,
1793 (char *)&server.sin_addr,
1794 hp->h_length);
1795 server.sin_family = hp->h_addrtype;
1796 }
1797 }
1798 else {
1799 /* it was a valid IP address */
1800 server.sin_addr.s_addr = addr;
1801 server.sin_family = AF_INET;
1802 }
1803
1804 if ( print_headers ) {
1805 fprintf(where,"XTI TCP REQUEST/RESPONSE TEST");
1806 fprintf(where," to %s", remote_host);
1807 if (iteration_max > 1) {
1808 fprintf(where,
1809 " : +/-%3.1f%% @ %2d%% conf.",
1810 interval/0.02,
1811 confidence_level);
1812 }
1813 if (loc_nodelay || rem_nodelay) {
1814 fprintf(where," : nodelay");
1815 }
1816 if (loc_sndavoid ||
1817 loc_rcvavoid ||
1818 rem_sndavoid ||
1819 rem_rcvavoid) {
1820 fprintf(where," : copy avoidance");
1821 }
1822 #ifdef WANT_HISTOGRAM
1823 fprintf(where," : histogram");
1824 #endif /* WANT_HISTOGRAM */
1825 #ifdef WANT_INTERVALS
1826 fprintf(where," : interval");
1827 #endif /* WANT_INTERVALS */
1828 #ifdef DIRTY
1829 fprintf(where," : dirty data");
1830 #endif /* DIRTY */
1831 fprintf(where,"\n");
1832 }
1833
1834 /* initialize a few counters */
1835
1836 send_ring = NULL;
1837 recv_ring = NULL;
1838 confidence_iteration = 1;
1839 init_stat();
1840
1841 /* we have a great-big while loop which controls the number of times */
1842 /* we run a particular test. this is for the calculation of a */
1843 /* confidence interval (I really should have stayed awake during */
1844 /* probstats :). If the user did not request confidence measurement */
1845 /* (no confidence is the default) then we will only go though the */
1846 /* loop once. the confidence stuff originates from the folks at IBM */
1847
1848 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
1849 (confidence_iteration <= iteration_min)) {
1850
1851 /* initialize a few counters. we have to remember that we might be */
1852 /* going through the loop more than once. */
1853
1854 nummessages = 0;
1855 bytes_xferd = 0.0;
1856 times_up = 0;
1857 timed_out = 0;
1858 trans_remaining = 0;
1859
1860 /* set-up the data buffers with the requested alignment and offset. */
1861 /* since this is a request/response test, default the send_width and */
1862 /* recv_width to 1 and not two raj 7/94 */
1863
1864 if (send_width == 0) send_width = 1;
1865 if (recv_width == 0) recv_width = 1;
1866
1867 if (send_ring == NULL) {
1868 send_ring = allocate_buffer_ring(send_width,
1869 req_size,
1870 local_send_align,
1871 local_send_offset);
1872 }
1873
1874 if (recv_ring == NULL) {
1875 recv_ring = allocate_buffer_ring(recv_width,
1876 rsp_size,
1877 local_recv_align,
1878 local_recv_offset);
1879 }
1880
1881 /*set up the data socket */
1882 send_socket = create_xti_endpoint(loc_xti_device);
1883
1884 if (send_socket == INVALID_SOCKET){
1885 perror("netperf: send_xti_tcp_rr: tcp stream data socket");
1886 exit(1);
1887 }
1888
1889 if (debug) {
1890 fprintf(where,"send_xti_tcp_rr: send_socket obtained...\n");
1891 }
1892
1893 /* it would seem that with XTI, there is no implicit bind on a */
1894 /* connect, so we have to make a call to t_bind. this is not */
1895 /* terribly convenient, but I suppose that "standard is better */
1896 /* than better" :) raj 2/95 */
1897
1898 if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) {
1899 t_error("send_xti_tcp_stream: t_bind");
1900 exit(1);
1901 }
1902
1903 /* If the user has requested cpu utilization measurements, we must */
1904 /* calibrate the cpu(s). We will perform this task within the tests */
1905 /* themselves. If the user has specified the cpu rate, then */
1906 /* calibrate_local_cpu will return rather quickly as it will have */
1907 /* nothing to do. If local_cpu_rate is zero, then we will go through */
1908 /* all the "normal" calibration stuff and return the rate back.*/
1909
1910 if (local_cpu_usage) {
1911 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
1912 }
1913
1914 /* Tell the remote end to do a listen. The server alters the socket */
1915 /* paramters on the other side at this point, hence the reason for */
1916 /* all the values being passed in the setup message. If the user did */
1917 /* not specify any of the parameters, they will be passed as 0, which */
1918 /* will indicate to the remote that no changes beyond the system's */
1919 /* default should be used. Alignment is the exception, it will */
1920 /* default to 8, which will be no alignment alterations. */
1921
1922 netperf_request.content.request_type = DO_XTI_TCP_RR;
1923 xti_tcp_rr_request->recv_buf_size = rsr_size;
1924 xti_tcp_rr_request->send_buf_size = rss_size;
1925 xti_tcp_rr_request->recv_alignment = remote_recv_align;
1926 xti_tcp_rr_request->recv_offset = remote_recv_offset;
1927 xti_tcp_rr_request->send_alignment = remote_send_align;
1928 xti_tcp_rr_request->send_offset = remote_send_offset;
1929 xti_tcp_rr_request->request_size = req_size;
1930 xti_tcp_rr_request->response_size = rsp_size;
1931 xti_tcp_rr_request->no_delay = rem_nodelay;
1932 xti_tcp_rr_request->measure_cpu = remote_cpu_usage;
1933 xti_tcp_rr_request->cpu_rate = remote_cpu_rate;
1934 xti_tcp_rr_request->so_rcvavoid = rem_rcvavoid;
1935 xti_tcp_rr_request->so_sndavoid = rem_sndavoid;
1936 if (test_time) {
1937 xti_tcp_rr_request->test_length = test_time;
1938 }
1939 else {
1940 xti_tcp_rr_request->test_length = test_trans * -1;
1941 }
1942
1943 strcpy(xti_tcp_rr_request->xti_device, rem_xti_device);
1944
1945 #ifdef __alpha
1946
1947 /* ok - even on a DEC box, strings are strings. I didn't really want */
1948 /* to ntohl the words of a string. since I don't want to teach the */
1949 /* send_ and recv_ _request and _response routines about the types, */
1950 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
1951 /* solution would be to use XDR, but I am still leary of being able */
1952 /* to find XDR libs on all platforms I want running netperf. raj */
1953 {
1954 int *charword;
1955 int *initword;
1956 int *lastword;
1957
1958 initword = (int *) xti_tcp_rr_request->xti_device;
1959 lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
1960
1961 for (charword = initword;
1962 charword < lastword;
1963 charword++) {
1964
1965 *charword = ntohl(*charword);
1966 }
1967 }
1968 #endif /* __alpha */
1969
1970 if (debug > 1) {
1971 fprintf(where,"netperf: send_xti_tcp_rr: requesting TCP rr test\n");
1972 }
1973
1974 send_request();
1975
1976 /* The response from the remote will contain all of the relevant */
1977 /* socket parameters for this test type. We will put them back into */
1978 /* the variables here so they can be displayed if desired. The */
1979 /* remote will have calibrated CPU if necessary, and will have done */
1980 /* all the needed set-up we will have calibrated the cpu locally */
1981 /* before sending the request, and will grab the counter value right*/
1982 /* after the connect returns. The remote will grab the counter right*/
1983 /* after the accept call. This saves the hassle of extra messages */
1984 /* being sent for the TCP tests. */
1985
1986 recv_response();
1987
1988 if (!netperf_response.content.serv_errno) {
1989 if (debug)
1990 fprintf(where,"remote listen done.\n");
1991 rsr_size = xti_tcp_rr_response->recv_buf_size;
1992 rss_size = xti_tcp_rr_response->send_buf_size;
1993 rem_nodelay = xti_tcp_rr_response->no_delay;
1994 remote_cpu_usage = xti_tcp_rr_response->measure_cpu;
1995 remote_cpu_rate = xti_tcp_rr_response->cpu_rate;
1996 /* make sure that port numbers are in network order */
1997 server.sin_port = (short)xti_tcp_rr_response->data_port_number;
1998 server.sin_port = htons(server.sin_port);
1999 }
2000 else {
2001 Set_errno(netperf_response.content.serv_errno);
2002 perror("netperf: remote error");
2003
2004 exit(1);
2005 }
2006
2007 /*Connect up to the remote port on the data socket */
2008 memset (&server_call, 0, sizeof(server_call));
2009 server_call.addr.maxlen = sizeof(struct sockaddr_in);
2010 server_call.addr.len = sizeof(struct sockaddr_in);
2011 server_call.addr.buf = (char *)&server;
2012
2013 if (t_connect(send_socket,
2014 &server_call,
2015 NULL) == INVALID_SOCKET){
2016 t_error("netperf: send_xti_tcp_rr: data socket connect failed");
2017 printf(" port: %d\n",ntohs(server.sin_port));
2018 exit(1);
2019 }
2020
2021 /* Data Socket set-up is finished. If there were problems, either the */
2022 /* connect would have failed, or the previous response would have */
2023 /* indicated a problem. I failed to see the value of the extra */
2024 /* message after the accept on the remote. If it failed, we'll see it */
2025 /* here. If it didn't, we might as well start pumping data. */
2026
2027 /* Set-up the test end conditions. For a request/response test, they */
2028 /* can be either time or transaction based. */
2029
2030 if (test_time) {
2031 /* The user wanted to end the test after a period of time. */
2032 times_up = 0;
2033 trans_remaining = 0;
2034 start_timer(test_time);
2035 }
2036 else {
2037 /* The tester wanted to send a number of bytes. */
2038 trans_remaining = test_bytes;
2039 times_up = 1;
2040 }
2041
2042 /* The cpu_start routine will grab the current time and possibly */
2043 /* value of the idle counter for later use in measuring cpu */
2044 /* utilization and/or service demand and thruput. */
2045
2046 cpu_start(local_cpu_usage);
2047
2048 #ifdef WANT_INTERVALS
2049 if ((interval_burst) || (demo_mode)) {
2050 /* zero means that we never pause, so we never should need the */
2051 /* interval timer, unless we are in demo_mode */
2052 start_itimer(interval_wate);
2053 }
2054 interval_count = interval_burst;
2055 /* get the signal set for the call to sigsuspend */
2056 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
2057 fprintf(where,
2058 "send_xti_tcp_rr: unable to get sigmask errno %d\n",
2059 errno);
2060 fflush(where);
2061 exit(1);
2062 }
2063 #endif /* WANT_INTERVALS */
2064
2065 /* We use an "OR" to control test execution. When the test is */
2066 /* controlled by time, the byte count check will always return false. */
2067 /* When the test is controlled by byte count, the time test will */
2068 /* always return false. When the test is finished, the whole */
2069 /* expression will go false and we will stop sending data. I think I */
2070 /* just arbitrarily decrement trans_remaining for the timed test, but */
2071 /* will not do that just yet... One other question is whether or not */
2072 /* the send buffer and the receive buffer should be the same buffer. */
2073
2074 while ((!times_up) || (trans_remaining > 0)) {
2075 /* send the request. we assume that if we use a blocking socket, */
2076 /* the request will be sent at one shot. */
2077
2078 #ifdef WANT_HISTOGRAM
2079 /* timestamp just before our call to send, and then again just */
2080 /* after the receive raj 8/94 */
2081 HIST_timestamp(&time_one);
2082 #endif /* WANT_HISTOGRAM */
2083
2084 if((len=t_snd(send_socket,
2085 send_ring->buffer_ptr,
2086 req_size,
2087 0)) != req_size) {
2088 if ((errno == EINTR) || (errno == 0)) {
2089 /* we hit the end of a */
2090 /* timed test. */
2091 timed_out = 1;
2092 break;
2093 }
2094 fprintf(where,
2095 "send_xti_tcp_rr: t_snd: errno %d t_errno %d t_look 0x%.4x\n",
2096 errno,
2097 t_errno,
2098 t_look(send_socket));
2099 fflush(where);
2100 exit(1);
2101 }
2102 send_ring = send_ring->next;
2103
2104 /* receive the response */
2105 rsp_bytes_left = rsp_size;
2106 temp_message_ptr = recv_ring->buffer_ptr;
2107 while(rsp_bytes_left > 0) {
2108 if((rsp_bytes_recvd=t_rcv(send_socket,
2109 temp_message_ptr,
2110 rsp_bytes_left,
2111 &xti_flags)) == SOCKET_ERROR) {
2112 if (errno == EINTR) {
2113 /* We hit the end of a timed test. */
2114 timed_out = 1;
2115 break;
2116 }
2117 fprintf(where,
2118 "send_xti_tcp_rr: t_rcv: errno %d t_errno %d t_look 0x%x\n",
2119 errno,
2120 t_errno,
2121 t_look(send_socket));
2122 fflush(where);
2123 exit(1);
2124 }
2125 rsp_bytes_left -= rsp_bytes_recvd;
2126 temp_message_ptr += rsp_bytes_recvd;
2127 }
2128 recv_ring = recv_ring->next;
2129
2130 if (timed_out) {
2131 /* we may have been in a nested while loop - we need */
2132 /* another call to break. */
2133 break;
2134 }
2135
2136 #ifdef WANT_HISTOGRAM
2137 HIST_timestamp(&time_two);
2138 HIST_add(time_hist,delta_micro(&time_one,&time_two));
2139 #endif /* WANT_HISTOGRAM */
2140 #ifdef WANT_INTERVALS
2141 if (demo_mode) {
2142 units_this_tick += 1;
2143 }
2144 /* in this case, the interval count is the count-down couter */
2145 /* to decide to sleep for a little bit */
2146 if ((interval_burst) && (--interval_count == 0)) {
2147 /* call sigsuspend and wait for the interval timer to get us */
2148 /* out */
2149 if (debug) {
2150 fprintf(where,"about to suspend\n");
2151 fflush(where);
2152 }
2153 if (sigsuspend(&signal_set) == EFAULT) {
2154 fprintf(where,
2155 "send_xti_udp_rr: fault with signal set!\n");
2156 fflush(where);
2157 exit(1);
2158 }
2159 interval_count = interval_burst;
2160 }
2161 #endif /* WANT_INTERVALS */
2162
2163 nummessages++;
2164 if (trans_remaining) {
2165 trans_remaining--;
2166 }
2167
2168 if (debug > 3) {
2169 if ((nummessages % 100) == 0) {
2170 fprintf(where,
2171 "Transaction %d completed\n",
2172 nummessages);
2173 fflush(where);
2174 }
2175 }
2176 }
2177
2178
2179 /* this call will always give us the elapsed time for the test, and */
2180 /* will also store-away the necessaries for cpu utilization */
2181
2182 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
2183 /* measured? how long */
2184 /* did we really run? */
2185
2186 /* Get the statistics from the remote end. The remote will have */
2187 /* calculated service demand and all those interesting things. If it */
2188 /* wasn't supposed to care, it will return obvious values. */
2189
2190 recv_response();
2191 if (!netperf_response.content.serv_errno) {
2192 if (debug)
2193 fprintf(where,"remote results obtained\n");
2194 }
2195 else {
2196 Set_errno(netperf_response.content.serv_errno);
2197 perror("netperf: remote error");
2198
2199 exit(1);
2200 }
2201
2202 /* We now calculate what our thruput was for the test. */
2203
2204 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
2205 thruput = nummessages/elapsed_time;
2206
2207 if (local_cpu_usage || remote_cpu_usage) {
2208 /* We must now do a little math for service demand and cpu */
2209 /* utilization for the system(s) */
2210 /* Of course, some of the information might be bogus because */
2211 /* there was no idle counter in the kernel(s). We need to make */
2212 /* a note of this for the user's benefit...*/
2213 if (local_cpu_usage) {
2214 local_cpu_utilization = calc_cpu_util(0.0);
2215 /* since calc_service demand is doing ms/Kunit we will */
2216 /* multiply the number of transaction by 1024 to get */
2217 /* "good" numbers */
2218 local_service_demand = calc_service_demand((double) nummessages*1024,
2219 0.0,
2220 0.0,
2221 0);
2222 }
2223 else {
2224 local_cpu_utilization = -1.0;
2225 local_service_demand = -1.0;
2226 }
2227
2228 if (remote_cpu_usage) {
2229 remote_cpu_utilization = xti_tcp_rr_result->cpu_util;
2230 /* since calc_service demand is doing ms/Kunit we will */
2231 /* multiply the number of transaction by 1024 to get */
2232 /* "good" numbers */
2233 remote_service_demand = calc_service_demand((double) nummessages*1024,
2234 0.0,
2235 remote_cpu_utilization,
2236 xti_tcp_rr_result->num_cpus);
2237 }
2238 else {
2239 remote_cpu_utilization = -1.0;
2240 remote_service_demand = -1.0;
2241 }
2242
2243 }
2244 else {
2245 /* we were not measuring cpu, for the confidence stuff, we */
2246 /* should make it -1.0 */
2247 local_cpu_utilization = -1.0;
2248 local_service_demand = -1.0;
2249 remote_cpu_utilization = -1.0;
2250 remote_service_demand = -1.0;
2251 }
2252
2253 /* at this point, we want to calculate the confidence information. */
2254 /* if debugging is on, calculate_confidence will print-out the */
2255 /* parameters we pass it */
2256
2257 calculate_confidence(confidence_iteration,
2258 elapsed_time,
2259 thruput,
2260 local_cpu_utilization,
2261 remote_cpu_utilization,
2262 local_service_demand,
2263 remote_service_demand);
2264
2265
2266 confidence_iteration++;
2267
2268 /* we are now done with the socket, so close it */
2269 t_close(send_socket);
2270
2271 }
2272
2273 retrieve_confident_values(&elapsed_time,
2274 &thruput,
2275 &local_cpu_utilization,
2276 &remote_cpu_utilization,
2277 &local_service_demand,
2278 &remote_service_demand);
2279
2280 /* We are now ready to print all the information. If the user */
2281 /* has specified zero-level verbosity, we will just print the */
2282 /* local service demand, or the remote service demand. If the */
2283 /* user has requested verbosity level 1, he will get the basic */
2284 /* "streamperf" numbers. If the user has specified a verbosity */
2285 /* of greater than 1, we will display a veritable plethora of */
2286 /* background information from outside of this block as it it */
2287 /* not cpu_measurement specific... */
2288
2289 if (confidence < 0) {
2290 /* we did not hit confidence, but were we asked to look for it? */
2291 if (iteration_max > 1) {
2292 display_confidence();
2293 }
2294 }
2295
2296 if (local_cpu_usage || remote_cpu_usage) {
2297 local_cpu_method = format_cpu_method(cpu_method);
2298 remote_cpu_method = format_cpu_method(xti_tcp_rr_result->cpu_method);
2299
2300 switch (verbosity) {
2301 case 0:
2302 if (local_cpu_usage) {
2303 fprintf(where,
2304 cpu_fmt_0,
2305 local_service_demand,
2306 local_cpu_method);
2307 }
2308 else {
2309 fprintf(where,
2310 cpu_fmt_0,
2311 remote_service_demand,
2312 remote_cpu_method);
2313 }
2314 break;
2315 case 1:
2316 case 2:
2317 if (print_headers) {
2318 fprintf(where,
2319 cpu_title,
2320 local_cpu_method,
2321 remote_cpu_method);
2322 }
2323
2324 fprintf(where,
2325 cpu_fmt_1_line_1, /* the format string */
2326 lss_size, /* local sendbuf size */
2327 lsr_size,
2328 req_size, /* how large were the requests */
2329 rsp_size, /* guess */
2330 elapsed_time, /* how long was the test */
2331 thruput,
2332 local_cpu_utilization, /* local cpu */
2333 remote_cpu_utilization, /* remote cpu */
2334 local_service_demand, /* local service demand */
2335 remote_service_demand); /* remote service demand */
2336 fprintf(where,
2337 cpu_fmt_1_line_2,
2338 rss_size,
2339 rsr_size);
2340 break;
2341 }
2342 }
2343 else {
2344 /* The tester did not wish to measure service demand. */
2345
2346 switch (verbosity) {
2347 case 0:
2348 fprintf(where,
2349 tput_fmt_0,
2350 thruput);
2351 break;
2352 case 1:
2353 case 2:
2354 if (print_headers) {
2355 fprintf(where,tput_title,format_units());
2356 }
2357
2358 fprintf(where,
2359 tput_fmt_1_line_1, /* the format string */
2360 lss_size,
2361 lsr_size,
2362 req_size, /* how large were the requests */
2363 rsp_size, /* how large were the responses */
2364 elapsed_time, /* how long did it take */
2365 thruput);
2366 fprintf(where,
2367 tput_fmt_1_line_2,
2368 rss_size, /* remote recvbuf size */
2369 rsr_size);
2370
2371 break;
2372 }
2373 }
2374
2375 /* it would be a good thing to include information about some of the */
2376 /* other parameters that may have been set for this test, but at the */
2377 /* moment, I do not wish to figure-out all the formatting, so I will */
2378 /* just put this comment here to help remind me that it is something */
2379 /* that should be done at a later time. */
2380
2381 /* how to handle the verbose information in the presence of */
2382 /* confidence intervals is yet to be determined... raj 11/94 */
2383 if (verbosity > 1) {
2384 /* The user wanted to know it all, so we will give it to him. */
2385 /* This information will include as much as we can find about */
2386 /* TCP statistics, the alignments of the sends and receives */
2387 /* and all that sort of rot... */
2388
2389 fprintf(where,
2390 ksink_fmt,
2391 local_send_align,
2392 remote_recv_offset,
2393 local_send_offset,
2394 remote_recv_offset);
2395
2396 #ifdef WANT_HISTOGRAM
2397 fprintf(where,"\nHistogram of request/response times\n");
2398 fflush(where);
2399 HIST_report(time_hist);
2400 #endif /* WANT_HISTOGRAM */
2401
2402 }
2403
2404 }
2405
2406 void
send_xti_udp_stream(char remote_host[])2407 send_xti_udp_stream(char remote_host[])
2408 {
2409 /**********************************************************************/
2410 /* */
2411 /* UDP Unidirectional Send Test */
2412 /* */
2413 /**********************************************************************/
2414 char *tput_title = "\
2415 Socket Message Elapsed Messages \n\
2416 Size Size Time Okay Errors Throughput\n\
2417 bytes bytes secs # # %s/sec\n\n";
2418
2419 char *tput_fmt_0 =
2420 "%7.2f\n";
2421
2422 char *tput_fmt_1 = "\
2423 %6d %6d %-7.2f %7d %6d %7.2f\n\
2424 %6d %-7.2f %7d %7.2f\n\n";
2425
2426
2427 char *cpu_title = "\
2428 Socket Message Elapsed Messages CPU Service\n\
2429 Size Size Time Okay Errors Throughput Util Demand\n\
2430 bytes bytes secs # # %s/sec %% %c%c us/KB\n\n";
2431
2432 char *cpu_fmt_0 =
2433 "%6.2f %c\n";
2434
2435 char *cpu_fmt_1 = "\
2436 %6d %6d %-7.2f %7d %6d %7.1f %-6.2f %-6.3f\n\
2437 %6d %-7.2f %7d %7.1f %-6.2f %-6.3f\n\n";
2438
2439 unsigned int messages_recvd;
2440 unsigned int messages_sent;
2441 unsigned int failed_sends;
2442
2443 float elapsed_time,
2444 recv_elapsed,
2445 local_cpu_utilization,
2446 remote_cpu_utilization;
2447
2448 float local_service_demand, remote_service_demand;
2449 double local_thruput, remote_thruput;
2450 double bytes_sent;
2451 double bytes_recvd;
2452
2453
2454 int len;
2455 int *message_int_ptr;
2456 struct ring_elt *send_ring;
2457 SOCKET data_socket;
2458
2459 unsigned int sum_messages_sent;
2460 unsigned int sum_messages_recvd;
2461 unsigned int sum_failed_sends;
2462 double sum_local_thruput;
2463
2464 #ifdef WANT_INTERVALS
2465 int interval_count;
2466 sigset_t signal_set;
2467 #endif /* WANT_INTERVALS */
2468
2469 struct hostent *hp;
2470 struct sockaddr_in server;
2471 unsigned int addr;
2472
2473 struct t_unitdata unitdata;
2474
2475 struct xti_udp_stream_request_struct *xti_udp_stream_request;
2476 struct xti_udp_stream_response_struct *xti_udp_stream_response;
2477 struct xti_udp_stream_results_struct *xti_udp_stream_results;
2478
2479 xti_udp_stream_request =
2480 (struct xti_udp_stream_request_struct *)netperf_request.content.test_specific_data;
2481 xti_udp_stream_response =
2482 (struct xti_udp_stream_response_struct *)netperf_response.content.test_specific_data;
2483 xti_udp_stream_results =
2484 (struct xti_udp_stream_results_struct *)netperf_response.content.test_specific_data;
2485
2486 #ifdef WANT_HISTOGRAM
2487 time_hist = HIST_new();
2488 #endif /* WANT_HISTOGRAM */
2489
2490 /* since we are now disconnected from the code that established the */
2491 /* control socket, and since we want to be able to use different */
2492 /* protocols and such, we are passed the name of the remote host and */
2493 /* must turn that into the test specific addressing information. */
2494
2495 bzero((char *)&server,
2496 sizeof(server));
2497
2498 /* it would seem that while HP-UX will allow an IP address (as a */
2499 /* string) in a call to gethostbyname, other, less enlightened */
2500 /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */
2501 /* order changed to check for IP address first. raj 7/96 */
2502
2503 if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
2504 /* it was not an IP address, try it as a name */
2505 if ((hp = gethostbyname(remote_host)) == NULL) {
2506 /* we have no idea what it is */
2507 fprintf(where,
2508 "establish_control: could not resolve the destination %s\n",
2509 remote_host);
2510 fflush(where);
2511 exit(1);
2512 }
2513 else {
2514 /* it was a valid remote_host */
2515 bcopy(hp->h_addr,
2516 (char *)&server.sin_addr,
2517 hp->h_length);
2518 server.sin_family = hp->h_addrtype;
2519 }
2520 }
2521 else {
2522 /* it was a valid IP address */
2523 server.sin_addr.s_addr = addr;
2524 server.sin_family = AF_INET;
2525 }
2526
2527 if ( print_headers ) {
2528 fprintf(where,"UDP UNIDIRECTIONAL SEND TEST");
2529 fprintf(where," to %s", remote_host);
2530 if (iteration_max > 1) {
2531 fprintf(where,
2532 " : +/-%3.1f%% @ %2d%% conf.",
2533 interval/0.02,
2534 confidence_level);
2535 }
2536 if (loc_sndavoid ||
2537 loc_rcvavoid ||
2538 rem_sndavoid ||
2539 rem_rcvavoid) {
2540 fprintf(where," : copy avoidance");
2541 }
2542 #ifdef WANT_HISTOGRAM
2543 fprintf(where," : histogram");
2544 #endif /* WANT_HISTOGRAM */
2545 #ifdef WANT_INTERVALS
2546 fprintf(where," : interval");
2547 #endif /* WANT_INTERVALS */
2548 #ifdef DIRTY
2549 fprintf(where," : dirty data");
2550 #endif /* DIRTY */
2551 fprintf(where,"\n");
2552 }
2553
2554 send_ring = NULL;
2555 confidence_iteration = 1;
2556 init_stat();
2557 sum_messages_sent = 0;
2558 sum_messages_recvd = 0;
2559 sum_failed_sends = 0;
2560 sum_local_thruput = 0.0;
2561
2562 /* we have a great-big while loop which controls the number of times */
2563 /* we run a particular test. this is for the calculation of a */
2564 /* confidence interval (I really should have stayed awake during */
2565 /* probstats :). If the user did not request confidence measurement */
2566 /* (no confidence is the default) then we will only go though the */
2567 /* loop once. the confidence stuff originates from the folks at IBM */
2568
2569 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
2570 (confidence_iteration <= iteration_min)) {
2571
2572 /* initialize a few counters. we have to remember that we might be */
2573 /* going through the loop more than once. */
2574 messages_sent = 0;
2575 messages_recvd = 0;
2576 failed_sends = 0;
2577 times_up = 0;
2578
2579 /*set up the data socket */
2580 data_socket = create_xti_endpoint(loc_xti_device);
2581
2582 if (data_socket == INVALID_SOCKET) {
2583 perror("send_xti_udp_stream: create_xti_endpoint");
2584 exit(1);
2585 }
2586
2587 if (t_bind(data_socket, NULL, NULL) == SOCKET_ERROR) {
2588 t_error("send_xti_udp_stream: t_bind");
2589 exit(1);
2590 }
2591
2592 /* now, we want to see if we need to set the send_size */
2593 if (send_size == 0) {
2594 if (lss_size > 0) {
2595 send_size = lss_size;
2596 }
2597 else {
2598 send_size = 4096;
2599 }
2600 }
2601
2602 /* set-up the data buffer with the requested alignment and offset, */
2603 /* most of the numbers here are just a hack to pick something nice */
2604 /* and big in an attempt to never try to send a buffer a second time */
2605 /* before it leaves the node...unless the user set the width */
2606 /* explicitly. */
2607 if (send_width == 0) send_width = 32;
2608
2609 if (send_ring == NULL ) {
2610 send_ring = allocate_buffer_ring(send_width,
2611 send_size,
2612 local_send_align,
2613 local_send_offset);
2614 }
2615
2616
2617 /* if the user supplied a cpu rate, this call will complete rather */
2618 /* quickly, otherwise, the cpu rate will be retured to us for */
2619 /* possible display. The Library will keep it's own copy of this data */
2620 /* for use elsewhere. We will only display it. (Does that make it */
2621 /* "opaque" to us?) */
2622
2623 if (local_cpu_usage)
2624 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
2625
2626 /* Tell the remote end to set up the data connection. The server */
2627 /* sends back the port number and alters the socket parameters there. */
2628 /* Of course this is a datagram service so no connection is actually */
2629 /* set up, the server just sets up the socket and binds it. */
2630
2631 netperf_request.content.request_type = DO_XTI_UDP_STREAM;
2632 xti_udp_stream_request->recv_buf_size = rsr_size;
2633 xti_udp_stream_request->message_size = send_size;
2634 xti_udp_stream_request->recv_alignment = remote_recv_align;
2635 xti_udp_stream_request->recv_offset = remote_recv_offset;
2636 xti_udp_stream_request->measure_cpu = remote_cpu_usage;
2637 xti_udp_stream_request->cpu_rate = remote_cpu_rate;
2638 xti_udp_stream_request->test_length = test_time;
2639 xti_udp_stream_request->so_rcvavoid = rem_rcvavoid;
2640 xti_udp_stream_request->so_sndavoid = rem_sndavoid;
2641
2642 strcpy(xti_udp_stream_request->xti_device, rem_xti_device);
2643
2644 #ifdef __alpha
2645
2646 /* ok - even on a DEC box, strings are strings. I didn't really want */
2647 /* to ntohl the words of a string. since I don't want to teach the */
2648 /* send_ and recv_ _request and _response routines about the types, */
2649 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
2650 /* solution would be to use XDR, but I am still leary of being able */
2651 /* to find XDR libs on all platforms I want running netperf. raj */
2652 {
2653 int *charword;
2654 int *initword;
2655 int *lastword;
2656
2657 initword = (int *) xti_udp_stream_request->xti_device;
2658 lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
2659
2660 for (charword = initword;
2661 charword < lastword;
2662 charword++) {
2663
2664 *charword = ntohl(*charword);
2665 }
2666 }
2667 #endif /* __alpha */
2668
2669 send_request();
2670
2671 recv_response();
2672
2673 if (!netperf_response.content.serv_errno) {
2674 if (debug)
2675 fprintf(where,"send_xti_udp_stream: remote data connection done.\n");
2676 }
2677 else {
2678 Set_errno(netperf_response.content.serv_errno);
2679 perror("send_xti_udp_stream: error on remote");
2680 exit(1);
2681 }
2682
2683 /* Place the port number returned by the remote into the sockaddr */
2684 /* structure so our sends can be sent to the correct place. Also get */
2685 /* some of the returned socket buffer information for user display. */
2686
2687 /* make sure that port numbers are in the proper order */
2688 server.sin_port = (short)xti_udp_stream_response->data_port_number;
2689 server.sin_port = htons(server.sin_port);
2690 rsr_size = xti_udp_stream_response->recv_buf_size;
2691 rss_size = xti_udp_stream_response->send_buf_size;
2692 remote_cpu_rate = xti_udp_stream_response->cpu_rate;
2693
2694 /* it would seem that XTI does not allow the expedient of */
2695 /* "connecting" a UDP end-point the way BSD does. so, we will do */
2696 /* everything with t_sndudata and t_rcvudata. Our "virtual" */
2697 /* connect here will be to assign the destination portion of the */
2698 /* t_unitdata struct here, where we would have otherwise called */
2699 /* t_connect() raj 3/95 */
2700
2701 memset (&unitdata, 0, sizeof(unitdata));
2702 unitdata.addr.maxlen = sizeof(struct sockaddr_in);
2703 unitdata.addr.len = sizeof(struct sockaddr_in);
2704 unitdata.addr.buf = (char *)&server;
2705
2706 /* we don't use any options, so might as well set that part here */
2707 /* too */
2708
2709 unitdata.opt.maxlen = 0;
2710 unitdata.opt.len = 0;
2711 unitdata.opt.buf = NULL;
2712
2713 /* we need to initialize the send buffer for the first time as */
2714 /* well since we move to the next pointer after the send call. */
2715
2716 unitdata.udata.maxlen = send_size;
2717 unitdata.udata.len = send_size;
2718 unitdata.udata.buf = send_ring->buffer_ptr;
2719
2720 /* set up the timer to call us after test_time. one of these days, */
2721 /* it might be nice to figure-out a nice reliable way to have the */
2722 /* test controlled by a byte count as well, but since UDP is not */
2723 /* reliable, that could prove difficult. so, in the meantime, we */
2724 /* only allow a XTI_UDP_STREAM test to be a timed test. */
2725
2726 if (test_time) {
2727 times_up = 0;
2728 start_timer(test_time);
2729 }
2730 else {
2731 fprintf(where,"Sorry, XTI_UDP_STREAM tests must be timed.\n");
2732 fflush(where);
2733 exit(1);
2734 }
2735
2736 /* Get the start count for the idle counter and the start time */
2737
2738 cpu_start(local_cpu_usage);
2739
2740 #ifdef WANT_INTERVALS
2741 if ((interval_burst) || (demo_mode)) {
2742 /* zero means that we never pause, so we never should need the */
2743 /* interval timer, unless we are in demo_mode */
2744 start_itimer(interval_wate);
2745 }
2746 interval_count = interval_burst;
2747 /* get the signal set for the call to sigsuspend */
2748 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
2749 fprintf(where,
2750 "send_xti_udp_stream: unable to get sigmask errno %d\n",
2751 errno);
2752 fflush(where);
2753 exit(1);
2754 }
2755 #endif /* WANT_INTERVALS */
2756
2757 /* Send datagrams like there was no tomorrow. at somepoint it might */
2758 /* be nice to set this up so that a quantity of bytes could be sent, */
2759 /* but we still need some sort of end of test trigger on the receive */
2760 /* side. that could be a select with a one second timeout, but then */
2761 /* if there is a test where none of the data arrives for awile and */
2762 /* then starts again, we would end the test too soon. something to */
2763 /* think about... */
2764 while (!times_up) {
2765
2766 #ifdef DIRTY
2767 /* we want to dirty some number of consecutive integers in the buffer */
2768 /* we are about to send. we may also want to bring some number of */
2769 /* them cleanly into the cache. The clean ones will follow any dirty */
2770 /* ones into the cache. */
2771
2772 access_buffer(send_ring->buffer_ptr,
2773 send_size,
2774 loc_dirty_count,
2775 loc_clean_count);
2776
2777 #endif /* DIRTY */
2778
2779 #ifdef WANT_HISTOGRAM
2780 HIST_timestamp(&time_one);
2781 #endif /* WANT_HISTOGRAM */
2782
2783 if ((t_sndudata(data_socket,
2784 &unitdata)) != 0) {
2785 if (errno == EINTR)
2786 break;
2787 if (errno == ENOBUFS) {
2788 failed_sends++;
2789 continue;
2790 }
2791 perror("xti_udp_send: data send error");
2792 t_error("xti_udp_send: data send error");
2793 exit(1);
2794 }
2795 messages_sent++;
2796
2797 /* now we want to move our pointer to the next position in the */
2798 /* data buffer...and update the unitdata structure */
2799
2800 send_ring = send_ring->next;
2801 unitdata.udata.buf = send_ring->buffer_ptr;
2802
2803 #ifdef WANT_HISTOGRAM
2804 /* get the second timestamp */
2805 HIST_timestamp(&time_two);
2806 HIST_add(time_hist,delta_micro(&time_one,&time_two));
2807 #endif /* WANT_HISTOGRAM */
2808 #ifdef WANT_INTERVALS
2809 if (demo_mode) {
2810 units_this_tick += send_size;
2811 }
2812 /* in this case, the interval count is the count-down couter */
2813 /* to decide to sleep for a little bit */
2814 if ((interval_burst) && (--interval_count == 0)) {
2815 /* call sigsuspend and wait for the interval timer to get us */
2816 /* out */
2817 if (debug) {
2818 fprintf(where,"about to suspend\n");
2819 fflush(where);
2820 }
2821 if (sigsuspend(&signal_set) == EFAULT) {
2822 fprintf(where,
2823 "send_xti_udp_stream: fault with signal set!\n");
2824 fflush(where);
2825 exit(1);
2826 }
2827 interval_count = interval_burst;
2828 }
2829 #endif /* WANT_INTERVALS */
2830
2831 }
2832
2833 /* This is a timed test, so the remote will be returning to us after */
2834 /* a time. We should not need to send any "strange" messages to tell */
2835 /* the remote that the test is completed, unless we decide to add a */
2836 /* number of messages to the test. */
2837
2838 /* the test is over, so get stats and stuff */
2839 cpu_stop(local_cpu_usage,
2840 &elapsed_time);
2841
2842 /* Get the statistics from the remote end */
2843 recv_response();
2844 if (!netperf_response.content.serv_errno) {
2845 if (debug)
2846 fprintf(where,"send_xti_udp_stream: remote results obtained\n");
2847 }
2848 else {
2849 Set_errno(netperf_response.content.serv_errno);
2850 perror("send_xti_udp_stream: error on remote");
2851 exit(1);
2852 }
2853
2854 bytes_sent = (double) send_size * (double) messages_sent;
2855 local_thruput = calc_thruput(bytes_sent);
2856
2857 messages_recvd = xti_udp_stream_results->messages_recvd;
2858 bytes_recvd = (double) send_size * (double) messages_recvd;
2859
2860 /* we asume that the remote ran for as long as we did */
2861
2862 remote_thruput = calc_thruput(bytes_recvd);
2863
2864 /* print the results for this socket and message size */
2865
2866 if (local_cpu_usage || remote_cpu_usage) {
2867 /* We must now do a little math for service demand and cpu */
2868 /* utilization for the system(s) We pass zeros for the local */
2869 /* cpu utilization and elapsed time to tell the routine to use */
2870 /* the libraries own values for those. */
2871 if (local_cpu_usage) {
2872 local_cpu_utilization = calc_cpu_util(0.0);
2873 /* shouldn't this really be based on bytes_recvd, since that is */
2874 /* the effective throughput of the test? I think that it should, */
2875 /* so will make the change raj 11/94 */
2876 local_service_demand = calc_service_demand(bytes_recvd,
2877 0.0,
2878 0.0,
2879 0);
2880 }
2881 else {
2882 local_cpu_utilization = -1.0;
2883 local_service_demand = -1.0;
2884 }
2885
2886 /* The local calculations could use variables being kept by */
2887 /* the local netlib routines. The remote calcuations need to */
2888 /* have a few things passed to them. */
2889 if (remote_cpu_usage) {
2890 remote_cpu_utilization = xti_udp_stream_results->cpu_util;
2891 remote_service_demand = calc_service_demand(bytes_recvd,
2892 0.0,
2893 remote_cpu_utilization,
2894 xti_udp_stream_results->num_cpus);
2895 }
2896 else {
2897 remote_cpu_utilization = -1.0;
2898 remote_service_demand = -1.0;
2899 }
2900 }
2901 else {
2902 /* we were not measuring cpu, for the confidence stuff, we */
2903 /* should make it -1.0 */
2904 local_cpu_utilization = -1.0;
2905 local_service_demand = -1.0;
2906 remote_cpu_utilization = -1.0;
2907 remote_service_demand = -1.0;
2908 }
2909
2910 /* at this point, we want to calculate the confidence information. */
2911 /* if debugging is on, calculate_confidence will print-out the */
2912 /* parameters we pass it */
2913
2914 calculate_confidence(confidence_iteration,
2915 elapsed_time,
2916 remote_thruput,
2917 local_cpu_utilization,
2918 remote_cpu_utilization,
2919 local_service_demand,
2920 remote_service_demand);
2921
2922 /* since the routine calculate_confidence is rather generic, and */
2923 /* we have a few other parms of interest, we will do a little work */
2924 /* here to caclulate their average. */
2925 sum_messages_sent += messages_sent;
2926 sum_messages_recvd += messages_recvd;
2927 sum_failed_sends += failed_sends;
2928 sum_local_thruput += local_thruput;
2929
2930 confidence_iteration++;
2931
2932 /* this datapoint is done, so we don't need the socket any longer */
2933 close(data_socket);
2934
2935 }
2936
2937 /* we should reach this point once the test is finished */
2938
2939 retrieve_confident_values(&elapsed_time,
2940 &remote_thruput,
2941 &local_cpu_utilization,
2942 &remote_cpu_utilization,
2943 &local_service_demand,
2944 &remote_service_demand);
2945
2946 /* some of the interesting values aren't covered by the generic */
2947 /* confidence routine */
2948 messages_sent = sum_messages_sent / (confidence_iteration -1);
2949 messages_recvd = sum_messages_recvd / (confidence_iteration -1);
2950 failed_sends = sum_failed_sends / (confidence_iteration -1);
2951 local_thruput = sum_local_thruput / (confidence_iteration -1);
2952
2953 /* We are now ready to print all the information. If the user */
2954 /* has specified zero-level verbosity, we will just print the */
2955 /* local service demand, or the remote service demand. If the */
2956 /* user has requested verbosity level 1, he will get the basic */
2957 /* "streamperf" numbers. If the user has specified a verbosity */
2958 /* of greater than 1, we will display a veritable plethora of */
2959 /* background information from outside of this block as it it */
2960 /* not cpu_measurement specific... */
2961
2962
2963 if (confidence < 0) {
2964 /* we did not hit confidence, but were we asked to look for it? */
2965 if (iteration_max > 1) {
2966 display_confidence();
2967 }
2968 }
2969
2970 if (local_cpu_usage || remote_cpu_usage) {
2971 local_cpu_method = format_cpu_method(cpu_method);
2972 remote_cpu_method = format_cpu_method(xti_udp_stream_results->cpu_method);
2973
2974 switch (verbosity) {
2975 case 0:
2976 if (local_cpu_usage) {
2977 fprintf(where,
2978 cpu_fmt_0,
2979 local_service_demand,
2980 local_cpu_method);
2981 }
2982 else {
2983 fprintf(where,
2984 cpu_fmt_0,
2985 remote_service_demand,
2986 local_cpu_method);
2987 }
2988 break;
2989 case 1:
2990 case 2:
2991 if (print_headers) {
2992 fprintf(where,
2993 cpu_title,
2994 format_units(),
2995 local_cpu_method,
2996 remote_cpu_method);
2997 }
2998
2999 fprintf(where,
3000 cpu_fmt_1, /* the format string */
3001 lss_size, /* local sendbuf size */
3002 send_size, /* how large were the sends */
3003 elapsed_time, /* how long was the test */
3004 messages_sent,
3005 failed_sends,
3006 local_thruput, /* what was the xfer rate */
3007 local_cpu_utilization, /* local cpu */
3008 local_service_demand, /* local service demand */
3009 rsr_size,
3010 elapsed_time,
3011 messages_recvd,
3012 remote_thruput,
3013 remote_cpu_utilization, /* remote cpu */
3014 remote_service_demand); /* remote service demand */
3015 break;
3016 }
3017 }
3018 else {
3019 /* The tester did not wish to measure service demand. */
3020 switch (verbosity) {
3021 case 0:
3022 fprintf(where,
3023 tput_fmt_0,
3024 local_thruput);
3025 break;
3026 case 1:
3027 case 2:
3028 if (print_headers) {
3029 fprintf(where,tput_title,format_units());
3030 }
3031 fprintf(where,
3032 tput_fmt_1, /* the format string */
3033 lss_size, /* local sendbuf size */
3034 send_size, /* how large were the sends */
3035 elapsed_time, /* how long did it take */
3036 messages_sent,
3037 failed_sends,
3038 local_thruput,
3039 rsr_size, /* remote recvbuf size */
3040 elapsed_time,
3041 messages_recvd,
3042 remote_thruput);
3043 break;
3044 }
3045 }
3046
3047 fflush(where);
3048 #ifdef WANT_HISTOGRAM
3049 if (verbosity > 1) {
3050 fprintf(where,"\nHistogram of time spent in send() call\n");
3051 fflush(where);
3052 HIST_report(time_hist);
3053 }
3054 #endif /* WANT_HISTOGRAM */
3055
3056 }
3057
3058
3059 /* this routine implements the receive side (netserver) of the */
3060 /* XTI_UDP_STREAM performance test. */
3061
3062 void
recv_xti_udp_stream()3063 recv_xti_udp_stream()
3064 {
3065 struct ring_elt *recv_ring;
3066
3067 struct t_bind bind_req, bind_resp;
3068 struct t_unitdata unitdata;
3069 int flags = 0;
3070
3071 struct sockaddr_in myaddr_in;
3072 struct sockaddr_in fromaddr_in;
3073
3074 SOCKET s_data;
3075 int addrlen;
3076 unsigned int bytes_received = 0;
3077 float elapsed_time;
3078
3079 unsigned int message_size;
3080 unsigned int messages_recvd = 0;
3081
3082 struct xti_udp_stream_request_struct *xti_udp_stream_request;
3083 struct xti_udp_stream_response_struct *xti_udp_stream_response;
3084 struct xti_udp_stream_results_struct *xti_udp_stream_results;
3085
3086 xti_udp_stream_request =
3087 (struct xti_udp_stream_request_struct *)netperf_request.content.test_specific_data;
3088 xti_udp_stream_response =
3089 (struct xti_udp_stream_response_struct *)netperf_response.content.test_specific_data;
3090 xti_udp_stream_results =
3091 (struct xti_udp_stream_results_struct *)netperf_response.content.test_specific_data;
3092
3093 if (debug) {
3094 fprintf(where,"netserver: recv_xti_udp_stream: entered...\n");
3095 fflush(where);
3096 }
3097
3098 /* We want to set-up the listen socket with all the desired */
3099 /* parameters and then let the initiator know that all is ready. If */
3100 /* socket size defaults are to be used, then the initiator will have */
3101 /* sent us 0's. If the socket sizes cannot be changed, then we will */
3102 /* send-back what they are. If that information cannot be determined, */
3103 /* then we send-back -1's for the sizes. If things go wrong for any */
3104 /* reason, we will drop back ten yards and punt. */
3105
3106 /* If anything goes wrong, we want the remote to know about it. It */
3107 /* would be best if the error that the remote reports to the user is */
3108 /* the actual error we encountered, rather than some bogus unexpected */
3109 /* response type message. */
3110
3111 if (debug > 1) {
3112 fprintf(where,"recv_xti_udp_stream: setting the response type...\n");
3113 fflush(where);
3114 }
3115
3116 netperf_response.content.response_type = XTI_UDP_STREAM_RESPONSE;
3117
3118 if (debug > 2) {
3119 fprintf(where,"recv_xti_udp_stream: the response type is set...\n");
3120 fflush(where);
3121 }
3122
3123 /* We now alter the message_ptr variable to be at the desired */
3124 /* alignment with the desired offset. */
3125
3126 if (debug > 1) {
3127 fprintf(where,"recv_xti_udp_stream: requested alignment of %d\n",
3128 xti_udp_stream_request->recv_alignment);
3129 fflush(where);
3130 }
3131
3132 if (recv_width == 0) recv_width = 1;
3133
3134 recv_ring = allocate_buffer_ring(recv_width,
3135 xti_udp_stream_request->message_size,
3136 xti_udp_stream_request->recv_alignment,
3137 xti_udp_stream_request->recv_offset);
3138
3139 if (debug > 1) {
3140 fprintf(where,"recv_xti_udp_stream: receive alignment and offset set...\n");
3141 fflush(where);
3142 }
3143
3144 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
3145 /* can put in OUR values !-) At some point, we may want to nail this */
3146 /* socket to a particular network-level address, but for now, */
3147 /* INADDR_ANY should be just fine. */
3148
3149 bzero((char *)&myaddr_in,
3150 sizeof(myaddr_in));
3151 myaddr_in.sin_family = AF_INET;
3152 myaddr_in.sin_addr.s_addr = INADDR_ANY;
3153 myaddr_in.sin_port = 0;
3154
3155 /* Grab a socket to listen on, and then listen on it. */
3156
3157 if (debug > 1) {
3158 fprintf(where,"recv_xti_udp_stream: grabbing a socket...\n");
3159 fflush(where);
3160 }
3161
3162 /* create_xti_endpoint expects to find some things in the global */
3163 /* variables, so set the globals based on the values in the request. */
3164 /* once the socket has been created, we will set the response values */
3165 /* based on the updated value of those globals. raj 7/94 */
3166 lsr_size = xti_udp_stream_request->recv_buf_size;
3167 loc_rcvavoid = xti_udp_stream_request->so_rcvavoid;
3168 loc_sndavoid = xti_udp_stream_request->so_sndavoid;
3169
3170 #ifdef __alpha
3171
3172 /* ok - even on a DEC box, strings are strings. I din't really want */
3173 /* to ntohl the words of a string. since I don't want to teach the */
3174 /* send_ and recv_ _request and _response routines about the types, */
3175 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
3176 /* solution would be to use XDR, but I am still leary of being able */
3177 /* to find XDR libs on all platforms I want running netperf. raj */
3178 {
3179 int *charword;
3180 int *initword;
3181 int *lastword;
3182
3183 initword = (int *) xti_udp_stream_request->xti_device;
3184 lastword = initword + ((xti_udp_stream_request->dev_name_len + 3) / 4);
3185
3186 for (charword = initword;
3187 charword < lastword;
3188 charword++) {
3189
3190 *charword = htonl(*charword);
3191 }
3192 }
3193
3194 #endif /* __alpha */
3195
3196 s_data = create_xti_endpoint(xti_udp_stream_request->xti_device);
3197
3198 if (s_data == INVALID_SOCKET) {
3199 netperf_response.content.serv_errno = errno;
3200 send_response();
3201 exit(1);
3202 }
3203
3204 /* Let's get an address assigned to this socket so we can tell the */
3205 /* initiator how to reach the data socket. There may be a desire to */
3206 /* nail this socket to a specific IP address in a multi-homed, */
3207 /* multi-connection situation, but for now, we'll ignore the issue */
3208 /* and concentrate on single connection testing. */
3209
3210 bind_req.addr.maxlen = sizeof(struct sockaddr_in);
3211 bind_req.addr.len = sizeof(struct sockaddr_in);
3212 bind_req.addr.buf = (char *)&myaddr_in;
3213 bind_req.qlen = 1;
3214
3215 bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
3216 bind_resp.addr.len = sizeof(struct sockaddr_in);
3217 bind_resp.addr.buf = (char *)&myaddr_in;
3218 bind_resp.qlen = 1;
3219
3220 if (t_bind(s_data,
3221 &bind_req,
3222 &bind_resp) == SOCKET_ERROR) {
3223 netperf_response.content.serv_errno = t_errno;
3224 send_response();
3225
3226 exit(1);
3227 }
3228
3229 xti_udp_stream_response->test_length =
3230 xti_udp_stream_request->test_length;
3231
3232 /* Now myaddr_in contains the port and the internet address this is */
3233 /* returned to the sender also implicitly telling the sender that the */
3234 /* socket buffer sizing has been done. */
3235
3236 xti_udp_stream_response->data_port_number =
3237 (int) ntohs(myaddr_in.sin_port);
3238 netperf_response.content.serv_errno = 0;
3239
3240 /* But wait, there's more. If the initiator wanted cpu measurements, */
3241 /* then we must call the calibrate routine, which will return the max */
3242 /* rate back to the initiator. If the CPU was not to be measured, or */
3243 /* something went wrong with the calibration, we will return a -1 to */
3244 /* the initiator. */
3245
3246 xti_udp_stream_response->cpu_rate = 0.0; /* assume no cpu */
3247 xti_udp_stream_response->measure_cpu = 0;
3248 if (xti_udp_stream_request->measure_cpu) {
3249 /* We will pass the rate into the calibration routine. If the */
3250 /* user did not specify one, it will be 0.0, and we will do a */
3251 /* "real" calibration. Otherwise, all it will really do is */
3252 /* store it away... */
3253 xti_udp_stream_response->measure_cpu = 1;
3254 xti_udp_stream_response->cpu_rate =
3255 calibrate_local_cpu(xti_udp_stream_request->cpu_rate);
3256 }
3257
3258 message_size = xti_udp_stream_request->message_size;
3259 test_time = xti_udp_stream_request->test_length;
3260
3261 /* before we send the response back to the initiator, pull some of */
3262 /* the socket parms from the globals */
3263 xti_udp_stream_response->send_buf_size = lss_size;
3264 xti_udp_stream_response->recv_buf_size = lsr_size;
3265 xti_udp_stream_response->so_rcvavoid = loc_rcvavoid;
3266 xti_udp_stream_response->so_sndavoid = loc_sndavoid;
3267
3268 /* since we are going to call t_rcvudata() instead of t_rcv() we */
3269 /* need to init the unitdata structure raj 3/95 */
3270
3271 unitdata.addr.maxlen = sizeof(fromaddr_in);
3272 unitdata.addr.len = sizeof(fromaddr_in);
3273 unitdata.addr.buf = (char *)&fromaddr_in;
3274
3275 unitdata.opt.maxlen = 0;
3276 unitdata.opt.len = 0;
3277 unitdata.opt.buf = NULL;
3278
3279 unitdata.udata.maxlen = xti_udp_stream_request->message_size;
3280 unitdata.udata.len = xti_udp_stream_request->message_size;
3281 unitdata.udata.buf = recv_ring->buffer_ptr;
3282
3283 send_response();
3284
3285 /* Now it's time to start receiving data on the connection. We will */
3286 /* first grab the apropriate counters and then start grabbing. */
3287
3288 cpu_start(xti_udp_stream_request->measure_cpu);
3289
3290 /* The loop will exit when the timer pops, or if we happen to recv a */
3291 /* message of less than send_size bytes... */
3292
3293 times_up = 0;
3294 start_timer(test_time + PAD_TIME);
3295
3296 if (debug) {
3297 fprintf(where,"recv_xti_udp_stream: about to enter inner sanctum.\n");
3298 fflush(where);
3299 }
3300
3301 while (!times_up) {
3302 #ifdef RAJ_DEBUG
3303 if (debug) {
3304 fprintf(where,"t_rcvudata, errno %d, t_errno %d",
3305 errno,
3306 t_errno);
3307 fprintf(where," after %d messages\n",messages_recvd);
3308 fprintf(where,"addrmax %d addrlen %d addrbuf %x\n",
3309 unitdata.addr.maxlen,
3310 unitdata.addr.len,
3311 unitdata.addr.buf);
3312 fprintf(where,"optmax %d optlen %d optbuf %x\n",
3313 unitdata.opt.maxlen,
3314 unitdata.opt.len,
3315 unitdata.opt.buf);
3316 fprintf(where,"udatamax %d udatalen %d udatabuf %x\n",
3317 unitdata.udata.maxlen,
3318 unitdata.udata.len,
3319 unitdata.udata.buf);
3320 fflush(where);
3321 }
3322 #endif /* RAJ_DEBUG */
3323 if (t_rcvudata(s_data,
3324 &unitdata,
3325 &flags) != 0) {
3326 if (errno == TNODATA) {
3327 continue;
3328 }
3329 if (errno != EINTR) {
3330 netperf_response.content.serv_errno = t_errno;
3331 send_response();
3332 exit(1);
3333 }
3334 break;
3335 }
3336 messages_recvd++;
3337 recv_ring = recv_ring->next;
3338 unitdata.udata.buf = recv_ring->buffer_ptr;
3339 }
3340
3341 if (debug) {
3342 fprintf(where,"recv_xti_udp_stream: got %d messages.\n",messages_recvd);
3343 fflush(where);
3344 }
3345
3346
3347 /* The loop now exits due timer or < send_size bytes received. */
3348
3349 cpu_stop(xti_udp_stream_request->measure_cpu,&elapsed_time);
3350
3351 if (times_up) {
3352 /* we ended on a timer, subtract the PAD_TIME */
3353 elapsed_time -= (float)PAD_TIME;
3354 }
3355 else {
3356 stop_timer();
3357 }
3358
3359 if (debug) {
3360 fprintf(where,"recv_xti_udp_stream: test ended in %f seconds.\n",elapsed_time);
3361 fflush(where);
3362 }
3363
3364 bytes_received = (messages_recvd * message_size);
3365
3366 /* send the results to the sender */
3367
3368 if (debug) {
3369 fprintf(where,
3370 "recv_xti_udp_stream: got %d bytes\n",
3371 bytes_received);
3372 fflush(where);
3373 }
3374
3375 netperf_response.content.response_type = XTI_UDP_STREAM_RESULTS;
3376 xti_udp_stream_results->bytes_received = bytes_received;
3377 xti_udp_stream_results->messages_recvd = messages_recvd;
3378 xti_udp_stream_results->elapsed_time = elapsed_time;
3379 xti_udp_stream_results->cpu_method = cpu_method;
3380 if (xti_udp_stream_request->measure_cpu) {
3381 xti_udp_stream_results->cpu_util = calc_cpu_util(elapsed_time);
3382 }
3383 else {
3384 xti_udp_stream_results->cpu_util = -1.0;
3385 }
3386
3387 if (debug > 1) {
3388 fprintf(where,
3389 "recv_xti_udp_stream: test complete, sending results.\n");
3390 fflush(where);
3391 }
3392
3393 send_response();
3394
3395 }
3396
send_xti_udp_rr(char remote_host[])3397 void send_xti_udp_rr(char remote_host[])
3398 {
3399
3400 char *tput_title = "\
3401 Local /Remote\n\
3402 Socket Size Request Resp. Elapsed Trans.\n\
3403 Send Recv Size Size Time Rate \n\
3404 bytes Bytes bytes bytes secs. per sec \n\n";
3405
3406 char *tput_fmt_0 =
3407 "%7.2f\n";
3408
3409 char *tput_fmt_1_line_1 = "\
3410 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
3411 char *tput_fmt_1_line_2 = "\
3412 %-6d %-6d\n";
3413
3414 char *cpu_title = "\
3415 Local /Remote\n\
3416 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
3417 Send Recv Size Size Time Rate local remote local remote\n\
3418 bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
3419
3420 char *cpu_fmt_0 =
3421 "%6.3f %c\n";
3422
3423 char *cpu_fmt_1_line_1 = "\
3424 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
3425
3426 char *cpu_fmt_1_line_2 = "\
3427 %-6d %-6d\n";
3428
3429 char *ksink_fmt = "\
3430 Alignment Offset\n\
3431 Local Remote Local Remote\n\
3432 Send Recv Send Recv\n\
3433 %5d %5d %5d %5d\n";
3434
3435
3436 float elapsed_time;
3437
3438 struct ring_elt *send_ring;
3439 struct ring_elt *recv_ring;
3440
3441 struct t_bind bind_req, bind_resp;
3442 struct t_unitdata unitdata;
3443 struct t_unitdata send_unitdata;
3444 struct t_unitdata recv_unitdata;
3445 int flags = 0;
3446
3447 int len;
3448 int nummessages;
3449 SOCKET send_socket;
3450 int trans_remaining;
3451 int bytes_xferd;
3452
3453 int rsp_bytes_recvd;
3454
3455 float local_cpu_utilization;
3456 float local_service_demand;
3457 float remote_cpu_utilization;
3458 float remote_service_demand;
3459 double thruput;
3460
3461 struct hostent *hp;
3462 struct sockaddr_in server, myaddr_in;
3463 unsigned int addr;
3464 int addrlen;
3465
3466 struct xti_udp_rr_request_struct *xti_udp_rr_request;
3467 struct xti_udp_rr_response_struct *xti_udp_rr_response;
3468 struct xti_udp_rr_results_struct *xti_udp_rr_result;
3469
3470 #ifdef WANT_INTERVALS
3471 int interval_count;
3472 sigset_t signal_set;
3473 #endif /* WANT_INTERVALS */
3474
3475 xti_udp_rr_request =
3476 (struct xti_udp_rr_request_struct *)netperf_request.content.test_specific_data;
3477 xti_udp_rr_response =
3478 (struct xti_udp_rr_response_struct *)netperf_response.content.test_specific_data;
3479 xti_udp_rr_result =
3480 (struct xti_udp_rr_results_struct *)netperf_response.content.test_specific_data;
3481
3482 #ifdef WANT_HISTOGRAM
3483 time_hist = HIST_new();
3484 #endif
3485
3486 /* since we are now disconnected from the code that established the */
3487 /* control socket, and since we want to be able to use different */
3488 /* protocols and such, we are passed the name of the remote host and */
3489 /* must turn that into the test specific addressing information. */
3490
3491 bzero((char *)&server,
3492 sizeof(server));
3493
3494 /* it would seem that while HP-UX will allow an IP address (as a */
3495 /* string) in a call to gethostbyname, other, less enlightened */
3496 /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */
3497 /* order changed to check for IP address first. raj 7/96 */
3498
3499 if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
3500 /* it was not an IP address, try it as a name */
3501 if ((hp = gethostbyname(remote_host)) == NULL) {
3502 /* we have no idea what it is */
3503 fprintf(where,
3504 "establish_control: could not resolve the destination %s\n",
3505 remote_host);
3506 fflush(where);
3507 exit(1);
3508 }
3509 else {
3510 /* it was a valid remote_host */
3511 bcopy(hp->h_addr,
3512 (char *)&server.sin_addr,
3513 hp->h_length);
3514 server.sin_family = hp->h_addrtype;
3515 }
3516 }
3517 else {
3518 /* it was a valid IP address */
3519 server.sin_addr.s_addr = addr;
3520 server.sin_family = AF_INET;
3521 }
3522
3523 if ( print_headers ) {
3524 fprintf(where,"XTI UDP REQUEST/RESPONSE TEST");
3525 fprintf(where," to %s", remote_host);
3526 if (iteration_max > 1) {
3527 fprintf(where,
3528 " : +/-%3.1f%% @ %2d%% conf.",
3529 interval/0.02,
3530 confidence_level);
3531 }
3532 if (loc_sndavoid ||
3533 loc_rcvavoid ||
3534 rem_sndavoid ||
3535 rem_rcvavoid) {
3536 fprintf(where," : copy avoidance");
3537 }
3538 #ifdef WANT_HISTOGRAM
3539 fprintf(where," : histogram");
3540 #endif /* WANT_HISTOGRAM */
3541 #ifdef WANT_INTERVALS
3542 fprintf(where," : interval");
3543 #endif /* WANT_INTERVALS */
3544 #ifdef DIRTY
3545 fprintf(where," : dirty data");
3546 #endif /* DIRTY */
3547 fprintf(where,"\n");
3548 }
3549
3550 /* initialize a few counters */
3551
3552 send_ring = NULL;
3553 recv_ring = NULL;
3554 nummessages = 0;
3555 bytes_xferd = 0;
3556 times_up = 0;
3557 confidence_iteration = 1;
3558 init_stat();
3559
3560
3561 /* we have a great-big while loop which controls the number of times */
3562 /* we run a particular test. this is for the calculation of a */
3563 /* confidence interval (I really should have stayed awake during */
3564 /* probstats :). If the user did not request confidence measurement */
3565 /* (no confidence is the default) then we will only go though the */
3566 /* loop once. the confidence stuff originates from the folks at IBM */
3567
3568 while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
3569 (confidence_iteration <= iteration_min)) {
3570
3571 nummessages = 0;
3572 bytes_xferd = 0.0;
3573 times_up = 0;
3574 trans_remaining = 0;
3575
3576 /* set-up the data buffers with the requested alignment and offset */
3577
3578 if (send_width == 0) send_width = 1;
3579 if (recv_width == 0) recv_width = 1;
3580
3581 if (send_ring == NULL) {
3582 send_ring = allocate_buffer_ring(send_width,
3583 req_size,
3584 local_send_align,
3585 local_send_offset);
3586 }
3587
3588 if (recv_ring == NULL) {
3589 recv_ring = allocate_buffer_ring(recv_width,
3590 rsp_size,
3591 local_recv_align,
3592 local_recv_offset);
3593 }
3594
3595 /* since we are going to call t_rcvudata() instead of t_rcv() we */
3596 /* need to init the unitdata structure raj 8/95 */
3597
3598 memset (&recv_unitdata, 0, sizeof(recv_unitdata));
3599 recv_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
3600 recv_unitdata.addr.len = sizeof(struct sockaddr_in);
3601 recv_unitdata.addr.buf = (char *)&server;
3602
3603 recv_unitdata.opt.maxlen = 0;
3604 recv_unitdata.opt.len = 0;
3605 recv_unitdata.opt.buf = NULL;
3606
3607 recv_unitdata.udata.maxlen = rsp_size;
3608 recv_unitdata.udata.len = rsp_size;
3609 recv_unitdata.udata.buf = recv_ring->buffer_ptr;
3610
3611 /* since we are going to call t_sndudata() instead of t_snd() we */
3612 /* need to init the unitdata structure raj 8/95 */
3613
3614 memset (&send_unitdata, 0, sizeof(send_unitdata));
3615 send_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
3616 send_unitdata.addr.len = sizeof(struct sockaddr_in);
3617 send_unitdata.addr.buf = (char *)&server;
3618
3619 send_unitdata.opt.maxlen = 0;
3620 send_unitdata.opt.len = 0;
3621 send_unitdata.opt.buf = NULL;
3622
3623 send_unitdata.udata.maxlen = req_size;
3624 send_unitdata.udata.len = req_size;
3625 send_unitdata.udata.buf = send_ring->buffer_ptr;
3626
3627 /*set up the data socket */
3628 send_socket = create_xti_endpoint(loc_xti_device);
3629
3630 if (send_socket == INVALID_SOCKET){
3631 perror("netperf: send_xti_udp_rr: udp rr data socket");
3632 exit(1);
3633 }
3634
3635 if (debug) {
3636 fprintf(where,"send_xti_udp_rr: send_socket obtained...\n");
3637 }
3638
3639 /* it would seem that with XTI, there is no implicit bind */
3640 /* so we have to make a call to t_bind. this is not */
3641 /* terribly convenient, but I suppose that "standard is better */
3642 /* than better" :) raj 2/95 */
3643
3644 if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) {
3645 t_error("send_xti_tcp_stream: t_bind");
3646 exit(1);
3647 }
3648
3649 /* If the user has requested cpu utilization measurements, we must */
3650 /* calibrate the cpu(s). We will perform this task within the tests */
3651 /* themselves. If the user has specified the cpu rate, then */
3652 /* calibrate_local_cpu will return rather quickly as it will have */
3653 /* nothing to do. If local_cpu_rate is zero, then we will go through */
3654 /* all the "normal" calibration stuff and return the rate back. If */
3655 /* there is no idle counter in the kernel idle loop, the */
3656 /* local_cpu_rate will be set to -1. */
3657
3658 if (local_cpu_usage) {
3659 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
3660 }
3661
3662 /* Tell the remote end to do a listen. The server alters the socket */
3663 /* paramters on the other side at this point, hence the reason for */
3664 /* all the values being passed in the setup message. If the user did */
3665 /* not specify any of the parameters, they will be passed as 0, which */
3666 /* will indicate to the remote that no changes beyond the system's */
3667 /* default should be used. Alignment is the exception, it will */
3668 /* default to 8, which will be no alignment alterations. */
3669
3670 netperf_request.content.request_type = DO_XTI_UDP_RR;
3671 xti_udp_rr_request->recv_buf_size = rsr_size;
3672 xti_udp_rr_request->send_buf_size = rss_size;
3673 xti_udp_rr_request->recv_alignment = remote_recv_align;
3674 xti_udp_rr_request->recv_offset = remote_recv_offset;
3675 xti_udp_rr_request->send_alignment = remote_send_align;
3676 xti_udp_rr_request->send_offset = remote_send_offset;
3677 xti_udp_rr_request->request_size = req_size;
3678 xti_udp_rr_request->response_size = rsp_size;
3679 xti_udp_rr_request->measure_cpu = remote_cpu_usage;
3680 xti_udp_rr_request->cpu_rate = remote_cpu_rate;
3681 xti_udp_rr_request->so_rcvavoid = rem_rcvavoid;
3682 xti_udp_rr_request->so_sndavoid = rem_sndavoid;
3683 if (test_time) {
3684 xti_udp_rr_request->test_length = test_time;
3685 }
3686 else {
3687 xti_udp_rr_request->test_length = test_trans * -1;
3688 }
3689
3690 strcpy(xti_udp_rr_request->xti_device, rem_xti_device);
3691
3692 #ifdef __alpha
3693
3694 /* ok - even on a DEC box, strings are strings. I didn't really want */
3695 /* to ntohl the words of a string. since I don't want to teach the */
3696 /* send_ and recv_ _request and _response routines about the types, */
3697 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
3698 /* solution would be to use XDR, but I am still leary of being able */
3699 /* to find XDR libs on all platforms I want running netperf. raj */
3700 {
3701 int *charword;
3702 int *initword;
3703 int *lastword;
3704
3705 initword = (int *) xti_udp_rr_request->xti_device;
3706 lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
3707
3708 for (charword = initword;
3709 charword < lastword;
3710 charword++) {
3711
3712 *charword = ntohl(*charword);
3713 }
3714 }
3715 #endif /* __alpha */
3716
3717 if (debug > 1) {
3718 fprintf(where,"netperf: send_xti_udp_rr: requesting UDP r/r test\n");
3719 }
3720
3721 send_request();
3722
3723 /* The response from the remote will contain all of the relevant */
3724 /* socket parameters for this test type. We will put them back into */
3725 /* the variables here so they can be displayed if desired. The */
3726 /* remote will have calibrated CPU if necessary, and will have done */
3727 /* all the needed set-up we will have calibrated the cpu locally */
3728 /* before sending the request, and will grab the counter value right*/
3729 /* after the connect returns. The remote will grab the counter right*/
3730 /* after the accept call. This saves the hassle of extra messages */
3731 /* being sent for the UDP tests. */
3732
3733 recv_response();
3734
3735 if (!netperf_response.content.serv_errno) {
3736 if (debug)
3737 fprintf(where,"remote listen done.\n");
3738 rsr_size = xti_udp_rr_response->recv_buf_size;
3739 rss_size = xti_udp_rr_response->send_buf_size;
3740 remote_cpu_usage = xti_udp_rr_response->measure_cpu;
3741 remote_cpu_rate = xti_udp_rr_response->cpu_rate;
3742 /* port numbers in proper order */
3743 server.sin_port = (short)xti_udp_rr_response->data_port_number;
3744 server.sin_port = htons(server.sin_port);
3745 }
3746 else {
3747 Set_errno(netperf_response.content.serv_errno);
3748 perror("netperf: remote error");
3749
3750 exit(1);
3751 }
3752
3753 /* Data Socket set-up is finished. If there were problems, either the */
3754 /* connect would have failed, or the previous response would have */
3755 /* indicated a problem. I failed to see the value of the extra */
3756 /* message after the accept on the remote. If it failed, we'll see it */
3757 /* here. If it didn't, we might as well start pumping data. */
3758
3759 /* Set-up the test end conditions. For a request/response test, they */
3760 /* can be either time or transaction based. */
3761
3762 if (test_time) {
3763 /* The user wanted to end the test after a period of time. */
3764 times_up = 0;
3765 trans_remaining = 0;
3766 start_timer(test_time);
3767 }
3768 else {
3769 /* The tester wanted to send a number of bytes. */
3770 trans_remaining = test_bytes;
3771 times_up = 1;
3772 }
3773
3774 /* The cpu_start routine will grab the current time and possibly */
3775 /* value of the idle counter for later use in measuring cpu */
3776 /* utilization and/or service demand and thruput. */
3777
3778 cpu_start(local_cpu_usage);
3779
3780 #ifdef WANT_INTERVALS
3781 if ((interval_burst) || (demo_mode)) {
3782 /* zero means that we never pause, so we never should need the */
3783 /* interval timer, unless we are in demo_mode */
3784 start_itimer(interval_wate);
3785 }
3786 interval_count = interval_burst;
3787 /* get the signal set for the call to sigsuspend */
3788 if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
3789 fprintf(where,
3790 "send_xti_udp_rr: unable to get sigmask errno %d\n",
3791 errno);
3792 fflush(where);
3793 exit(1);
3794 }
3795 #endif /* WANT_INTERVALS */
3796
3797 /* We use an "OR" to control test execution. When the test is */
3798 /* controlled by time, the byte count check will always return */
3799 /* false. When the test is controlled by byte count, the time test */
3800 /* will always return false. When the test is finished, the whole */
3801 /* expression will go false and we will stop sending data. I think */
3802 /* I just arbitrarily decrement trans_remaining for the timed */
3803 /* test, but will not do that just yet... One other question is */
3804 /* whether or not the send buffer and the receive buffer should be */
3805 /* the same buffer. */
3806
3807 while ((!times_up) || (trans_remaining > 0)) {
3808 /* send the request */
3809 #ifdef WANT_HISTOGRAM
3810 HIST_timestamp(&time_one);
3811 #endif
3812 if((t_sndudata(send_socket,
3813 &send_unitdata)) != 0) {
3814 if (errno == EINTR) {
3815 /* We likely hit */
3816 /* test-end time. */
3817 break;
3818 }
3819 fprintf(where,
3820 "send_xti_udp_rr: t_sndudata: errno %d t_errno %d t_look 0x%.4x\n",
3821 errno,
3822 t_errno,
3823 t_look(send_socket));
3824 fflush(where);
3825 exit(1);
3826 }
3827 send_ring = send_ring->next;
3828
3829 /* receive the response. with UDP we will get it all, or nothing */
3830
3831 if((t_rcvudata(send_socket,
3832 &recv_unitdata,
3833 &flags)) != 0) {
3834 if (errno == TNODATA) {
3835 continue;
3836 }
3837 if (errno == EINTR) {
3838 /* Again, we have likely hit test-end time */
3839 break;
3840 }
3841 fprintf(where,
3842 "send_xti_udp_rr: t_rcvudata: errno %d t_errno %d t_look 0x%x\n",
3843 errno,
3844 t_errno,
3845 t_look(send_socket));
3846 fprintf(where,
3847 "recv_unitdata.udata.buf %x\n",recv_unitdata.udata.buf);
3848 fprintf(where,
3849 "recv_unitdata.udata.maxlen %x\n",recv_unitdata.udata.maxlen);
3850 fprintf(where,
3851 "recv_unitdata.udata.len %x\n",recv_unitdata.udata.len);
3852 fprintf(where,
3853 "recv_unitdata.addr.buf %x\n",recv_unitdata.addr.buf);
3854 fprintf(where,
3855 "recv_unitdata.addr.maxlen %x\n",recv_unitdata.addr.maxlen);
3856 fprintf(where,
3857 "recv_unitdata.addr.len %x\n",recv_unitdata.addr.len);
3858 fflush(where);
3859 exit(1);
3860 }
3861 recv_ring = recv_ring->next;
3862
3863 #ifdef WANT_HISTOGRAM
3864 HIST_timestamp(&time_two);
3865 HIST_add(time_hist,delta_micro(&time_one,&time_two));
3866
3867 /* at this point, we may wish to sleep for some period of */
3868 /* time, so we see how long that last transaction just took, */
3869 /* and sleep for the difference of that and the interval. We */
3870 /* will not sleep if the time would be less than a */
3871 /* millisecond. */
3872 #endif
3873 #ifdef WANT_INTERVALS
3874 if (demo_mode) {
3875 units_this_tick += 1;
3876 }
3877 /* in this case, the interval count is the count-down couter */
3878 /* to decide to sleep for a little bit */
3879 if ((interval_burst) && (--interval_count == 0)) {
3880 /* call sigsuspend and wait for the interval timer to get us */
3881 /* out */
3882 if (debug) {
3883 fprintf(where,"about to suspend\n");
3884 fflush(where);
3885 }
3886 if (sigsuspend(&signal_set) == EFAULT) {
3887 fprintf(where,
3888 "send_xti_udp_rr: fault with signal set!\n");
3889 fflush(where);
3890 exit(1);
3891 }
3892 interval_count = interval_burst;
3893 }
3894 #endif /* WANT_INTERVALS */
3895
3896 nummessages++;
3897 if (trans_remaining) {
3898 trans_remaining--;
3899 }
3900
3901 if (debug > 3) {
3902 if ((nummessages % 100) == 0) {
3903 fprintf(where,"Transaction %d completed\n",nummessages);
3904 fflush(where);
3905 }
3906 }
3907
3908 }
3909
3910 /* this call will always give us the elapsed time for the test, and */
3911 /* will also store-away the necessaries for cpu utilization */
3912
3913 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being */
3914 /* measured? how long */
3915 /* did we really run? */
3916
3917 /* Get the statistics from the remote end. The remote will have */
3918 /* calculated service demand and all those interesting things. If */
3919 /* it wasn't supposed to care, it will return obvious values. */
3920
3921 recv_response();
3922 if (!netperf_response.content.serv_errno) {
3923 if (debug)
3924 fprintf(where,"remote results obtained\n");
3925 }
3926 else {
3927 Set_errno(netperf_response.content.serv_errno);
3928 perror("netperf: remote error");
3929
3930 exit(1);
3931 }
3932
3933 /* We now calculate what our thruput was for the test. In the */
3934 /* future, we may want to include a calculation of the thruput */
3935 /* measured by the remote, but it should be the case that for a */
3936 /* UDP rr test, that the two numbers should be *very* close... */
3937 /* We calculate bytes_sent regardless of the way the test length */
3938 /* was controlled. */
3939
3940 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
3941 thruput = nummessages / elapsed_time;
3942
3943 if (local_cpu_usage || remote_cpu_usage) {
3944
3945 /* We must now do a little math for service demand and cpu */
3946 /* utilization for the system(s) Of course, some of the */
3947 /* information might be bogus because there was no idle counter */
3948 /* in the kernel(s). We need to make a note of this for the */
3949 /* user's benefit by placing a code for the metod used in the */
3950 /* test banner */
3951
3952 if (local_cpu_usage) {
3953 local_cpu_utilization = calc_cpu_util(0.0);
3954
3955 /* since calc_service demand is doing ms/Kunit we will */
3956 /* multiply the number of transaction by 1024 to get */
3957 /* "good" numbers */
3958
3959 local_service_demand = calc_service_demand((double) nummessages*1024,
3960 0.0,
3961 0.0,
3962 0);
3963 }
3964 else {
3965 local_cpu_utilization = -1.0;
3966 local_service_demand = -1.0;
3967 }
3968
3969 if (remote_cpu_usage) {
3970 remote_cpu_utilization = xti_udp_rr_result->cpu_util;
3971
3972 /* since calc_service demand is doing ms/Kunit we will */
3973 /* multiply the number of transaction by 1024 to get */
3974 /* "good" numbers */
3975
3976 remote_service_demand = calc_service_demand((double) nummessages*1024,
3977 0.0,
3978 remote_cpu_utilization,
3979 xti_udp_rr_result->num_cpus);
3980 }
3981 else {
3982 remote_cpu_utilization = -1.0;
3983 remote_service_demand = -1.0;
3984 }
3985 }
3986 else {
3987 /* we were not measuring cpu, for the confidence stuff, we */
3988 /* should make it -1.0 */
3989 local_cpu_utilization = -1.0;
3990 local_service_demand = -1.0;
3991 remote_cpu_utilization = -1.0;
3992 remote_service_demand = -1.0;
3993 }
3994
3995 /* at this point, we want to calculate the confidence information. */
3996 /* if debugging is on, calculate_confidence will print-out the */
3997 /* parameters we pass it */
3998
3999 calculate_confidence(confidence_iteration,
4000 elapsed_time,
4001 thruput,
4002 local_cpu_utilization,
4003 remote_cpu_utilization,
4004 local_service_demand,
4005 remote_service_demand);
4006
4007
4008 confidence_iteration++;
4009
4010 /* we are done with the socket */
4011 t_close(send_socket);
4012 }
4013
4014 /* at this point, we have made all the iterations we are going to */
4015 /* make. */
4016 retrieve_confident_values(&elapsed_time,
4017 &thruput,
4018 &local_cpu_utilization,
4019 &remote_cpu_utilization,
4020 &local_service_demand,
4021 &remote_service_demand);
4022
4023 /* We are now ready to print all the information. If the user */
4024 /* has specified zero-level verbosity, we will just print the */
4025 /* local service demand, or the remote service demand. If the */
4026 /* user has requested verbosity level 1, he will get the basic */
4027 /* "streamperf" numbers. If the user has specified a verbosity */
4028 /* of greater than 1, we will display a veritable plethora of */
4029 /* background information from outside of this block as it it */
4030 /* not cpu_measurement specific... */
4031
4032 if (confidence < 0) {
4033 /* we did not hit confidence, but were we asked to look for it? */
4034 if (iteration_max > 1) {
4035 display_confidence();
4036 }
4037 }
4038
4039 if (local_cpu_usage || remote_cpu_usage) {
4040 local_cpu_method = format_cpu_method(cpu_method);
4041 remote_cpu_method = format_cpu_method(xti_udp_rr_result->cpu_method);
4042
4043 switch (verbosity) {
4044 case 0:
4045 if (local_cpu_usage) {
4046 fprintf(where,
4047 cpu_fmt_0,
4048 local_service_demand,
4049 local_cpu_method);
4050 }
4051 else {
4052 fprintf(where,
4053 cpu_fmt_0,
4054 remote_service_demand,
4055 remote_cpu_method);
4056 }
4057 break;
4058 case 1:
4059 case 2:
4060 if (print_headers) {
4061 fprintf(where,
4062 cpu_title,
4063 local_cpu_method,
4064 remote_cpu_method);
4065 }
4066
4067 fprintf(where,
4068 cpu_fmt_1_line_1, /* the format string */
4069 lss_size, /* local sendbuf size */
4070 lsr_size,
4071 req_size, /* how large were the requests */
4072 rsp_size, /* guess */
4073 elapsed_time, /* how long was the test */
4074 nummessages/elapsed_time,
4075 local_cpu_utilization, /* local cpu */
4076 remote_cpu_utilization, /* remote cpu */
4077 local_service_demand, /* local service demand */
4078 remote_service_demand); /* remote service demand */
4079 fprintf(where,
4080 cpu_fmt_1_line_2,
4081 rss_size,
4082 rsr_size);
4083 break;
4084 }
4085 }
4086 else {
4087 /* The tester did not wish to measure service demand. */
4088 switch (verbosity) {
4089 case 0:
4090 fprintf(where,
4091 tput_fmt_0,
4092 nummessages/elapsed_time);
4093 break;
4094 case 1:
4095 case 2:
4096 if (print_headers) {
4097 fprintf(where,tput_title,format_units());
4098 }
4099
4100 fprintf(where,
4101 tput_fmt_1_line_1, /* the format string */
4102 lss_size,
4103 lsr_size,
4104 req_size, /* how large were the requests */
4105 rsp_size, /* how large were the responses */
4106 elapsed_time, /* how long did it take */
4107 nummessages/elapsed_time);
4108 fprintf(where,
4109 tput_fmt_1_line_2,
4110 rss_size, /* remote recvbuf size */
4111 rsr_size);
4112
4113 break;
4114 }
4115 }
4116 fflush(where);
4117
4118 /* it would be a good thing to include information about some of the */
4119 /* other parameters that may have been set for this test, but at the */
4120 /* moment, I do not wish to figure-out all the formatting, so I will */
4121 /* just put this comment here to help remind me that it is something */
4122 /* that should be done at a later time. */
4123
4124 /* how to handle the verbose information in the presence of */
4125 /* confidence intervals is yet to be determined... raj 11/94 */
4126
4127 if (verbosity > 1) {
4128 /* The user wanted to know it all, so we will give it to him. */
4129 /* This information will include as much as we can find about */
4130 /* UDP statistics, the alignments of the sends and receives */
4131 /* and all that sort of rot... */
4132
4133 #ifdef WANT_HISTOGRAM
4134 fprintf(where,"\nHistogram of request/reponse times.\n");
4135 fflush(where);
4136 HIST_report(time_hist);
4137 #endif /* WANT_HISTOGRAM */
4138 }
4139 }
4140
4141 /* this routine implements the receive side (netserver) of a XTI_UDP_RR */
4142 /* test. */
4143 void
recv_xti_udp_rr()4144 recv_xti_udp_rr()
4145 {
4146
4147 struct ring_elt *recv_ring;
4148 struct ring_elt *send_ring;
4149
4150 struct t_bind bind_req, bind_resp;
4151 struct t_unitdata send_unitdata;
4152 struct t_unitdata recv_unitdata;
4153 int flags = 0;
4154
4155 struct sockaddr_in myaddr_in, peeraddr_in;
4156 SOCKET s_data;
4157 int addrlen;
4158 int trans_received;
4159 int trans_remaining;
4160 float elapsed_time;
4161
4162 struct xti_udp_rr_request_struct *xti_udp_rr_request;
4163 struct xti_udp_rr_response_struct *xti_udp_rr_response;
4164 struct xti_udp_rr_results_struct *xti_udp_rr_results;
4165
4166
4167 /* a little variable initialization */
4168 memset (&myaddr_in, 0, sizeof(struct sockaddr_in));
4169 myaddr_in.sin_family = AF_INET;
4170 myaddr_in.sin_addr.s_addr = INADDR_ANY;
4171 myaddr_in.sin_port = 0;
4172 memset (&peeraddr_in, 0, sizeof(struct sockaddr_in));
4173
4174 /* and some not so paranoid :) */
4175 xti_udp_rr_request =
4176 (struct xti_udp_rr_request_struct *)netperf_request.content.test_specific_data;
4177 xti_udp_rr_response =
4178 (struct xti_udp_rr_response_struct *)netperf_response.content.test_specific_data;
4179 xti_udp_rr_results =
4180 (struct xti_udp_rr_results_struct *)netperf_response.content.test_specific_data;
4181
4182 if (debug) {
4183 fprintf(where,"netserver: recv_xti_udp_rr: entered...\n");
4184 fflush(where);
4185 }
4186
4187 /* We want to set-up the listen socket with all the desired */
4188 /* parameters and then let the initiator know that all is ready. If */
4189 /* socket size defaults are to be used, then the initiator will have */
4190 /* sent us 0's. If the socket sizes cannot be changed, then we will */
4191 /* send-back what they are. If that information cannot be determined, */
4192 /* then we send-back -1's for the sizes. If things go wrong for any */
4193 /* reason, we will drop back ten yards and punt. */
4194
4195 /* If anything goes wrong, we want the remote to know about it. It */
4196 /* would be best if the error that the remote reports to the user is */
4197 /* the actual error we encountered, rather than some bogus unexpected */
4198 /* response type message. */
4199
4200 if (debug) {
4201 fprintf(where,"recv_xti_udp_rr: setting the response type...\n");
4202 fflush(where);
4203 }
4204
4205 netperf_response.content.response_type = XTI_UDP_RR_RESPONSE;
4206
4207 if (debug) {
4208 fprintf(where,"recv_xti_udp_rr: the response type is set...\n");
4209 fflush(where);
4210 }
4211
4212 /* We now alter the message_ptr variables to be at the desired */
4213 /* alignments with the desired offsets. */
4214
4215 if (debug) {
4216 fprintf(where,"recv_xti_udp_rr: requested recv alignment of %d offset %d\n",
4217 xti_udp_rr_request->recv_alignment,
4218 xti_udp_rr_request->recv_offset);
4219 fprintf(where,"recv_xti_udp_rr: requested send alignment of %d offset %d\n",
4220 xti_udp_rr_request->send_alignment,
4221 xti_udp_rr_request->send_offset);
4222 fflush(where);
4223 }
4224
4225 if (send_width == 0) send_width = 1;
4226 if (recv_width == 0) recv_width = 1;
4227
4228 recv_ring = allocate_buffer_ring(recv_width,
4229 xti_udp_rr_request->request_size,
4230 xti_udp_rr_request->recv_alignment,
4231 xti_udp_rr_request->recv_offset);
4232
4233 send_ring = allocate_buffer_ring(send_width,
4234 xti_udp_rr_request->response_size,
4235 xti_udp_rr_request->send_alignment,
4236 xti_udp_rr_request->send_offset);
4237
4238 if (debug) {
4239 fprintf(where,"recv_xti_udp_rr: receive alignment and offset set...\n");
4240 fflush(where);
4241 }
4242
4243 /* create_xti_endpoint expects to find some things in the global */
4244 /* variables, so set the globals based on the values in the request. */
4245 /* once the socket has been created, we will set the response values */
4246 /* based on the updated value of those globals. raj 7/94 */
4247 lss_size = xti_udp_rr_request->send_buf_size;
4248 lsr_size = xti_udp_rr_request->recv_buf_size;
4249 loc_rcvavoid = xti_udp_rr_request->so_rcvavoid;
4250 loc_sndavoid = xti_udp_rr_request->so_sndavoid;
4251
4252 #ifdef __alpha
4253
4254 /* ok - even on a DEC box, strings are strings. I din't really want */
4255 /* to ntohl the words of a string. since I don't want to teach the */
4256 /* send_ and recv_ _request and _response routines about the types, */
4257 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
4258 /* solution would be to use XDR, but I am still leary of being able */
4259 /* to find XDR libs on all platforms I want running netperf. raj */
4260 {
4261 int *charword;
4262 int *initword;
4263 int *lastword;
4264
4265 initword = (int *) xti_udp_rr_request->xti_device;
4266 lastword = initword + ((xti_udp_rr_request->dev_name_len + 3) / 4);
4267
4268 for (charword = initword;
4269 charword < lastword;
4270 charword++) {
4271
4272 *charword = htonl(*charword);
4273 }
4274 }
4275
4276 #endif /* __alpha */
4277
4278 s_data = create_xti_endpoint(xti_udp_rr_request->xti_device);
4279
4280 if (s_data == INVALID_SOCKET) {
4281 netperf_response.content.serv_errno = errno;
4282 send_response();
4283 exit(1);
4284 }
4285
4286 if (debug) {
4287 fprintf(where,"recv_xti_udp_rr: endpoint created...\n");
4288 fflush(where);
4289 }
4290
4291 /* Let's get an address assigned to this socket so we can tell the */
4292 /* initiator how to reach the data socket. There may be a desire to */
4293 /* nail this socket to a specific IP address in a multi-homed, */
4294 /* multi-connection situation, but for now, we'll ignore the issue */
4295 /* and concentrate on single connection testing. */
4296
4297 bind_req.addr.maxlen = sizeof(struct sockaddr_in);
4298 bind_req.addr.len = sizeof(struct sockaddr_in);
4299 bind_req.addr.buf = (char *)&myaddr_in;
4300 bind_req.qlen = 1;
4301
4302 bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
4303 bind_resp.addr.len = sizeof(struct sockaddr_in);
4304 bind_resp.addr.buf = (char *)&myaddr_in;
4305 bind_resp.qlen = 1;
4306
4307 if (t_bind(s_data,
4308 &bind_req,
4309 &bind_resp) == SOCKET_ERROR) {
4310 if (debug) {
4311 fprintf(where,
4312 "recv_xti_udp_rr: t_bind failed, t_errno %d errno %d\n",
4313 t_errno,
4314 errno);
4315 fflush(where);
4316 }
4317
4318 netperf_response.content.serv_errno = t_errno;
4319 send_response();
4320
4321 exit(1);
4322 }
4323
4324 if (debug) {
4325 fprintf(where,
4326 "recv_xti_udp_rr: endpoint bound to port %d...\n",
4327 ntohs(myaddr_in.sin_port));
4328 fflush(where);
4329 }
4330
4331 xti_udp_rr_response->test_length =
4332 xti_udp_rr_request->test_length;
4333
4334
4335 /* Now myaddr_in contains the port and the internet address this is */
4336 /* returned to the sender also implicitly telling the sender that the */
4337 /* socket buffer sizing has been done. */
4338
4339 xti_udp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
4340 netperf_response.content.serv_errno = 0;
4341
4342 fprintf(where,"recv port number %d\n",myaddr_in.sin_port);
4343 fflush(where);
4344
4345 /* But wait, there's more. If the initiator wanted cpu measurements, */
4346 /* then we must call the calibrate routine, which will return the max */
4347 /* rate back to the initiator. If the CPU was not to be measured, or */
4348 /* something went wrong with the calibration, we will return a 0.0 to */
4349 /* the initiator. */
4350
4351 xti_udp_rr_response->cpu_rate = 0.0; /* assume no cpu */
4352 xti_udp_rr_response->measure_cpu = 0;
4353 if (xti_udp_rr_request->measure_cpu) {
4354 xti_udp_rr_response->measure_cpu = 1;
4355 xti_udp_rr_response->cpu_rate =
4356 calibrate_local_cpu(xti_udp_rr_request->cpu_rate);
4357 }
4358
4359 /* before we send the response back to the initiator, pull some of */
4360 /* the socket parms from the globals */
4361 xti_udp_rr_response->send_buf_size = lss_size;
4362 xti_udp_rr_response->recv_buf_size = lsr_size;
4363 xti_udp_rr_response->so_rcvavoid = loc_rcvavoid;
4364 xti_udp_rr_response->so_sndavoid = loc_sndavoid;
4365
4366 /* since we are going to call t_rcvudata() instead of t_rcv() we */
4367 /* need to init the unitdata structure raj 3/95 */
4368
4369 memset (&recv_unitdata, 0, sizeof(recv_unitdata));
4370 recv_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
4371 recv_unitdata.addr.len = sizeof(struct sockaddr_in);
4372 recv_unitdata.addr.buf = (char *)&peeraddr_in;
4373
4374 recv_unitdata.opt.maxlen = 0;
4375 recv_unitdata.opt.len = 0;
4376 recv_unitdata.opt.buf = NULL;
4377
4378 recv_unitdata.udata.maxlen = xti_udp_rr_request->request_size;
4379 recv_unitdata.udata.len = xti_udp_rr_request->request_size;
4380 recv_unitdata.udata.buf = recv_ring->buffer_ptr;
4381
4382 /* since we are going to call t_sndudata() instead of t_snd() we */
4383 /* need to init the unitdata structure raj 8/95 */
4384
4385 memset (&send_unitdata, 0, sizeof(send_unitdata));
4386 send_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
4387 send_unitdata.addr.len = sizeof(struct sockaddr_in);
4388 send_unitdata.addr.buf = (char *)&peeraddr_in;
4389
4390 send_unitdata.opt.maxlen = 0;
4391 send_unitdata.opt.len = 0;
4392 send_unitdata.opt.buf = NULL;
4393
4394 send_unitdata.udata.maxlen = xti_udp_rr_request->response_size;
4395 send_unitdata.udata.len = xti_udp_rr_request->response_size;
4396 send_unitdata.udata.buf = send_ring->buffer_ptr;
4397
4398 send_response();
4399
4400
4401 /* Now it's time to start receiving data on the connection. We will */
4402 /* first grab the apropriate counters and then start grabbing. */
4403
4404 cpu_start(xti_udp_rr_request->measure_cpu);
4405
4406 if (xti_udp_rr_request->test_length > 0) {
4407 times_up = 0;
4408 trans_remaining = 0;
4409 start_timer(xti_udp_rr_request->test_length + PAD_TIME);
4410 }
4411 else {
4412 times_up = 1;
4413 trans_remaining = xti_udp_rr_request->test_length * -1;
4414 }
4415
4416 addrlen = sizeof(peeraddr_in);
4417 bzero((char *)&peeraddr_in, addrlen);
4418
4419 trans_received = 0;
4420
4421 while ((!times_up) || (trans_remaining > 0)) {
4422
4423 /* receive the request from the other side */
4424 if (t_rcvudata(s_data,
4425 &recv_unitdata,
4426 &flags) != 0) {
4427 if (errno == TNODATA) {
4428 continue;
4429 }
4430 if (errno == EINTR) {
4431 /* we must have hit the end of test time. */
4432 break;
4433 }
4434 if (debug) {
4435 fprintf(where,
4436 "recv_xti_udp_rr: t_rcvudata failed, t_errno %d errno %d\n",
4437 t_errno,
4438 errno);
4439 fflush(where);
4440 }
4441 netperf_response.content.serv_errno = t_errno;
4442 send_response();
4443 exit(1);
4444 }
4445 recv_ring = recv_ring->next;
4446 recv_unitdata.udata.buf = recv_ring->buffer_ptr;
4447
4448 /* Now, send the response to the remote */
4449 if (t_sndudata(s_data,
4450 &send_unitdata) != 0) {
4451 if (errno == EINTR) {
4452 /* we have hit end of test time. */
4453 break;
4454 }
4455 if (debug) {
4456 fprintf(where,
4457 "recv_xti_udp_rr: t_sndudata failed, t_errno %d errno %d\n",
4458 t_errno,
4459 errno);
4460 fflush(where);
4461 }
4462 netperf_response.content.serv_errno = errno;
4463 send_response();
4464 exit(1);
4465 }
4466 send_ring = send_ring->next;
4467 send_unitdata.udata.buf = send_ring->buffer_ptr;
4468
4469 trans_received++;
4470 if (trans_remaining) {
4471 trans_remaining--;
4472 }
4473
4474 if (debug) {
4475 fprintf(where,
4476 "recv_xti_udp_rr: Transaction %d complete.\n",
4477 trans_received);
4478 fflush(where);
4479 }
4480
4481 }
4482
4483
4484 /* The loop now exits due to timeout or transaction count being */
4485 /* reached */
4486
4487 cpu_stop(xti_udp_rr_request->measure_cpu,&elapsed_time);
4488
4489 if (times_up) {
4490 /* we ended the test by time, which was at least 2 seconds */
4491 /* longer than we wanted to run. so, we want to subtract */
4492 /* PAD_TIME from the elapsed_time. */
4493 elapsed_time -= PAD_TIME;
4494 }
4495 /* send the results to the sender */
4496
4497 if (debug) {
4498 fprintf(where,
4499 "recv_xti_udp_rr: got %d transactions\n",
4500 trans_received);
4501 fflush(where);
4502 }
4503
4504 xti_udp_rr_results->bytes_received = (trans_received *
4505 (xti_udp_rr_request->request_size +
4506 xti_udp_rr_request->response_size));
4507 xti_udp_rr_results->trans_received = trans_received;
4508 xti_udp_rr_results->elapsed_time = elapsed_time;
4509 xti_udp_rr_results->cpu_method = cpu_method;
4510 if (xti_udp_rr_request->measure_cpu) {
4511 xti_udp_rr_results->cpu_util = calc_cpu_util(elapsed_time);
4512 }
4513
4514 if (debug) {
4515 fprintf(where,
4516 "recv_xti_udp_rr: test complete, sending results.\n");
4517 fflush(where);
4518 }
4519
4520 send_response();
4521
4522 /* we are done with the socket now */
4523 close(s_data);
4524
4525 }
4526
4527 /* this routine implements the receive (netserver) side of a XTI_TCP_RR */
4528 /* test */
4529 void
recv_xti_tcp_rr()4530 recv_xti_tcp_rr()
4531 {
4532
4533 struct ring_elt *send_ring;
4534 struct ring_elt *recv_ring;
4535
4536 struct sockaddr_in myaddr_in, peeraddr_in;
4537 struct t_bind bind_req, bind_resp;
4538 struct t_call call_req;
4539
4540 SOCKET s_listen,s_data;
4541 int addrlen;
4542 char *temp_message_ptr;
4543 int trans_received;
4544 int trans_remaining;
4545 int bytes_sent;
4546 int request_bytes_recvd;
4547 int request_bytes_remaining;
4548 int timed_out = 0;
4549 float elapsed_time;
4550
4551 struct xti_tcp_rr_request_struct *xti_tcp_rr_request;
4552 struct xti_tcp_rr_response_struct *xti_tcp_rr_response;
4553 struct xti_tcp_rr_results_struct *xti_tcp_rr_results;
4554
4555 xti_tcp_rr_request =
4556 (struct xti_tcp_rr_request_struct *)netperf_request.content.test_specific_data;
4557 xti_tcp_rr_response =
4558 (struct xti_tcp_rr_response_struct *)netperf_response.content.test_specific_data;
4559 xti_tcp_rr_results =
4560 (struct xti_tcp_rr_results_struct *)netperf_response.content.test_specific_data;
4561
4562 if (debug) {
4563 fprintf(where,"netserver: recv_xti_tcp_rr: entered...\n");
4564 fflush(where);
4565 }
4566
4567 /* We want to set-up the listen socket with all the desired */
4568 /* parameters and then let the initiator know that all is ready. If */
4569 /* socket size defaults are to be used, then the initiator will have */
4570 /* sent us 0's. If the socket sizes cannot be changed, then we will */
4571 /* send-back what they are. If that information cannot be determined, */
4572 /* then we send-back -1's for the sizes. If things go wrong for any */
4573 /* reason, we will drop back ten yards and punt. */
4574
4575 /* If anything goes wrong, we want the remote to know about it. It */
4576 /* would be best if the error that the remote reports to the user is */
4577 /* the actual error we encountered, rather than some bogus unexpected */
4578 /* response type message. */
4579
4580 if (debug) {
4581 fprintf(where,"recv_xti_tcp_rr: setting the response type...\n");
4582 fflush(where);
4583 }
4584
4585 netperf_response.content.response_type = XTI_TCP_RR_RESPONSE;
4586
4587 if (debug) {
4588 fprintf(where,"recv_xti_tcp_rr: the response type is set...\n");
4589 fflush(where);
4590 }
4591
4592 /* allocate the recv and send rings with the requested alignments */
4593 /* and offsets. raj 7/94 */
4594 if (debug) {
4595 fprintf(where,"recv_xti_tcp_rr: requested recv alignment of %d offset %d\n",
4596 xti_tcp_rr_request->recv_alignment,
4597 xti_tcp_rr_request->recv_offset);
4598 fprintf(where,"recv_xti_tcp_rr: requested send alignment of %d offset %d\n",
4599 xti_tcp_rr_request->send_alignment,
4600 xti_tcp_rr_request->send_offset);
4601 fflush(where);
4602 }
4603
4604 /* at some point, these need to come to us from the remote system */
4605 if (send_width == 0) send_width = 1;
4606 if (recv_width == 0) recv_width = 1;
4607
4608 send_ring = allocate_buffer_ring(send_width,
4609 xti_tcp_rr_request->response_size,
4610 xti_tcp_rr_request->send_alignment,
4611 xti_tcp_rr_request->send_offset);
4612
4613 recv_ring = allocate_buffer_ring(recv_width,
4614 xti_tcp_rr_request->request_size,
4615 xti_tcp_rr_request->recv_alignment,
4616 xti_tcp_rr_request->recv_offset);
4617
4618
4619 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
4620 /* can put in OUR values !-) At some point, we may want to nail this */
4621 /* socket to a particular network-level address, but for now, */
4622 /* INADDR_ANY should be just fine. */
4623
4624 bzero((char *)&myaddr_in,
4625 sizeof(myaddr_in));
4626 myaddr_in.sin_family = AF_INET;
4627 myaddr_in.sin_addr.s_addr = INADDR_ANY;
4628 myaddr_in.sin_port = 0;
4629
4630 /* Grab a socket to listen on, and then listen on it. */
4631
4632 if (debug) {
4633 fprintf(where,"recv_xti_tcp_rr: grabbing a socket...\n");
4634 fflush(where);
4635 }
4636
4637 /* create_xti_endpoint expects to find some things in the global */
4638 /* variables, so set the globals based on the values in the request. */
4639 /* once the socket has been created, we will set the response values */
4640 /* based on the updated value of those globals. raj 7/94 */
4641 lss_size = xti_tcp_rr_request->send_buf_size;
4642 lsr_size = xti_tcp_rr_request->recv_buf_size;
4643 loc_nodelay = xti_tcp_rr_request->no_delay;
4644 loc_rcvavoid = xti_tcp_rr_request->so_rcvavoid;
4645 loc_sndavoid = xti_tcp_rr_request->so_sndavoid;
4646
4647 #ifdef __alpha
4648
4649 /* ok - even on a DEC box, strings are strings. I din't really want */
4650 /* to ntohl the words of a string. since I don't want to teach the */
4651 /* send_ and recv_ _request and _response routines about the types, */
4652 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
4653 /* solution would be to use XDR, but I am still leary of being able */
4654 /* to find XDR libs on all platforms I want running netperf. raj */
4655 {
4656 int *charword;
4657 int *initword;
4658 int *lastword;
4659
4660 initword = (int *) xti_tcp_rr_request->xti_device;
4661 lastword = initword + ((xti_tcp_rr_request->dev_name_len + 3) / 4);
4662
4663 for (charword = initword;
4664 charword < lastword;
4665 charword++) {
4666
4667 *charword = htonl(*charword);
4668 }
4669 }
4670
4671 #endif /* __alpha */
4672
4673 s_listen = create_xti_endpoint(xti_tcp_rr_request->xti_device);
4674
4675 if (s_listen == INVALID_SOCKET) {
4676 netperf_response.content.serv_errno = errno;
4677 send_response();
4678
4679 exit(1);
4680 }
4681
4682 /* Let's get an address assigned to this socket so we can tell the */
4683 /* initiator how to reach the data socket. There may be a desire to */
4684 /* nail this socket to a specific IP address in a multi-homed, */
4685 /* multi-connection situation, but for now, we'll ignore the issue */
4686 /* and concentrate on single connection testing. */
4687
4688 bind_req.addr.maxlen = sizeof(struct sockaddr_in);
4689 bind_req.addr.len = sizeof(struct sockaddr_in);
4690 bind_req.addr.buf = (char *)&myaddr_in;
4691 bind_req.qlen = 1;
4692
4693 bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
4694 bind_resp.addr.len = sizeof(struct sockaddr_in);
4695 bind_resp.addr.buf = (char *)&myaddr_in;
4696 bind_resp.qlen = 1;
4697
4698 if (t_bind(s_listen,
4699 &bind_req,
4700 &bind_resp) == SOCKET_ERROR) {
4701 netperf_response.content.serv_errno = t_errno;
4702 close(s_listen);
4703 send_response();
4704
4705 exit(1);
4706 }
4707
4708 if (debug) {
4709 fprintf(where,
4710 "recv_xti_tcp_rr: t_bind complete port %d\n",
4711 ntohs(myaddr_in.sin_port));
4712 fflush(where);
4713 }
4714
4715 /* Now myaddr_in contains the port and the internet address this is */
4716 /* returned to the sender also implicitly telling the sender that the */
4717 /* socket buffer sizing has been done. */
4718
4719 xti_tcp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
4720 netperf_response.content.serv_errno = 0;
4721
4722 /* But wait, there's more. If the initiator wanted cpu measurements, */
4723 /* then we must call the calibrate routine, which will return the max */
4724 /* rate back to the initiator. If the CPU was not to be measured, or */
4725 /* something went wrong with the calibration, we will return a 0.0 to */
4726 /* the initiator. */
4727
4728 xti_tcp_rr_response->cpu_rate = 0.0; /* assume no cpu */
4729 xti_tcp_rr_response->measure_cpu = 0;
4730
4731 if (xti_tcp_rr_request->measure_cpu) {
4732 xti_tcp_rr_response->measure_cpu = 1;
4733 xti_tcp_rr_response->cpu_rate = calibrate_local_cpu(xti_tcp_rr_request->cpu_rate);
4734 }
4735
4736
4737 /* before we send the response back to the initiator, pull some of */
4738 /* the socket parms from the globals */
4739 xti_tcp_rr_response->send_buf_size = lss_size;
4740 xti_tcp_rr_response->recv_buf_size = lsr_size;
4741 xti_tcp_rr_response->no_delay = loc_nodelay;
4742 xti_tcp_rr_response->so_rcvavoid = loc_rcvavoid;
4743 xti_tcp_rr_response->so_sndavoid = loc_sndavoid;
4744 xti_tcp_rr_response->test_length = xti_tcp_rr_request->test_length;
4745 send_response();
4746
4747 /* Now, let's set-up the socket to listen for connections. for xti, */
4748 /* the t_listen call is blocking by default - this is different */
4749 /* semantics from BSD - probably has to do with being able to reject */
4750 /* a call before an accept */
4751 call_req.addr.maxlen = sizeof(struct sockaddr_in);
4752 call_req.addr.len = sizeof(struct sockaddr_in);
4753 call_req.addr.buf = (char *)&peeraddr_in;
4754 call_req.opt.maxlen = 0;
4755 call_req.opt.len = 0;
4756 call_req.opt.buf = NULL;
4757 call_req.udata.maxlen= 0;
4758 call_req.udata.len = 0;
4759 call_req.udata.buf = 0;
4760
4761 if (t_listen(s_listen, &call_req) == -1) {
4762 fprintf(where,
4763 "recv_xti_tcp_rr: t_listen: errno %d t_errno %d\n",
4764 errno,
4765 t_errno);
4766 fflush(where);
4767 netperf_response.content.serv_errno = t_errno;
4768 close(s_listen);
4769 send_response();
4770 exit(1);
4771 }
4772
4773 if (debug) {
4774 fprintf(where,
4775 "recv_xti_tcp_rr: t_listen complete t_look 0x%.4x\n",
4776 t_look(s_listen));
4777 fflush(where);
4778 }
4779
4780 /* now just rubber stamp the thing. we want to use the same fd? so */
4781 /* we will just equate s_data with s_listen. this seems a little */
4782 /* hokey to me, but then I'm a BSD biggot still. raj 2/95 */
4783 s_data = s_listen;
4784 if (t_accept(s_listen,
4785 s_data,
4786 &call_req) == -1) {
4787 fprintf(where,
4788 "recv_xti_tcp_rr: t_accept: errno %d t_errno %d\n",
4789 errno,
4790 t_errno);
4791 fflush(where);
4792 close(s_listen);
4793 exit(1);
4794 }
4795
4796 if (debug) {
4797 fprintf(where,
4798 "recv_xti_tcp_rr: t_accept complete t_look 0x%.4x",
4799 t_look(s_data));
4800 fprintf(where,
4801 " remote is %s port %d\n",
4802 inet_ntoa(*(struct in_addr *)&peeraddr_in.sin_addr),
4803 ntohs(peeraddr_in.sin_port));
4804 fflush(where);
4805 }
4806
4807 /* Now it's time to start receiving data on the connection. We will */
4808 /* first grab the apropriate counters and then start grabbing. */
4809
4810 cpu_start(xti_tcp_rr_request->measure_cpu);
4811
4812 if (xti_tcp_rr_request->test_length > 0) {
4813 times_up = 0;
4814 trans_remaining = 0;
4815 start_timer(xti_tcp_rr_request->test_length + PAD_TIME);
4816 }
4817 else {
4818 times_up = 1;
4819 trans_remaining = xti_tcp_rr_request->test_length * -1;
4820 }
4821
4822 trans_received = 0;
4823
4824 while ((!times_up) || (trans_remaining > 0)) {
4825 temp_message_ptr = recv_ring->buffer_ptr;
4826 request_bytes_remaining = xti_tcp_rr_request->request_size;
4827 while(request_bytes_remaining > 0) {
4828 if((request_bytes_recvd=t_rcv(s_data,
4829 temp_message_ptr,
4830 request_bytes_remaining,
4831 &xti_flags)) == SOCKET_ERROR) {
4832 if (errno == EINTR) {
4833 /* the timer popped */
4834 timed_out = 1;
4835 break;
4836 }
4837 fprintf(where,
4838 "recv_xti_tcp_rr: t_rcv: errno %d t_errno %d len %d",
4839 errno,
4840 t_errno,
4841 request_bytes_recvd);
4842 fprintf(where,
4843 " t_look 0x%x",
4844 t_look(s_data));
4845 fflush(where);
4846 netperf_response.content.serv_errno = t_errno;
4847 send_response();
4848 exit(1);
4849 }
4850 else {
4851 request_bytes_remaining -= request_bytes_recvd;
4852 temp_message_ptr += request_bytes_recvd;
4853 }
4854 }
4855
4856 recv_ring = recv_ring->next;
4857
4858 if (timed_out) {
4859 /* we hit the end of the test based on time - lets */
4860 /* bail out of here now... */
4861 if (debug) {
4862 fprintf(where,"yo5\n");
4863 fflush(where);
4864 }
4865 break;
4866 }
4867
4868 /* Now, send the response to the remote */
4869 if((bytes_sent=t_snd(s_data,
4870 send_ring->buffer_ptr,
4871 xti_tcp_rr_request->response_size,
4872 0)) == -1) {
4873 if (errno == EINTR) {
4874 /* the test timer has popped */
4875 timed_out = 1;
4876 if (debug) {
4877 fprintf(where,"yo6\n");
4878 fflush(where);
4879 }
4880 break;
4881 }
4882 fprintf(where,
4883 "recv_xti_tcp_rr: t_rcv: errno %d t_errno %d len %d",
4884 errno,
4885 t_errno,
4886 bytes_sent);
4887 fprintf(where,
4888 " t_look 0x%x",
4889 t_look(s_data));
4890 fflush(where);
4891 netperf_response.content.serv_errno = t_errno;
4892 send_response();
4893 exit(1);
4894 }
4895
4896 send_ring = send_ring->next;
4897
4898 trans_received++;
4899 if (trans_remaining) {
4900 trans_remaining--;
4901 }
4902 }
4903
4904
4905 /* The loop now exits due to timeout or transaction count being */
4906 /* reached */
4907
4908 cpu_stop(xti_tcp_rr_request->measure_cpu,&elapsed_time);
4909
4910 stop_timer(); /* this is probably unnecessary, but it shouldn't hurt */
4911
4912 if (timed_out) {
4913 /* we ended the test by time, which was at least 2 seconds */
4914 /* longer than we wanted to run. so, we want to subtract */
4915 /* PAD_TIME from the elapsed_time. */
4916 elapsed_time -= PAD_TIME;
4917 }
4918
4919 /* send the results to the sender */
4920
4921 if (debug) {
4922 fprintf(where,
4923 "recv_xti_tcp_rr: got %d transactions\n",
4924 trans_received);
4925 fflush(where);
4926 }
4927
4928 xti_tcp_rr_results->bytes_received = (trans_received *
4929 (xti_tcp_rr_request->request_size +
4930 xti_tcp_rr_request->response_size));
4931 xti_tcp_rr_results->trans_received = trans_received;
4932 xti_tcp_rr_results->elapsed_time = elapsed_time;
4933 xti_tcp_rr_results->cpu_method = cpu_method;
4934 if (xti_tcp_rr_request->measure_cpu) {
4935 xti_tcp_rr_results->cpu_util = calc_cpu_util(elapsed_time);
4936 }
4937
4938 if (debug) {
4939 fprintf(where,
4940 "recv_xti_tcp_rr: test complete, sending results.\n");
4941 fflush(where);
4942 }
4943
4944 /* we are done with the socket, free it */
4945 t_close(s_data);
4946
4947 send_response();
4948
4949 }
4950
4951
4952
4953 /* this test is intended to test the performance of establishing a */
4954 /* connection, exchanging a request/response pair, and repeating. it */
4955 /* is expected that this would be a good starting-point for */
4956 /* comparision of T/TCP with classic TCP for transactional workloads. */
4957 /* it will also look (can look) much like the communication pattern */
4958 /* of http for www access. */
4959
4960 void
send_xti_tcp_conn_rr(char remote_host[])4961 send_xti_tcp_conn_rr(char remote_host[])
4962 {
4963
4964 char *tput_title = "\
4965 Local /Remote\n\
4966 Socket Size Request Resp. Elapsed Trans.\n\
4967 Send Recv Size Size Time Rate \n\
4968 bytes Bytes bytes bytes secs. per sec \n\n";
4969
4970 char *tput_fmt_0 =
4971 "%7.2f\n";
4972
4973 char *tput_fmt_1_line_1 = "\
4974 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
4975 char *tput_fmt_1_line_2 = "\
4976 %-6d %-6d\n";
4977
4978 char *cpu_title = "\
4979 Local /Remote\n\
4980 Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
4981 Send Recv Size Size Time Rate local remote local remote\n\
4982 bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n";
4983
4984 char *cpu_fmt_0 =
4985 "%6.3f\n";
4986
4987 char *cpu_fmt_1_line_1 = "\
4988 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
4989
4990 char *cpu_fmt_1_line_2 = "\
4991 %-6d %-6d\n";
4992
4993 char *ksink_fmt = "\
4994 Alignment Offset\n\
4995 Local Remote Local Remote\n\
4996 Send Recv Send Recv\n\
4997 %5d %5d %5d %5d\n";
4998
4999
5000 int one = 1;
5001 int timed_out = 0;
5002 float elapsed_time;
5003
5004 int len;
5005 struct ring_elt *send_ring;
5006 struct ring_elt *recv_ring;
5007 char *temp_message_ptr;
5008 int nummessages;
5009 SOCKET send_socket;
5010 int trans_remaining;
5011 double bytes_xferd;
5012 int sock_opt_len = sizeof(int);
5013 int rsp_bytes_left;
5014 int rsp_bytes_recvd;
5015
5016 float local_cpu_utilization;
5017 float local_service_demand;
5018 float remote_cpu_utilization;
5019 float remote_service_demand;
5020 double thruput;
5021
5022 struct hostent *hp;
5023 struct sockaddr_in server;
5024 struct sockaddr_in *myaddr;
5025 unsigned int addr;
5026 int myport;
5027
5028 struct xti_tcp_conn_rr_request_struct *xti_tcp_conn_rr_request;
5029 struct xti_tcp_conn_rr_response_struct *xti_tcp_conn_rr_response;
5030 struct xti_tcp_conn_rr_results_struct *xti_tcp_conn_rr_result;
5031
5032 xti_tcp_conn_rr_request =
5033 (struct xti_tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data;
5034 xti_tcp_conn_rr_response =
5035 (struct xti_tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data;
5036 xti_tcp_conn_rr_result =
5037 (struct xti_tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data;
5038
5039 /* since we are now disconnected from the code that established the */
5040 /* control socket, and since we want to be able to use different */
5041 /* protocols and such, we are passed the name of the remote host and */
5042 /* must turn that into the test specific addressing information. */
5043
5044 myaddr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
5045 if (myaddr == NULL) {
5046 printf("malloc(%d) failed!\n", sizeof(struct sockaddr_in));
5047 exit(1);
5048 }
5049
5050 bzero((char *)&server,
5051 sizeof(server));
5052 bzero((char *)myaddr,
5053 sizeof(struct sockaddr_in));
5054 myaddr->sin_family = AF_INET;
5055
5056 /* it would seem that while HP-UX will allow an IP address (as a */
5057 /* string) in a call to gethostbyname, other, less enlightened */
5058 /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */
5059 /* order changed to check for IP address first. raj 7/96 */
5060
5061 if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
5062 /* it was not an IP address, try it as a name */
5063 if ((hp = gethostbyname(remote_host)) == NULL) {
5064 /* we have no idea what it is */
5065 fprintf(where,
5066 "establish_control: could not resolve the destination %s\n",
5067 remote_host);
5068 fflush(where);
5069 exit(1);
5070 }
5071 else {
5072 /* it was a valid remote_host */
5073 bcopy(hp->h_addr,
5074 (char *)&server.sin_addr,
5075 hp->h_length);
5076 server.sin_family = hp->h_addrtype;
5077 }
5078 }
5079 else {
5080 /* it was a valid IP address */
5081 server.sin_addr.s_addr = addr;
5082 server.sin_family = AF_INET;
5083 }
5084
5085 if ( print_headers ) {
5086 fprintf(where,"TCP Connect/Request/Response Test\n");
5087 if (local_cpu_usage || remote_cpu_usage)
5088 fprintf(where,cpu_title,format_units());
5089 else
5090 fprintf(where,tput_title,format_units());
5091 }
5092
5093 /* initialize a few counters */
5094
5095 nummessages = 0;
5096 bytes_xferd = 0.0;
5097 times_up = 0;
5098
5099 /* set-up the data buffers with the requested alignment and offset */
5100 if (send_width == 0) send_width = 1;
5101 if (recv_width == 0) recv_width = 1;
5102
5103 send_ring = allocate_buffer_ring(send_width,
5104 req_size,
5105 local_send_align,
5106 local_send_offset);
5107
5108 recv_ring = allocate_buffer_ring(recv_width,
5109 rsp_size,
5110 local_recv_align,
5111 local_recv_offset);
5112
5113
5114 if (debug) {
5115 fprintf(where,"send_xti_tcp_conn_rr: send_socket obtained...\n");
5116 }
5117
5118 /* If the user has requested cpu utilization measurements, we must */
5119 /* calibrate the cpu(s). We will perform this task within the tests */
5120 /* themselves. If the user has specified the cpu rate, then */
5121 /* calibrate_local_cpu will return rather quickly as it will have */
5122 /* nothing to do. If local_cpu_rate is zero, then we will go through */
5123 /* all the "normal" calibration stuff and return the rate back.*/
5124
5125 if (local_cpu_usage) {
5126 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
5127 }
5128
5129 /* Tell the remote end to do a listen. The server alters the socket */
5130 /* paramters on the other side at this point, hence the reason for */
5131 /* all the values being passed in the setup message. If the user did */
5132 /* not specify any of the parameters, they will be passed as 0, which */
5133 /* will indicate to the remote that no changes beyond the system's */
5134 /* default should be used. Alignment is the exception, it will */
5135 /* default to 8, which will be no alignment alterations. */
5136
5137 netperf_request.content.request_type = DO_XTI_TCP_CRR;
5138 xti_tcp_conn_rr_request->recv_buf_size = rsr_size;
5139 xti_tcp_conn_rr_request->send_buf_size = rss_size;
5140 xti_tcp_conn_rr_request->recv_alignment = remote_recv_align;
5141 xti_tcp_conn_rr_request->recv_offset = remote_recv_offset;
5142 xti_tcp_conn_rr_request->send_alignment = remote_send_align;
5143 xti_tcp_conn_rr_request->send_offset = remote_send_offset;
5144 xti_tcp_conn_rr_request->request_size = req_size;
5145 xti_tcp_conn_rr_request->response_size = rsp_size;
5146 xti_tcp_conn_rr_request->no_delay = rem_nodelay;
5147 xti_tcp_conn_rr_request->measure_cpu = remote_cpu_usage;
5148 xti_tcp_conn_rr_request->cpu_rate = remote_cpu_rate;
5149 xti_tcp_conn_rr_request->so_rcvavoid = rem_rcvavoid;
5150 xti_tcp_conn_rr_request->so_sndavoid = rem_sndavoid;
5151 if (test_time) {
5152 xti_tcp_conn_rr_request->test_length = test_time;
5153 }
5154 else {
5155 xti_tcp_conn_rr_request->test_length = test_trans * -1;
5156 }
5157
5158 if (debug > 1) {
5159 fprintf(where,"netperf: send_xti_tcp_conn_rr: requesting TCP crr test\n");
5160 }
5161
5162 send_request();
5163
5164 /* The response from the remote will contain all of the relevant */
5165 /* socket parameters for this test type. We will put them back into */
5166 /* the variables here so they can be displayed if desired. The */
5167 /* remote will have calibrated CPU if necessary, and will have done */
5168 /* all the needed set-up we will have calibrated the cpu locally */
5169 /* before sending the request, and will grab the counter value right */
5170 /* after the connect returns. The remote will grab the counter right */
5171 /* after the accept call. This saves the hassle of extra messages */
5172 /* being sent for the TCP tests. */
5173
5174 recv_response();
5175
5176 if (!netperf_response.content.serv_errno) {
5177 rsr_size = xti_tcp_conn_rr_response->recv_buf_size;
5178 rss_size = xti_tcp_conn_rr_response->send_buf_size;
5179 rem_nodelay = xti_tcp_conn_rr_response->no_delay;
5180 remote_cpu_usage= xti_tcp_conn_rr_response->measure_cpu;
5181 remote_cpu_rate = xti_tcp_conn_rr_response->cpu_rate;
5182 /* make sure that port numbers are in network order */
5183 server.sin_port = (short)xti_tcp_conn_rr_response->data_port_number;
5184 server.sin_port = htons(server.sin_port);
5185 if (debug) {
5186 fprintf(where,"remote listen done.\n");
5187 fprintf(where,"remote port is %d\n",ntohs(server.sin_port));
5188 fflush(where);
5189 }
5190 }
5191 else {
5192 Set_errno(netperf_response.content.serv_errno);
5193 perror("netperf: remote error");
5194
5195 exit(1);
5196 }
5197
5198 /* Set-up the test end conditions. For a request/response test, they */
5199 /* can be either time or transaction based. */
5200
5201 if (test_time) {
5202 /* The user wanted to end the test after a period of time. */
5203 times_up = 0;
5204 trans_remaining = 0;
5205 start_timer(test_time);
5206 }
5207 else {
5208 /* The tester wanted to send a number of bytes. */
5209 trans_remaining = test_bytes;
5210 times_up = 1;
5211 }
5212
5213 /* The cpu_start routine will grab the current time and possibly */
5214 /* value of the idle counter for later use in measuring cpu */
5215 /* utilization and/or service demand and thruput. */
5216
5217 cpu_start(local_cpu_usage);
5218
5219 /* We use an "OR" to control test execution. When the test is */
5220 /* controlled by time, the byte count check will always return false. */
5221 /* When the test is controlled by byte count, the time test will */
5222 /* always return false. When the test is finished, the whole */
5223 /* expression will go false and we will stop sending data. I think I */
5224 /* just arbitrarily decrement trans_remaining for the timed test, but */
5225 /* will not do that just yet... One other question is whether or not */
5226 /* the send buffer and the receive buffer should be the same buffer. */
5227
5228 /* just for grins, start the port numbers at 65530. this should */
5229 /* quickly flush-out those broken implementations of TCP which treat */
5230 /* the port number as a signed 16 bit quantity. */
5231 myport = 65530;
5232 myaddr->sin_port = htons(myport);
5233
5234 while ((!times_up) || (trans_remaining > 0)) {
5235
5236 /* set up the data socket */
5237 send_socket = create_xti_endpoint(loc_xti_device);
5238
5239 if (send_socket == INVALID_SOCKET) {
5240 perror("netperf: send_xti_tcp_conn_rr: tcp stream data socket");
5241 exit(1);
5242 }
5243
5244 /* we set SO_REUSEADDR on the premis that no unreserved port */
5245 /* number on the local system is going to be already connected to */
5246 /* the remote netserver's port number. we might still have a */
5247 /* problem if there is a port in the unconnected state. In that */
5248 /* case, we might want to throw-in a goto to the point where we */
5249 /* increment the port number by one and try again. of course, this */
5250 /* could lead to a big load of spinning. one thing that I might */
5251 /* try later is to have the remote actually allocate a couple of */
5252 /* port numbers and cycle through those as well. depends on if we */
5253 /* can get through all the unreserved port numbers in less than */
5254 /* the length of the TIME_WAIT state raj 8/94 */
5255 one = 1;
5256 if(setsockopt(send_socket, SOL_SOCKET, SO_REUSEADDR,
5257 (char *)&one, sock_opt_len) == SOCKET_ERROR) {
5258 perror("netperf: send_xti_tcp_conn_rr: so_reuseaddr");
5259 exit(1);
5260 }
5261
5262 /* we want to bind our socket to a particular port number. */
5263 if (bind(send_socket,
5264 (struct sockaddr *)myaddr,
5265 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
5266 printf("netperf: send_xti_tcp_conn_rr: tried to bind to port %d\n",
5267 ntohs(myaddr->sin_port));
5268 perror("netperf: send_xti_tcp_conn_rr: bind");
5269 exit(1);
5270 }
5271
5272 /* Connect up to the remote port on the data socket */
5273 if (connect(send_socket,
5274 (struct sockaddr *)&server,
5275 sizeof(server)) == INVALID_SOCKET){
5276 if (errno == EINTR) {
5277 /* we hit the end of a */
5278 /* timed test. */
5279 timed_out = 1;
5280 break;
5281 }
5282 perror("netperf: data socket connect failed");
5283 printf("\tattempted to connect on socket %d to port %d",
5284 send_socket,
5285 ntohs(server.sin_port));
5286 printf(" from port %d \n",ntohs(myaddr->sin_port));
5287 exit(1);
5288 }
5289
5290 /* send the request */
5291 if((len=send(send_socket,
5292 send_ring->buffer_ptr,
5293 req_size,
5294 0)) != req_size) {
5295 if (errno == EINTR) {
5296 /* we hit the end of a */
5297 /* timed test. */
5298 timed_out = 1;
5299 break;
5300 }
5301 perror("send_xti_tcp_conn_rr: data send error");
5302 exit(1);
5303 }
5304 send_ring = send_ring->next;
5305
5306 /* receive the response */
5307 rsp_bytes_left = rsp_size;
5308 temp_message_ptr = recv_ring->buffer_ptr;
5309 while(rsp_bytes_left > 0) {
5310 if((rsp_bytes_recvd=recv(send_socket,
5311 temp_message_ptr,
5312 rsp_bytes_left,
5313 0)) == SOCKET_ERROR) {
5314 if (errno == EINTR) {
5315 /* We hit the end of a timed test. */
5316 timed_out = 1;
5317 break;
5318 }
5319 perror("send_xti_tcp_conn_rr: data recv error");
5320 exit(1);
5321 }
5322 rsp_bytes_left -= rsp_bytes_recvd;
5323 temp_message_ptr += rsp_bytes_recvd;
5324 }
5325 recv_ring = recv_ring->next;
5326
5327 if (timed_out) {
5328 /* we may have been in a nested while loop - we need */
5329 /* another call to break. */
5330 break;
5331 }
5332
5333 close(send_socket);
5334
5335 nummessages++;
5336 if (trans_remaining) {
5337 trans_remaining--;
5338 }
5339
5340 if (debug > 3) {
5341 fprintf(where,
5342 "Transaction %d completed on local port %d\n",
5343 nummessages,
5344 ntohs(myaddr->sin_port));
5345 fflush(where);
5346 }
5347
5348 newport:
5349 /* pick a new port number */
5350 myport = ntohs(myaddr->sin_port);
5351 myport++;
5352 /* we do not want to use the port number that the server is */
5353 /* sitting at - this would cause us to fail in a loopback test */
5354
5355 if (myport == ntohs(server.sin_port)) myport++;
5356
5357 /* wrap the port number when we get to 65535. NOTE, some broken */
5358 /* TCP's might treat the port number as a signed 16 bit quantity. */
5359 /* we aren't interested in testing such broekn implementations :) */
5360 /* raj 8/94 */
5361 if (myport == 65535) {
5362 myport = 5000;
5363 }
5364 myaddr->sin_port = htons(myport);
5365
5366 if (debug) {
5367 if ((myport % 1000) == 0) {
5368 printf("port %d\n",myport);
5369 }
5370 }
5371
5372 }
5373
5374 /* this call will always give us the elapsed time for the test, and */
5375 /* will also store-away the necessaries for cpu utilization */
5376
5377 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */
5378 /* how long did we really run? */
5379
5380 /* Get the statistics from the remote end. The remote will have */
5381 /* calculated service demand and all those interesting things. If it */
5382 /* wasn't supposed to care, it will return obvious values. */
5383
5384 recv_response();
5385 if (!netperf_response.content.serv_errno) {
5386 if (debug)
5387 fprintf(where,"remote results obtained\n");
5388 }
5389 else {
5390 Set_errno(netperf_response.content.serv_errno);
5391 perror("netperf: remote error");
5392
5393 exit(1);
5394 }
5395
5396 /* We now calculate what our thruput was for the test. In the future, */
5397 /* we may want to include a calculation of the thruput measured by */
5398 /* the remote, but it should be the case that for a TCP stream test, */
5399 /* that the two numbers should be *very* close... We calculate */
5400 /* bytes_sent regardless of the way the test length was controlled. */
5401 /* If it was time, we needed to, and if it was by bytes, the user may */
5402 /* have specified a number of bytes that wasn't a multiple of the */
5403 /* send_size, so we really didn't send what he asked for ;-) We use */
5404 /* Kbytes/s as the units of thruput for a TCP stream test, where K = */
5405 /* 1024. A future enhancement *might* be to choose from a couple of */
5406 /* unit selections. */
5407
5408 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
5409 thruput = calc_thruput(bytes_xferd);
5410
5411 if (local_cpu_usage || remote_cpu_usage) {
5412 /* We must now do a little math for service demand and cpu */
5413 /* utilization for the system(s) */
5414 /* Of course, some of the information might be bogus because */
5415 /* there was no idle counter in the kernel(s). We need to make */
5416 /* a note of this for the user's benefit...*/
5417 if (local_cpu_usage) {
5418 if (local_cpu_rate == 0.0) {
5419 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n");
5420 fprintf(where,"Local CPU usage numbers based on process information only!\n");
5421 fflush(where);
5422 }
5423 local_cpu_utilization = calc_cpu_util(0.0);
5424 /* since calc_service demand is doing ms/Kunit we will */
5425 /* multiply the number of transaction by 1024 to get */
5426 /* "good" numbers */
5427 local_service_demand = calc_service_demand((double) nummessages*1024,
5428 0.0,
5429 0.0,
5430 0);
5431 }
5432 else {
5433 local_cpu_utilization = -1.0;
5434 local_service_demand = -1.0;
5435 }
5436
5437 if (remote_cpu_usage) {
5438 if (remote_cpu_rate == 0.0) {
5439 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n");
5440 fprintf(where,"Remote CPU usage numbers based on process information only!\n");
5441 fflush(where);
5442 }
5443 remote_cpu_utilization = xti_tcp_conn_rr_result->cpu_util;
5444 /* since calc_service demand is doing ms/Kunit we will */
5445 /* multiply the number of transaction by 1024 to get */
5446 /* "good" numbers */
5447 remote_service_demand = calc_service_demand((double) nummessages*1024,
5448 0.0,
5449 remote_cpu_utilization,
5450 xti_tcp_conn_rr_result->num_cpus);
5451 }
5452 else {
5453 remote_cpu_utilization = -1.0;
5454 remote_service_demand = -1.0;
5455 }
5456
5457 /* We are now ready to print all the information. If the user */
5458 /* has specified zero-level verbosity, we will just print the */
5459 /* local service demand, or the remote service demand. If the */
5460 /* user has requested verbosity level 1, he will get the basic */
5461 /* "streamperf" numbers. If the user has specified a verbosity */
5462 /* of greater than 1, we will display a veritable plethora of */
5463 /* background information from outside of this block as it it */
5464 /* not cpu_measurement specific... */
5465
5466 switch (verbosity) {
5467 case 0:
5468 if (local_cpu_usage) {
5469 fprintf(where,
5470 cpu_fmt_0,
5471 local_service_demand);
5472 }
5473 else {
5474 fprintf(where,
5475 cpu_fmt_0,
5476 remote_service_demand);
5477 }
5478 break;
5479 case 1:
5480 fprintf(where,
5481 cpu_fmt_1_line_1, /* the format string */
5482 lss_size, /* local sendbuf size */
5483 lsr_size,
5484 req_size, /* how large were the requests */
5485 rsp_size, /* guess */
5486 elapsed_time, /* how long was the test */
5487 nummessages/elapsed_time,
5488 local_cpu_utilization, /* local cpu */
5489 remote_cpu_utilization, /* remote cpu */
5490 local_service_demand, /* local service demand */
5491 remote_service_demand); /* remote service demand */
5492 fprintf(where,
5493 cpu_fmt_1_line_2,
5494 rss_size,
5495 rsr_size);
5496 break;
5497 }
5498 }
5499 else {
5500 /* The tester did not wish to measure service demand. */
5501 switch (verbosity) {
5502 case 0:
5503 fprintf(where,
5504 tput_fmt_0,
5505 nummessages/elapsed_time);
5506 break;
5507 case 1:
5508 fprintf(where,
5509 tput_fmt_1_line_1, /* the format string */
5510 lss_size,
5511 lsr_size,
5512 req_size, /* how large were the requests */
5513 rsp_size, /* how large were the responses */
5514 elapsed_time, /* how long did it take */
5515 nummessages/elapsed_time);
5516 fprintf(where,
5517 tput_fmt_1_line_2,
5518 rss_size, /* remote recvbuf size */
5519 rsr_size);
5520
5521 break;
5522 }
5523 }
5524
5525 /* it would be a good thing to include information about some of the */
5526 /* other parameters that may have been set for this test, but at the */
5527 /* moment, I do not wish to figure-out all the formatting, so I will */
5528 /* just put this comment here to help remind me that it is something */
5529 /* that should be done at a later time. */
5530
5531 if (verbosity > 1) {
5532 /* The user wanted to know it all, so we will give it to him. */
5533 /* This information will include as much as we can find about */
5534 /* TCP statistics, the alignments of the sends and receives */
5535 /* and all that sort of rot... */
5536
5537 fprintf(where,
5538 ksink_fmt);
5539 }
5540
5541 }
5542
5543
5544 void
recv_xti_tcp_conn_rr()5545 recv_xti_tcp_conn_rr()
5546 {
5547
5548 char *message;
5549 struct sockaddr_in myaddr_in,
5550 peeraddr_in;
5551 SOCKET s_listen,s_data;
5552 int addrlen;
5553 char *recv_message_ptr;
5554 char *send_message_ptr;
5555 char *temp_message_ptr;
5556 int trans_received;
5557 int trans_remaining;
5558 int bytes_sent;
5559 int request_bytes_recvd;
5560 int request_bytes_remaining;
5561 int timed_out = 0;
5562 float elapsed_time;
5563
5564 struct xti_tcp_conn_rr_request_struct *xti_tcp_conn_rr_request;
5565 struct xti_tcp_conn_rr_response_struct *xti_tcp_conn_rr_response;
5566 struct xti_tcp_conn_rr_results_struct *xti_tcp_conn_rr_results;
5567
5568 xti_tcp_conn_rr_request =
5569 (struct xti_tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data;
5570 xti_tcp_conn_rr_response =
5571 (struct xti_tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data;
5572 xti_tcp_conn_rr_results =
5573 (struct xti_tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data;
5574
5575 if (debug) {
5576 fprintf(where,"netserver: recv_xti_tcp_conn_rr: entered...\n");
5577 fflush(where);
5578 }
5579
5580 /* We want to set-up the listen socket with all the desired */
5581 /* parameters and then let the initiator know that all is ready. If */
5582 /* socket size defaults are to be used, then the initiator will have */
5583 /* sent us 0's. If the socket sizes cannot be changed, then we will */
5584 /* send-back what they are. If that information cannot be determined, */
5585 /* then we send-back -1's for the sizes. If things go wrong for any */
5586 /* reason, we will drop back ten yards and punt. */
5587
5588 /* If anything goes wrong, we want the remote to know about it. It */
5589 /* would be best if the error that the remote reports to the user is */
5590 /* the actual error we encountered, rather than some bogus unexpected */
5591 /* response type message. */
5592
5593 if (debug) {
5594 fprintf(where,"recv_xti_tcp_conn_rr: setting the response type...\n");
5595 fflush(where);
5596 }
5597
5598 netperf_response.content.response_type = XTI_TCP_CRR_RESPONSE;
5599
5600 if (debug) {
5601 fprintf(where,"recv_xti_tcp_conn_rr: the response type is set...\n");
5602 fflush(where);
5603 }
5604
5605 /* set-up the data buffer with the requested alignment and offset */
5606 message = (char *)malloc(DATABUFFERLEN);
5607 if (message == NULL) {
5608 printf("malloc(%d) failed!\n", DATABUFFERLEN);
5609 exit(1);
5610 }
5611
5612 /* We now alter the message_ptr variables to be at the desired */
5613 /* alignments with the desired offsets. */
5614
5615 if (debug) {
5616 fprintf(where,
5617 "recv_xti_tcp_conn_rr: requested recv alignment of %d offset %d\n",
5618 xti_tcp_conn_rr_request->recv_alignment,
5619 xti_tcp_conn_rr_request->recv_offset);
5620 fprintf(where,
5621 "recv_xti_tcp_conn_rr: requested send alignment of %d offset %d\n",
5622 xti_tcp_conn_rr_request->send_alignment,
5623 xti_tcp_conn_rr_request->send_offset);
5624 fflush(where);
5625 }
5626
5627 recv_message_ptr = ALIGN_BUFFER(message, xti_tcp_conn_rr_request->recv_alignment, xti_tcp_conn_rr_request->recv_offset);
5628
5629 send_message_ptr = ALIGN_BUFFER(message, xti_tcp_conn_rr_request->send_alignment, xti_tcp_conn_rr_request->send_offset);
5630
5631 if (debug) {
5632 fprintf(where,"recv_xti_tcp_conn_rr: receive alignment and offset set...\n");
5633 fflush(where);
5634 }
5635
5636 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
5637 /* can put in OUR values !-) At some point, we may want to nail this */
5638 /* socket to a particular network-level address, but for now, */
5639 /* INADDR_ANY should be just fine. */
5640
5641 bzero((char *)&myaddr_in,
5642 sizeof(myaddr_in));
5643 myaddr_in.sin_family = AF_INET;
5644 myaddr_in.sin_addr.s_addr = INADDR_ANY;
5645 myaddr_in.sin_port = 0;
5646
5647 /* Grab a socket to listen on, and then listen on it. */
5648
5649 if (debug) {
5650 fprintf(where,"recv_xti_tcp_conn_rr: grabbing a socket...\n");
5651 fflush(where);
5652 }
5653
5654 /* create_xti_endpoint expects to find some things in the global */
5655 /* variables, so set the globals based on the values in the request. */
5656 /* once the socket has been created, we will set the response values */
5657 /* based on the updated value of those globals. raj 7/94 */
5658 lss_size = xti_tcp_conn_rr_request->send_buf_size;
5659 lsr_size = xti_tcp_conn_rr_request->recv_buf_size;
5660 loc_nodelay = xti_tcp_conn_rr_request->no_delay;
5661 loc_rcvavoid = xti_tcp_conn_rr_request->so_rcvavoid;
5662 loc_sndavoid = xti_tcp_conn_rr_request->so_sndavoid;
5663
5664 s_listen = create_xti_endpoint(loc_xti_device);
5665
5666 if (s_listen == INVALID_SOCKET) {
5667 netperf_response.content.serv_errno = errno;
5668 send_response();
5669 if (debug) {
5670 fprintf(where,"could not create data socket\n");
5671 fflush(where);
5672 }
5673 exit(1);
5674 }
5675
5676 /* Let's get an address assigned to this socket so we can tell the */
5677 /* initiator how to reach the data socket. There may be a desire to */
5678 /* nail this socket to a specific IP address in a multi-homed, */
5679 /* multi-connection situation, but for now, we'll ignore the issue */
5680 /* and concentrate on single connection testing. */
5681
5682 if (bind(s_listen,
5683 (struct sockaddr *)&myaddr_in,
5684 sizeof(myaddr_in)) == SOCKET_ERROR) {
5685 netperf_response.content.serv_errno = errno;
5686 close(s_listen);
5687 send_response();
5688 if (debug) {
5689 fprintf(where,"could not bind\n");
5690 fflush(where);
5691 }
5692 exit(1);
5693 }
5694
5695 /* Now, let's set-up the socket to listen for connections */
5696 if (listen(s_listen, 5) == SOCKET_ERROR) {
5697 netperf_response.content.serv_errno = errno;
5698 close(s_listen);
5699 send_response();
5700 if (debug) {
5701 fprintf(where,"could not listen\n");
5702 fflush(where);
5703 }
5704 exit(1);
5705 }
5706
5707 /* now get the port number assigned by the system */
5708 addrlen = sizeof(myaddr_in);
5709 if (getsockname(s_listen,
5710 (struct sockaddr *)&myaddr_in,
5711 &addrlen) == SOCKET_ERROR){
5712 netperf_response.content.serv_errno = errno;
5713 close(s_listen);
5714 send_response();
5715 if (debug) {
5716 fprintf(where,"could not geetsockname\n");
5717 fflush(where);
5718 }
5719 exit(1);
5720 }
5721
5722 /* Now myaddr_in contains the port and the internet address this is */
5723 /* returned to the sender also implicitly telling the sender that the */
5724 /* socket buffer sizing has been done. */
5725
5726 xti_tcp_conn_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
5727 if (debug) {
5728 fprintf(where,"telling the remote to call me at %d\n",
5729 xti_tcp_conn_rr_response->data_port_number);
5730 fflush(where);
5731 }
5732 netperf_response.content.serv_errno = 0;
5733
5734 /* But wait, there's more. If the initiator wanted cpu measurements, */
5735 /* then we must call the calibrate routine, which will return the max */
5736 /* rate back to the initiator. If the CPU was not to be measured, or */
5737 /* something went wrong with the calibration, we will return a 0.0 to */
5738 /* the initiator. */
5739
5740 xti_tcp_conn_rr_response->cpu_rate = 0.0; /* assume no cpu */
5741 if (xti_tcp_conn_rr_request->measure_cpu) {
5742 xti_tcp_conn_rr_response->measure_cpu = 1;
5743 xti_tcp_conn_rr_response->cpu_rate =
5744 calibrate_local_cpu(xti_tcp_conn_rr_request->cpu_rate);
5745 }
5746
5747
5748
5749 /* before we send the response back to the initiator, pull some of */
5750 /* the socket parms from the globals */
5751 xti_tcp_conn_rr_response->send_buf_size = lss_size;
5752 xti_tcp_conn_rr_response->recv_buf_size = lsr_size;
5753 xti_tcp_conn_rr_response->no_delay = loc_nodelay;
5754 xti_tcp_conn_rr_response->so_rcvavoid = loc_rcvavoid;
5755 xti_tcp_conn_rr_response->so_sndavoid = loc_sndavoid;
5756
5757 send_response();
5758
5759 addrlen = sizeof(peeraddr_in);
5760
5761 /* Now it's time to start receiving data on the connection. We will */
5762 /* first grab the apropriate counters and then start grabbing. */
5763
5764 cpu_start(xti_tcp_conn_rr_request->measure_cpu);
5765
5766 /* The loop will exit when the sender does a shutdown, which will */
5767 /* return a length of zero */
5768
5769 if (xti_tcp_conn_rr_request->test_length > 0) {
5770 times_up = 0;
5771 trans_remaining = 0;
5772 start_timer(xti_tcp_conn_rr_request->test_length + PAD_TIME);
5773 }
5774 else {
5775 times_up = 1;
5776 trans_remaining = xti_tcp_conn_rr_request->test_length * -1;
5777 }
5778
5779 trans_received = 0;
5780
5781 while ((!times_up) || (trans_remaining > 0)) {
5782
5783 /* accept a connection from the remote */
5784 if ((s_data=accept(s_listen,
5785 (struct sockaddr *)&peeraddr_in,
5786 &addrlen)) == INVALID_SOCKET) {
5787 if (errno == EINTR) {
5788 /* the timer popped */
5789 timed_out = 1;
5790 break;
5791 }
5792 fprintf(where,"recv_xti_tcp_conn_rr: accept: errno = %d\n",errno);
5793 fflush(where);
5794 close(s_listen);
5795
5796 exit(1);
5797 }
5798
5799 if (debug) {
5800 fprintf(where,"recv_xti_tcp_conn_rr: accepted data connection.\n");
5801 fflush(where);
5802 }
5803
5804 temp_message_ptr = recv_message_ptr;
5805 request_bytes_remaining = xti_tcp_conn_rr_request->request_size;
5806
5807 /* receive the request from the other side */
5808 while(request_bytes_remaining > 0) {
5809 if((request_bytes_recvd=recv(s_data,
5810 temp_message_ptr,
5811 request_bytes_remaining,
5812 0)) == SOCKET_ERROR) {
5813 if (errno == EINTR) {
5814 /* the timer popped */
5815 timed_out = 1;
5816 break;
5817 }
5818 netperf_response.content.serv_errno = errno;
5819 send_response();
5820 exit(1);
5821 }
5822 else {
5823 request_bytes_remaining -= request_bytes_recvd;
5824 temp_message_ptr += request_bytes_recvd;
5825 }
5826 }
5827
5828 if (timed_out) {
5829 /* we hit the end of the test based on time - lets */
5830 /* bail out of here now... */
5831 fprintf(where,"yo5\n");
5832 fflush(where);
5833 break;
5834 }
5835
5836 /* Now, send the response to the remote */
5837 if((bytes_sent=send(s_data,
5838 send_message_ptr,
5839 xti_tcp_conn_rr_request->response_size,
5840 0)) == SOCKET_ERROR) {
5841 if (errno == EINTR) {
5842 /* the test timer has popped */
5843 timed_out = 1;
5844 fprintf(where,"yo6\n");
5845 fflush(where);
5846 break;
5847 }
5848 netperf_response.content.serv_errno = 99;
5849 send_response();
5850 exit(1);
5851 }
5852
5853 trans_received++;
5854 if (trans_remaining) {
5855 trans_remaining--;
5856 }
5857
5858 if (debug) {
5859 fprintf(where,
5860 "recv_xti_tcp_conn_rr: Transaction %d complete\n",
5861 trans_received);
5862 fflush(where);
5863 }
5864
5865 /* close the connection */
5866 close(s_data);
5867
5868 }
5869
5870
5871 /* The loop now exits due to timeout or transaction count being */
5872 /* reached */
5873
5874 cpu_stop(xti_tcp_conn_rr_request->measure_cpu,&elapsed_time);
5875
5876 if (timed_out) {
5877 /* we ended the test by time, which was at least 2 seconds */
5878 /* longer than we wanted to run. so, we want to subtract */
5879 /* PAD_TIME from the elapsed_time. */
5880 elapsed_time -= PAD_TIME;
5881 }
5882 /* send the results to the sender */
5883
5884 if (debug) {
5885 fprintf(where,
5886 "recv_xti_tcp_conn_rr: got %d transactions\n",
5887 trans_received);
5888 fflush(where);
5889 }
5890
5891 xti_tcp_conn_rr_results->bytes_received = (trans_received *
5892 (xti_tcp_conn_rr_request->request_size +
5893 xti_tcp_conn_rr_request->response_size));
5894 xti_tcp_conn_rr_results->trans_received = trans_received;
5895 xti_tcp_conn_rr_results->elapsed_time = elapsed_time;
5896 if (xti_tcp_conn_rr_request->measure_cpu) {
5897 xti_tcp_conn_rr_results->cpu_util = calc_cpu_util(elapsed_time);
5898 }
5899
5900 if (debug) {
5901 fprintf(where,
5902 "recv_xti_tcp_conn_rr: test complete, sending results.\n");
5903 fflush(where);
5904 }
5905
5906 send_response();
5907
5908 }
5909
5910 void
print_xti_usage()5911 print_xti_usage()
5912 {
5913
5914 fwrite(xti_usage, sizeof(char), strlen(xti_usage), stdout);
5915 exit(1);
5916
5917 }
5918
5919 void
scan_xti_args(int argc,char * argv[])5920 scan_xti_args(int argc, char *argv[])
5921 {
5922 #define XTI_ARGS "Dhm:M:r:s:S:Vw:W:X:"
5923 extern int optind, opterrs; /* index of first unused arg */
5924 extern char *optarg; /* pointer to option string */
5925
5926 int c;
5927
5928 char
5929 arg1[BUFSIZ], /* argument holders */
5930 arg2[BUFSIZ];
5931
5932 if (no_control) {
5933 fprintf(where,
5934 "The XTI tests do not know how to run with no control connection\n");
5935 exit(-1);
5936 }
5937
5938 /* Go through all the command line arguments and break them */
5939 /* out. For those options that take two parms, specifying only */
5940 /* the first will set both to that value. Specifying only the */
5941 /* second will leave the first untouched. To change only the */
5942 /* first, use the form "first," (see the routine break_args.. */
5943
5944 while ((c= getopt(argc, argv, XTI_ARGS)) != EOF) {
5945 switch (c) {
5946 case '?':
5947 case 'h':
5948 print_xti_usage();
5949 exit(1);
5950 case 'D':
5951 /* set the TCP nodelay flag */
5952 loc_nodelay = 1;
5953 rem_nodelay = 1;
5954 break;
5955 case 's':
5956 /* set local socket sizes */
5957 break_args(optarg,arg1,arg2);
5958 if (arg1[0])
5959 lss_size = convert(arg1);
5960 if (arg2[0])
5961 lsr_size = convert(arg2);
5962 break;
5963 case 'S':
5964 /* set remote socket sizes */
5965 break_args(optarg,arg1,arg2);
5966 if (arg1[0])
5967 rss_size = convert(arg1);
5968 if (arg2[0])
5969 rsr_size = convert(arg2);
5970 break;
5971 case 'r':
5972 /* set the request/response sizes */
5973 break_args(optarg,arg1,arg2);
5974 if (arg1[0])
5975 req_size = convert(arg1);
5976 if (arg2[0])
5977 rsp_size = convert(arg2);
5978 break;
5979 case 'm':
5980 /* set the send size */
5981 send_size = convert(optarg);
5982 break;
5983 case 'M':
5984 /* set the recv size */
5985 recv_size = convert(optarg);
5986 break;
5987 case 'W':
5988 /* set the "width" of the user space data */
5989 /* buffer. This will be the number of */
5990 /* send_size buffers malloc'd in the */
5991 /* *_STREAM test. It may be enhanced to set */
5992 /* both send and receive "widths" but for now */
5993 /* it is just the sending *_STREAM. */
5994 send_width = convert(optarg);
5995 break;
5996 case 'V' :
5997 /* we want to do copy avoidance and will set */
5998 /* it for everything, everywhere, if we really */
5999 /* can. of course, we don't know anything */
6000 /* about the remote... */
6001 #ifdef SO_SND_COPYAVOID
6002 loc_sndavoid = 1;
6003 #else
6004 loc_sndavoid = 0;
6005 printf("Local send copy avoidance not available.\n");
6006 #endif
6007 #ifdef SO_RCV_COPYAVOID
6008 loc_rcvavoid = 1;
6009 #else
6010 loc_rcvavoid = 0;
6011 printf("Local recv copy avoidance not available.\n");
6012 #endif
6013 rem_sndavoid = 1;
6014 rem_rcvavoid = 1;
6015 break;
6016 case 'X':
6017 /* set the xti device file name(s) */
6018 break_args(optarg,arg1,arg2);
6019 if (arg1[0])
6020 strcpy(loc_xti_device,arg1);
6021 if (arg2[0])
6022 strcpy(rem_xti_device,arg2);
6023 break;
6024 };
6025 }
6026 }
6027 #endif /* WANT_XTI */
6028