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