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