-
Notifications
You must be signed in to change notification settings - Fork 0
/
nettest_bsd.c
12333 lines (10388 loc) · 385 KB
/
nettest_bsd.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#ifndef lint
char nettest_id[]="\
@(#)nettest_bsd.c (c) Copyright 1993-2004 Hewlett-Packard Co. Version 2.4.3";
#endif /* lint */
/****************************************************************/
/* */
/* nettest_bsd.c */
/* */
/* the BSD sockets parsing routine... */
/* ...with the addition of Windows NT, this is now also */
/* a Winsock test... sigh :) */
/* */
/* scan_sockets_args() */
/* */
/* the actual test routines... */
/* */
/* send_tcp_stream() perform a tcp stream test */
/* recv_tcp_stream() */
/* send_tcp_maerts() perform a tcp stream test */
/* recv_tcp_maerts() in the other direction */
/* send_tcp_rr() perform a tcp request/response */
/* recv_tcp_rr() */
/* send_tcp_conn_rr() an RR test including connect */
/* recv_tcp_conn_rr() */
/* send_tcp_cc() a connect/disconnect test with */
/* recv_tcp_cc() no RR */
/* send_udp_stream() perform a udp stream test */
/* recv_udp_stream() */
/* send_udp_rr() perform a udp request/response */
/* recv_udp_rr() */
/* loc_cpu_rate() determine the local cpu maxrate */
/* rem_cpu_rate() find the remote cpu maxrate */
/* */
/****************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#if HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#if STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# if HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif
#if HAVE_STRING_H
# if !STDC_HEADERS && HAVE_MEMORY_H
# include <memory.h>
# endif
# include <string.h>
#endif
#if HAVE_STRINGS_H
# include <strings.h>
#endif
#if HAVE_INTTYPES_H
# include <inttypes.h>
#else
# if HAVE_STDINT_H
# include <stdint.h>
# endif
#endif
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#ifndef WIN32
#include <errno.h>
#include <signal.h>
#endif
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#ifdef NOSTDLIBH
#include <malloc.h>
#endif /* NOSTDLIBH */
#ifndef WIN32
#if !defined(__VMS)
#include <sys/ipc.h>
#endif /* !defined(__VMS) */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#else /* WIN32 */
#include <process.h>
#define netperf_socklen_t socklen_t
#include <winsock2.h>
/* while it is unlikely that anyone running Windows 2000 or NT 4 is
going to be trying to compile this, if they are they will want to
define DONT_IPV6 in the sources file */
#ifndef DONT_IPV6
#include <ws2tcpip.h>
#endif
#include <windows.h>
#define sleep(x) Sleep((x)*1000)
#define __func__ __FUNCTION__
#endif /* WIN32 */
/* We don't want to use bare constants in the shutdown() call. In the
extremely unlikely event that SHUT_WR isn't defined, we will define
it to the value we used to be passing to shutdown() anyway. raj
2007-02-08 */
#if !defined(SHUT_WR)
#define SHUT_WR 1
#endif
#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO)
# include "missing/getaddrinfo.h"
#endif
#include "netlib.h"
#include "netsh.h"
#include "nettest_bsd.h"
#if defined(WANT_HISTOGRAM) || defined(WANT_DEMO)
#include "hist.h"
#endif /* WANT_HISTOGRAM */
/* make first_burst_size unconditional so we can use it easily enough
when calculating transaction latency for the TCP_RR test. raj
2007-06-08 */
int first_burst_size=0;
#if defined(HAVE_SENDFILE) && (defined(__linux) || defined(__sun__))
#include <sys/sendfile.h>
#endif /* HAVE_SENDFILE && (__linux || __sun__) */
/* these variables are specific to the BSD sockets tests, but can
* be used elsewhere if needed. They are externed through nettest_bsd.h
*/
int
rss_size_req = -1, /* requested remote socket send buffer size */
rsr_size_req = -1, /* requested remote socket recv buffer size */
rss_size, /* remote socket send buffer size */
rsr_size, /* remote socket recv buffer size */
lss_size_req = -1, /* requested local socket send buffer size */
lsr_size_req = -1, /* requested local socket recv buffer size */
lss_size, /* local socket send buffer size */
lsr_size, /* local socket recv buffer size */
req_size = 1, /* request size */
rsp_size = 1, /* response size */
send_size, /* how big are individual sends */
recv_size; /* how big are individual receives */
static int confidence_iteration;
static char local_cpu_method;
static char remote_cpu_method;
/* these will control the width of port numbers we try to use in the */
/* TCP_CRR and/or TCP_TRR tests. raj 3/95 */
static int client_port_min = 5000;
static int client_port_max = 65535;
/* different options for the sockets */
int
loc_nodelay, /* don't/do use NODELAY locally */
rem_nodelay, /* don't/do use NODELAY remotely */
#ifdef TCP_CORK
loc_tcpcork=0, /* don't/do use TCP_CORK locally */
rem_tcpcork=0, /* don't/do use TCP_CORK remotely */
#endif /* TCP_CORK */
loc_sndavoid, /* avoid send copies locally */
loc_rcvavoid, /* avoid recv copies locally */
rem_sndavoid, /* avoid send copies remotely */
rem_rcvavoid, /* avoid recv_copies remotely */
local_connected = 0, /* local socket type, connected/non-connected */
remote_connected = 0; /* remote socket type, connected/non-connected */
#ifdef WANT_HISTOGRAM
#ifdef HAVE_GETHRTIME
static hrtime_t time_one;
static hrtime_t time_two;
#elif HAVE_GET_HRT
#include "hrt.h"
static hrt_t time_one;
static hrt_t time_two;
#elif defined(WIN32)
static LARGE_INTEGER time_one;
static LARGE_INTEGER time_two;
#else
static struct timeval time_one;
static struct timeval time_two;
#endif /* HAVE_GETHRTIME */
static HIST time_hist;
#endif /* WANT_HISTOGRAM */
#ifdef WANT_INTERVALS
int interval_count;
#ifndef WANT_SPIN
sigset_t signal_set;
#define INTERVALS_INIT() \
if (interval_burst) { \
/* zero means that we never pause, so we never should need the \
interval timer. we used to use it for demo mode, but we deal \
with that with a variant on watching the clock rather than \
waiting for a timer. raj 2006-02-06 */ \
start_itimer(interval_wate); \
} \
interval_count = interval_burst; \
/* get the signal set for the call to sigsuspend */ \
if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { \
fprintf(where, \
"%s: unable to get sigmask errno %d\n", \
__func__, \
errno); \
fflush(where); \
exit(1); \
}
#define INTERVALS_WAIT() \
/* in this case, the interval count is the count-down couter \
to decide to sleep for a little bit */ \
if ((interval_burst) && (--interval_count == 0)) { \
/* call sigsuspend and wait for the interval timer to get us \
out */ \
if (debug > 1) { \
fprintf(where,"about to suspend\n"); \
fflush(where); \
} \
if (sigsuspend(&signal_set) == EFAULT) { \
fprintf(where, \
"%s: fault with sigsuspend.\n", \
__func__); \
fflush(where); \
exit(1); \
} \
interval_count = interval_burst; \
}
#else
/* first out timestamp */
#ifdef HAVE_GETHRTIME
static hrtime_t intvl_one;
static hrtime_t intvl_two;
static hrtime_t *intvl_one_ptr = &intvl_one;
static hrtime_t *intvl_two_ptr = &intvl_two;
static hrtime_t *temp_intvl_ptr = &intvl_one;
#elif defined(WIN32)
static LARGE_INTEGER intvl_one;
static LARGE_INTEGER intvl_two;
static LARGE_INTEGER *intvl_one_ptr = &intvl_one;
static LARGE_INTEGER *intvl_two_ptr = &intvl_two;
static LARGE_INTEGER *temp_intvl_ptr = &intvl_one;
#else
static struct timeval intvl_one;
static struct timeval intvl_two;
static struct timeval *intvl_one_ptr = &intvl_one;
static struct timeval *intvl_two_ptr = &intvl_two;
static struct timeval *temp_intvl_ptr = &intvl_one;
#endif
#define INTERVALS_INIT() \
if (interval_burst) { \
HIST_timestamp(intvl_one_ptr); \
} \
interval_count = interval_burst; \
#define INTERVALS_WAIT() \
/* in this case, the interval count is the count-down couter \
to decide to sleep for a little bit */ \
if ((interval_burst) && (--interval_count == 0)) { \
/* call sigsuspend and wait for the interval timer to get us \
out */ \
if (debug > 1) { \
fprintf(where,"about to spin suspend\n"); \
fflush(where); \
} \
HIST_timestamp(intvl_two_ptr); \
while(delta_micro(intvl_one_ptr,intvl_two_ptr) < interval_usecs) { \
HIST_timestamp(intvl_two_ptr); \
} \
temp_intvl_ptr = intvl_one_ptr; \
intvl_one_ptr = intvl_two_ptr; \
intvl_two_ptr = temp_intvl_ptr; \
interval_count = interval_burst; \
}
#endif
#endif
#ifdef WANT_DEMO
#ifdef HAVE_GETHRTIME
static hrtime_t demo_one;
static hrtime_t demo_two;
static hrtime_t *demo_one_ptr = &demo_one;
static hrtime_t *demo_two_ptr = &demo_two;
static hrtime_t *temp_demo_ptr = &demo_one;
#elif defined(WIN32)
static LARGE_INTEGER demo_one;
static LARGE_INTEGER demo_two;
static LARGE_INTEGER *demo_one_ptr = &demo_one;
static LARGE_INTEGER *demo_two_ptr = &demo_two;
static LARGE_INTEGER *temp_demo_ptr = &demo_one;
#else
static struct timeval demo_one;
static struct timeval demo_two;
static struct timeval *demo_one_ptr = &demo_one;
static struct timeval *demo_two_ptr = &demo_two;
static struct timeval *temp_demo_ptr = &demo_one;
#endif
/* for a _STREAM test, "a" should be lss_size and "b" should be
rsr_size. for a _MAERTS test, "a" should be lsr_size and "b" should
be rss_size. raj 2005-04-06 */
#define DEMO_STREAM_SETUP(a,b) \
if ((demo_mode) && (demo_units == 0)) { \
/* take our default value of demo_units to be the larger of \
twice the remote's SO_RCVBUF or twice our SO_SNDBUF */ \
if (a > b) { \
demo_units = 2*a; \
} \
else { \
demo_units = 2*b; \
} \
}
#define DEMO_STREAM_INTERVAL(units) \
if (demo_mode) { \
double actual_interval; \
units_this_tick += units; \
if (units_this_tick >= demo_units) { \
/* time to possibly update demo_units and maybe output an \
interim result */ \
HIST_timestamp(demo_two_ptr); \
actual_interval = delta_micro(demo_one_ptr,demo_two_ptr); \
/* we always want to fine-tune demo_units here whether we \
emit an interim result or not. if we are short, this \
will lengthen demo_units. if we are long, this will \
shorten it */ \
demo_units = demo_units * (demo_interval / actual_interval); \
if (actual_interval >= demo_interval) { \
/* time to emit an interim result */ \
fprintf(where, \
"Interim result: %7.2f %s/s over %.2f seconds\n", \
calc_thruput_interval(units_this_tick, \
actual_interval/1000000.0), \
format_units(), \
actual_interval/1000000.0); \
fflush(where); \
units_this_tick = 0.0; \
/* now get a new starting timestamp. we could be clever \
and swap pointers - the math we do probably does not \
take all that long, but for now this will suffice */ \
temp_demo_ptr = demo_one_ptr; \
demo_one_ptr = demo_two_ptr; \
demo_two_ptr = temp_demo_ptr; \
} \
} \
}
#define DEMO_RR_SETUP(a) \
if ((demo_mode) && (demo_units == 0)) { \
/* take whatever we are given */ \
demo_units = a; \
}
#define DEMO_RR_INTERVAL(units) \
if (demo_mode) { \
double actual_interval; \
units_this_tick += units; \
if (units_this_tick >= demo_units) { \
/* time to possibly update demo_units and maybe output an \
interim result */ \
HIST_timestamp(demo_two_ptr); \
actual_interval = delta_micro(demo_one_ptr,demo_two_ptr); \
/* we always want to fine-tune demo_units here whether we \
emit an interim result or not. if we are short, this \
will lengthen demo_units. if we are long, this will \
shorten it */ \
demo_units = demo_units * (demo_interval / actual_interval); \
if (actual_interval >= demo_interval) { \
/* time to emit an interim result */ \
fprintf(where, \
"Interim result: %.2f %s/s over %.2f seconds\n", \
units_this_tick / (actual_interval/1000000.0), \
"Trans", \
actual_interval/1000000.0); \
units_this_tick = 0.0; \
/* now get a new starting timestamp. we could be clever \
and swap pointers - the math we do probably does not \
take all that long, but for now this will suffice */ \
temp_demo_ptr = demo_one_ptr; \
demo_one_ptr = demo_two_ptr; \
demo_two_ptr = temp_demo_ptr; \
} \
} \
}
#endif
char sockets_usage[] = "\n\
Usage: netperf [global options] -- [test options] \n\
\n\
TCP/UDP BSD Sockets Test Options:\n\
-b number Send number requests at start of _RR tests\n\
-C Set TCP_CORK when available\n\
-D [L][,R] Set TCP_NODELAY locally and/or remotely (TCP_*)\n\
-h Display this text\n\
-H name,fam Use name (or IP) and family as target of data connection\n\
-L name,fam Use name (or IP) and family as source of data connection\n\
-m bytes Set the send size (TCP_STREAM, UDP_STREAM)\n\
-M bytes Set the recv size (TCP_STREAM, UDP_STREAM)\n\
-n Use the connected socket for UDP locally\n\
-N Use the connected socket for UDP remotely\n\
-p min[,max] Set the min/max port numbers for TCP_CRR, TCP_TRR\n\
-P local[,remote] Set the local/remote port for the data socket\n\
-r req,[rsp] Set request/response sizes (TCP_RR, UDP_RR)\n\
-s send[,recv] Set local socket send/recv buffer sizes\n\
-S send[,recv] Set remote socket send/recv buffer sizes\n\
-4 Use AF_INET (eg IPv4) on both ends of the data conn\n\
-6 Use AF_INET6 (eg IPv6) on both ends of the data conn\n\
\n\
For those options taking two parms, at least one must be specified;\n\
specifying one value without a comma will set both parms to that\n\
value, specifying a value with a leading comma will set just the second\n\
parm, a value with a trailing comma will set just the first. To set\n\
each parm to unique values, specify both and separate them with a\n\
comma.\n";
/* these routines convert between the AF address space and the NF
address space since the numeric values of AF_mumble are not the
same across the platforms. raj 2005-02-08 */
int
nf_to_af(int nf) {
switch(nf) {
case NF_INET:
return AF_INET;
break;
case NF_UNSPEC:
return AF_UNSPEC;
break;
case NF_INET6:
#if defined(AF_INET6)
return AF_INET6;
#else
return AF_UNSPEC;
#endif
break;
default:
return AF_UNSPEC;
break;
}
}
int
af_to_nf(int af) {
switch(af) {
case AF_INET:
return NF_INET;
break;
case AF_UNSPEC:
return NF_UNSPEC;
break;
#if defined(AF_INET6)
case AF_INET6:
return NF_INET6;
break;
#endif
default:
return NF_UNSPEC;
break;
}
}
/* This routine is intended to retrieve interesting aspects of tcp */
/* for the data connection. at first, it attempts to retrieve the */
/* maximum segment size. later, it might be modified to retrieve */
/* other information, but it must be information that can be */
/* retrieved quickly as it is called during the timing of the test. */
/* for that reason, a second routine may be created that can be */
/* called outside of the timing loop */
static
void
get_tcp_info(SOCKET socket, int *mss)
{
#ifdef TCP_MAXSEG
netperf_socklen_t sock_opt_len;
sock_opt_len = sizeof(netperf_socklen_t);
if (getsockopt(socket,
getprotobyname("tcp")->p_proto,
TCP_MAXSEG,
(char *)mss,
&sock_opt_len) == SOCKET_ERROR) {
fprintf(where,
"netperf: get_tcp_info: getsockopt TCP_MAXSEG: errno %d\n",
errno);
fflush(where);
*mss = -1;
}
#else
*mss = -1;
#endif /* TCP_MAXSEG */
}
/* return a pointer to a completed addrinfo chain - prefer
data_address to controlhost and utilize the specified address
family */
struct addrinfo *
complete_addrinfo(char *controlhost, char *data_address, char *port, int family, int type, int protocol, int flags)
{
struct addrinfo hints;
struct addrinfo *res;
struct addrinfo *temp_res;
#define CHANGED_SOCK_TYPE 0x1
#define CHANGED_PROTOCOL 0x2
#define CHANGED_SCTP 0x4
int change_info = 0;
static int change_warning_displayed = 0;
int count = 0;
int error = 0;
char *hostname;
/* take data-address over controlhost */
if (data_address)
hostname = data_address;
else
hostname = controlhost;
if (debug) {
fprintf(where,
"complete_addrinfo using hostname %s port %s family %s type %s prot %s flags 0x%x\n",
hostname,
port,
inet_ftos(family),
inet_ttos(type),
inet_ptos(protocol),
flags);
fflush(where);
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
hints.ai_socktype = type;
hints.ai_protocol = protocol;
hints.ai_flags = flags|AI_CANONNAME;
count = 0;
do {
error = getaddrinfo((char *)hostname,
(char *)port,
&hints,
&res);
count += 1;
if (error == EAI_AGAIN) {
if (debug) {
fprintf(where,"Sleeping on getaddrinfo EAI_AGAIN\n");
fflush(where);
}
sleep(1);
}
/* while you see this kludge first, it is actually the second, the
first being the one for Solaris below. The need for this kludge
came after implementing the Solaris broken getaddrinfo kludge -
now we see a kludge in Linux getaddrinfo where if it is given
SOCK_STREAM and IPPROTO_SCTP it barfs with a -7
EAI_SOCKTYPE. so, we check if the error was EAI_SOCKTYPE and if
we were asking for IPPROTO_SCTP and if so, kludge, again... raj
2008-10-13 */
#ifdef WANT_SCTP
if (EAI_SOCKTYPE == error
#ifdef EAI_BADHINTS
|| EAI_BADHINTS == error
#endif
) {
/* we ass-u-me this is the Linux getaddrinfo bug, clear the
hints.ai_protocol field, and set some state "remembering"
that we did this so the code for the Solaris kludge can do
the fix-up for us. also flip error over to EAI_AGAIN and
make sure we don't "count" this time around the loop. */
hints.ai_protocol = 0;
error = EAI_AGAIN;
count -= 1;
change_info |= CHANGED_SCTP;
}
#endif
} while ((error == EAI_AGAIN) && (count <= 5));
if (error) {
fprintf(where,
"complete_addrinfo: could not resolve '%s' port '%s' af %d",
hostname,
port,
family);
fprintf(where,
"\n\tgetaddrinfo returned %d %s\n",
error,
gai_strerror(error));
fflush(where);
exit(-1);
}
/* there exists at least one platform - Solaris 10 - that does not
seem to completely honor the ai_protocol and/or ai_socktype one
sets in the hints parm to the getaddrinfo call. so, we need to
walk the list of entries returned and if either of those do not
match what we asked for, we need to go ahead and set them
"correctly" this is based in part on some earlier SCTP-only code
from previous revisions. raj 2006-10-09 */
temp_res = res;
while (temp_res) {
if ((type) &&
(temp_res->ai_socktype != type)) {
change_info |= CHANGED_SOCK_TYPE;
if (debug) {
fprintf(where,
"WARNING! Changed bogus getaddrinfo socket type %d to %d\n",
temp_res->ai_socktype,
type);
fflush(where);
}
temp_res->ai_socktype = type;
}
if ((protocol) &&
(temp_res->ai_protocol != protocol)) {
change_info |= CHANGED_PROTOCOL;
if (debug) {
fprintf(where,
"WARNING! Changed bogus getaddrinfo protocol %d to %d\n",
temp_res->ai_protocol,
protocol);
fflush(where);
}
temp_res->ai_protocol = protocol;
}
temp_res = temp_res->ai_next;
}
if ((change_info & CHANGED_SOCK_TYPE) &&
!(change_warning_displayed & CHANGED_SOCK_TYPE)) {
change_warning_displayed |= CHANGED_SOCK_TYPE;
fprintf(where,
"WARNING! getaddrinfo returned a socket type which did not\n");
fprintf(where,
"match the requested type. Please contact your vendor for\n");
fprintf(where,
"a fix to this bug in getaddrinfo()\n");
fflush(where);
}
/* if we dropped the protocol hint, it would be for a protocol that
getaddrinfo() wasn't supporting yet, not for the bug that it took
our hint and still returned zero. raj 2006-10-16 */
if ((change_info & CHANGED_PROTOCOL) &&
!(change_warning_displayed & CHANGED_PROTOCOL) &&
(hints.ai_protocol != 0)) {
change_warning_displayed |= CHANGED_PROTOCOL;
fprintf(where,
"WARNING! getaddrinfo returned a protocol other than the\n");
fprintf(where,
"requested protocol. Please contact your vendor for\n");
fprintf(where,
"a fix to this bug in getaddrinfo()\n");
fflush(where);
}
if ((change_info & CHANGED_SCTP) &&
!(change_warning_displayed & CHANGED_SCTP)) {
change_warning_displayed |= CHANGED_SCTP;
fprintf(where,
"WARNING! getaddrinfo on this platform does not accept IPPROTO_SCTP!\n");
fprintf(where,
"Please contact your vendor for a fix to this bug in getaddrinfo().\n");
fflush(where);
}
if (debug) {
dump_addrinfo(where, res, hostname, port, family);
}
return(res);
}
void
complete_addrinfos(struct addrinfo **remote,struct addrinfo **local, char remote_host[], int type, int protocol, int flags) {
*remote = complete_addrinfo(remote_host,
remote_data_address,
remote_data_port,
remote_data_family,
type,
protocol,
flags);
/* OK, if the user has not specified a local data endpoint address
(test-specific -L), pick the local data endpoint address based on
the remote data family info (test-specific -H or -4 or -6
option). if the user has not specified remote data addressing
info (test-specific -H, -4 -6) pick something based on the local
control connection address (ie the global -L option). */
if (NULL == local_data_address) {
local_data_address = malloc(HOSTNAMESIZE);
if (NULL == remote_data_address) {
if (debug) {
fprintf(where,
"local_data_address not set, using local_host_name of '%s'\n",
local_host_name);
fflush(where);
}
strcpy(local_data_address,local_host_name);
}
else {
if (debug) {
fprintf(where,
"local_data_address not set, using address family info\n");
fflush(where);
}
/* by default, use 0.0.0.0 - assume IPv4 */
strcpy(local_data_address,"0.0.0.0");
#if defined(AF_INET6)
if ((AF_INET6 == local_data_family) ||
((AF_UNSPEC == local_data_family) &&
(AF_INET6 == remote_data_family)) ||
((AF_UNSPEC == local_data_family) &&
(AF_INET6 == (*remote)->ai_family))) {
strcpy(local_data_address,"::0");
}
#endif
}
}
*local = complete_addrinfo("what to put here?",
local_data_address,
local_data_port,
local_data_family,
type,
protocol,
flags|AI_PASSIVE);
}
void
set_hostname_and_port(char *hostname, char *portstr, int family, int port)
{
strcpy(hostname,"0.0.0.0");
#if defined AF_INET6
if (AF_INET6 == family) {
strcpy(hostname,"::0");
}
#endif
sprintf(portstr, "%u", port);
}
static unsigned short
get_port_number(struct addrinfo *res)
{
switch(res->ai_family) {
case AF_INET: {
struct sockaddr_in *foo = (struct sockaddr_in *)res->ai_addr;
return(ntohs(foo->sin_port));
break;
}
#if defined(AF_INET6)
case AF_INET6: {
struct sockaddr_in6 *foo = (struct sockaddr_in6 *)res->ai_addr;
return(ntohs(foo->sin6_port));
break;
}
#endif
default:
fprintf(where,
"Unexpected Address Family of %u\n",res->ai_family);
fflush(where);
exit(-1);
}
}
/* this routine will set the port number of the sockaddr in the
addrinfo to the specified value, based on the address family */
void
set_port_number(struct addrinfo *res, unsigned short port)
{
switch(res->ai_family) {
case AF_INET: {
struct sockaddr_in *foo = (struct sockaddr_in *)res->ai_addr;
foo->sin_port = htons(port);
break;
}
#if defined(AF_INET6)
case AF_INET6: {
struct sockaddr_in6 *foo = (struct sockaddr_in6 *)res->ai_addr;
foo->sin6_port = htons(port);
break;
}
#endif
default:
fprintf(where,
"Unexpected Address Family of %u\n",res->ai_family);
fflush(where);
exit(-1);
}
}
/* This routine will create a data (listen) socket with the
apropriate options set and return it to the caller. this replaces
all the duplicate code in each of the test routines and should help
make things a little easier to understand. since this routine can be
called by either the netperf or netserver programs, all output
should be directed towards "where." family is generally AF_INET and
type will be either SOCK_STREAM or SOCK_DGRAM. This routine will
also be used by the "SCTP" tests, hence the slightly strange-looking
SCTP stuff in the classic bsd sockets test file... vlad/raj
2005-03-15 */
SOCKET
create_data_socket(struct addrinfo *res)
{
SOCKET temp_socket;
int one;
int on = 1;
/*set up the data socket */
temp_socket = socket(res->ai_family,
res->ai_socktype,
res->ai_protocol);
if (temp_socket == INVALID_SOCKET){
fprintf(where,
"netperf: create_data_socket: socket: errno %d fam %s type %s prot %s errmsg %s\n",
errno,
inet_ftos(res->ai_family),
inet_ttos(res->ai_socktype),
inet_ptos(res->ai_protocol),
strerror(errno));
fflush(where);
exit(1);
}
if (debug) {
fprintf(where,"create_data_socket: socket %d obtained...\n",temp_socket);
fflush(where);
}
/* Modify the local socket size. The reason we alter the send buffer
size here rather than when the connection is made is to take care
of decreases in buffer size. Decreasing the window size after
connection establishment is a TCP no-no. Also, by setting the
buffer (window) size before the connection is established, we can
control the TCP MSS (segment size). The MSS is never (well, should
never be) more that 1/2 the minimum receive buffer size at each
half of the connection. This is why we are altering the receive
buffer size on the sending size of a unidirectional transfer. If
the user has not requested that the socket buffers be altered, we
will try to find-out what their values are. If we cannot touch the
socket buffer in any way, we will set the values to -1 to indicate
that. */
/* all the oogy nitty gritty stuff moved from here into the routine
being called below, per patches from davidm to workaround the bug
in Linux getsockopt(). raj 2004-06-15 */
set_sock_buffer (temp_socket, SEND_BUFFER, lss_size_req, &lss_size);
set_sock_buffer (temp_socket, RECV_BUFFER, lsr_size_req, &lsr_size);
/* now, we may wish to enable the copy avoidance features on the */
/* local system. of course, this may not be possible... */
#ifdef SO_RCV_COPYAVOID
if (loc_rcvavoid) {
if (setsockopt(temp_socket,
SOL_SOCKET,
SO_RCV_COPYAVOID,
(const char *)&loc_rcvavoid,
sizeof(int)) == SOCKET_ERROR) {
fprintf(where,
"netperf: create_data_socket: Could not enable receive copy avoidance");
fflush(where);
loc_rcvavoid = 0;
}
}
#else
/* it wasn't compiled in... */
loc_rcvavoid = 0;
#endif /* SO_RCV_COPYAVOID */
#ifdef SO_SND_COPYAVOID
if (loc_sndavoid) {
if (setsockopt(temp_socket,
SOL_SOCKET,
SO_SND_COPYAVOID,
(const char *)&loc_sndavoid,
sizeof(int)) == SOCKET_ERROR) {
fprintf(where,
"netperf: create_data_socket: Could not enable send copy avoidance");
fflush(where);
loc_sndavoid = 0;
}
}
#else
/* it was not compiled in... */
loc_sndavoid = 0;
#endif
/* Now, we will see about setting the TCP_NODELAY flag on the local */
/* socket. We will only do this for those systems that actually */
/* support the option. If it fails, note the fact, but keep going. */
/* If the user tries to enable TCP_NODELAY on a UDP socket, this */
/* will cause an error to be displayed */
/* well..... long ago and far away that would have happened, in
particular because we would always use IPPROTO_TCP here.
however, now we are using res->ai_protocol, which will be
IPPROT_UDP, and while HP-UX, and I suspect no-one else on the
planet has a UDP_mumble option that overlaps with TCP_NODELAY,
sure as knuth made little green programs, linux has a UDP_CORK
option that is defined as a value of 1, which is the same a
TCP_NODELAY under Linux. So, when asking for -D and
"TCP_NODELAY" under Linux, we are actually setting UDP_CORK
instead of getting an error like every other OS on the
planet. joy and rupture. this stops a UDP_RR test cold sooo we
have to make sure that res->ai_protocol actually makes sense for
a _NODELAY setsockopt() or a UDP_RR test on Linux where someone
mistakenly sets -D will hang. raj 2005-04-21 */
#if defined(TCP_NODELAY) || defined(SCTP_NODELAY)
if ((loc_nodelay) && (res->ai_protocol != IPPROTO_UDP)) {
/* strictly speaking, since the if defined above is an OR, we
should probably check against TCP_NODELAY being defined here.
however, the likelihood of SCTP_NODELAY being defined and
TCP_NODELAY _NOT_ being defined is, probably :), epsilon. raj
2005-03-15 */
int option = TCP_NODELAY;
/* I suspect that WANT_SCTP would suffice here since that is the
only time we would have called getaddrinfo with a hints asking
for SCTP, but just in case there is an SCTP implementation out
there _without_ SCTP_NODELAY... raj 2005-03-15 */
#if defined(WANT_SCTP) && defined(SCTP_NODELAY)
if (IPPROTO_SCTP == res->ai_protocol) {
option = SCTP_NODELAY;
}
#endif
one = 1;
if(setsockopt(temp_socket,
res->ai_protocol,
option,
(char *)&one,
sizeof(one)) == SOCKET_ERROR) {
fprintf(where,
"netperf: create_data_socket: nodelay: errno %d\n",
errno);
fflush(where);
}
if (debug > 1) {
fprintf(where,
"netperf: create_data_socket: [TCP|SCTP]_NODELAY requested...\n");