]>
Commit | Line | Data |
---|---|---|
342c141e A |
1 | /* |
2 | * Copyright (c) 2012-2014 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | /* | |
29 | * Copyright (c) 1997 | |
30 | * The Regents of the University of California. All rights reserved. | |
31 | * | |
32 | * Redistribution and use in source and binary forms, with or without | |
33 | * modification, are permitted provided that: (1) source code distributions | |
34 | * retain the above copyright notice and this paragraph in its entirety, (2) | |
35 | * distributions including binary code include the above copyright notice and | |
36 | * this paragraph in its entirety in the documentation or other materials | |
37 | * provided with the distribution, and (3) all advertising materials mentioning | |
38 | * features or use of this software display the following acknowledgement: | |
39 | * ``This product includes software developed by the University of California, | |
40 | * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of | |
41 | * the University nor the names of its contributors may be used to endorse | |
42 | * or promote products derived from this software without specific prior | |
43 | * written permission. | |
44 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED | |
45 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF | |
46 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
47 | */ | |
48 | ||
49 | // | |
50 | // Created by Anumita Biswas on 7/17/12. | |
51 | // | |
52 | ||
53 | #include <stdio.h> | |
54 | #include <stdlib.h> | |
55 | #include <unistd.h> | |
56 | #include <string.h> | |
57 | #include <stdint.h> | |
58 | #include <sys/types.h> | |
59 | #include <sys/socket.h> | |
60 | #include <sys/ioctl.h> | |
61 | #include <net/if.h> | |
62 | #include <netinet/in.h> | |
63 | #include <netdb.h> | |
64 | #include <errno.h> | |
65 | #include <arpa/inet.h> | |
66 | #include <err.h> | |
67 | #include <sysexits.h> | |
68 | #include <getopt.h> | |
69 | ||
70 | #include "conn_lib.h" | |
71 | ||
72 | struct so_cordreq socorder; | |
73 | static void showmpinfo(int s); | |
74 | ||
75 | #define MSG_HDR "Message Header" | |
76 | #define RESPONSE "I got your message" | |
77 | ||
78 | static int verbose = 0; | |
79 | ||
80 | static int32_t thiszone = 0; /* time difference with gmt */ | |
81 | ||
82 | char* setup_buffer1(int bufsz) | |
83 | { | |
84 | int i = 0, j = 1; | |
85 | char *buf = malloc(bufsz); | |
86 | if (buf) { | |
87 | bzero(buf, bufsz); | |
88 | strlcpy(buf, MSG_HDR, sizeof(MSG_HDR)); | |
89 | } | |
90 | for (i = sizeof(MSG_HDR); i < bufsz; i++) { | |
91 | buf[i] = j; | |
92 | j++; | |
93 | if (j >= 255) | |
94 | j = 1; | |
95 | } | |
96 | return buf; | |
97 | } | |
98 | ||
99 | char* setup_buffer2(int bufsz) | |
100 | { | |
101 | int i = 0; | |
102 | char j = 'A'; | |
103 | char *buf = malloc(bufsz); | |
104 | if (buf) { | |
105 | bzero(buf, bufsz); | |
106 | strlcpy(buf, MSG_HDR, sizeof(MSG_HDR)); | |
107 | } | |
108 | for (i = sizeof(MSG_HDR); i < bufsz; i++) { | |
109 | buf[i] = j; | |
110 | j++; | |
111 | if (j >= 'z') | |
112 | j = 'A'; | |
113 | } | |
114 | return buf; | |
115 | } | |
116 | ||
117 | char *setup_buffer3(int bufsz) | |
118 | { | |
119 | char *buf = malloc(bufsz); | |
120 | if (buf) { | |
121 | bzero(buf, bufsz); | |
122 | } | |
123 | return buf; | |
124 | } | |
125 | ||
126 | /* | |
127 | * Returns the difference between gmt and local time in seconds. | |
128 | * Use gmtime() and localtime() to keep things simple. | |
129 | * from tcpdump/gmt2local.c | |
130 | */ | |
131 | static int32_t | |
132 | gmt2local(time_t t) | |
133 | { | |
134 | int dt, dir; | |
135 | struct tm *gmt, *loc; | |
136 | struct tm sgmt; | |
137 | ||
138 | if (t == 0) | |
139 | t = time(NULL); | |
140 | gmt = &sgmt; | |
141 | *gmt = *gmtime(&t); | |
142 | loc = localtime(&t); | |
143 | dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + | |
144 | (loc->tm_min - gmt->tm_min) * 60; | |
145 | ||
146 | /* | |
147 | * If the year or julian day is different, we span 00:00 GMT | |
148 | * and must add or subtract a day. Check the year first to | |
149 | * avoid problems when the julian day wraps. | |
150 | */ | |
151 | dir = loc->tm_year - gmt->tm_year; | |
152 | if (dir == 0) | |
153 | dir = loc->tm_yday - gmt->tm_yday; | |
154 | dt += dir * 24 * 60 * 60; | |
155 | ||
156 | return (dt); | |
157 | } | |
158 | ||
159 | /* | |
160 | * Print the timestamp | |
161 | * from tcpdump/util.c | |
162 | */ | |
163 | static void | |
164 | ts_print(void) | |
165 | { | |
166 | int s; | |
167 | struct timeval tv; | |
168 | ||
169 | gettimeofday(&tv, NULL); | |
170 | ||
171 | /* Default */ | |
172 | s = (tv.tv_sec + thiszone) % 86400; | |
173 | printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60, | |
174 | (u_int32_t)tv.tv_usec); | |
175 | } | |
176 | ||
177 | static const char * | |
178 | basename(const char * str) | |
179 | { | |
180 | const char *last_slash = strrchr(str, '/'); | |
181 | ||
182 | if (last_slash == NULL) | |
183 | return (str); | |
184 | else | |
185 | return (last_slash + 1); | |
186 | } | |
187 | ||
188 | struct option_desc { | |
189 | const char *option; | |
190 | const char *description; | |
191 | int required; | |
192 | }; | |
193 | ||
194 | struct option_desc option_desc_list[] = { | |
195 | { "--host addr", "address of server to connect to", 1 }, | |
196 | { "--port n", "port of server to connect to", 1 }, | |
197 | { "--reqlen n", "length of request (256 by default)", 0 }, | |
198 | { "--rsplen n", "length of response (256 by default)", 0 }, | |
199 | { "--ntimes n", "number of time to send request (1 by default)", 0 }, | |
200 | { "--alt_addr addr", "alternate server to connect to", 0 }, | |
201 | { "--connorder add", "alternate server to connect to", 0 }, | |
202 | { "--longlived n", "number of reconnection for long lived (default 0)", 0 }, | |
203 | { "--fastjoin (0|1)", "use fast join (default 0)", 0 }, | |
204 | { "--nowaitforjoin (0|1)", "do not wait for join (default 0 -- i.e. wait)", 0 }, | |
205 | { "--verbose", "increase verbosity", 0 }, | |
206 | { "--help", "display this help", 0 }, | |
207 | ||
208 | { NULL, NULL, 0 } /* Mark end of list */ | |
209 | }; | |
210 | ||
211 | static void | |
212 | usage(const char *cmd) | |
213 | { | |
214 | struct option_desc *option_desc; | |
215 | char *usage_str = malloc(LINE_MAX); | |
216 | size_t usage_len; | |
217 | ||
218 | if (usage_str == NULL) | |
219 | err(1, "%s: malloc(%d)", __func__, LINE_MAX); | |
220 | ||
221 | usage_len = snprintf(usage_str, LINE_MAX, "# usage: %s ", basename(cmd)); | |
222 | ||
223 | for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) { | |
224 | int len; | |
225 | ||
226 | if (option_desc->required) | |
227 | len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "%s ", option_desc->option); | |
228 | else | |
229 | len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "[%s] ", option_desc->option); | |
230 | if (len < 0) | |
231 | err(1, "%s: snprintf(", __func__); | |
232 | ||
233 | usage_len += len; | |
234 | if (usage_len > LINE_MAX) | |
235 | break; | |
236 | } | |
237 | printf("%s\n", usage_str); | |
238 | printf("options:\n"); | |
239 | ||
240 | for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) { | |
241 | printf(" %-24s # %s\n", option_desc->option, option_desc->description); | |
242 | } | |
243 | printf("\n"); | |
244 | printf("# legacy usage: "); | |
245 | printf("%s hostname port reqlen rsplen ntimes alt_addr 0 connorder longlived fastjoin nowaitforjoin\n", | |
246 | basename(cmd)); | |
247 | } | |
248 | ||
249 | static struct option longopts[] = { | |
250 | { "host", required_argument, NULL, 'c' }, | |
251 | { "port", required_argument, NULL, 'p' }, | |
252 | { "reqlen", required_argument, NULL, 'r' }, | |
253 | { "rsplen", required_argument, NULL, 'R' }, | |
254 | { "ntimes", required_argument, NULL, 'n' }, | |
255 | { "alt_addr", required_argument, NULL, 'a' }, | |
256 | { "connorder", required_argument, NULL, 'o' }, | |
257 | { "longlived", required_argument, NULL, 'l' }, | |
258 | { "fastjoin", required_argument, NULL, 'f' }, | |
259 | { "nowaitforjoin", required_argument, NULL, 'w' }, | |
260 | { "help", no_argument, NULL, 'h' }, | |
261 | { "verbose", no_argument, NULL, 'v' }, | |
262 | { "quiet", no_argument, NULL, 'q' }, | |
263 | { NULL, 0, NULL, 0 } | |
264 | ||
265 | }; | |
266 | ||
267 | static int | |
268 | sprint_sockaddr(char *str, socklen_t strlen, struct sockaddr *sa) | |
269 | { | |
270 | int retval = 0; | |
271 | ||
272 | if (sa->sa_family == AF_INET) { | |
273 | struct sockaddr_in *sin = (struct sockaddr_in*)sa; | |
274 | char str4[INET_ADDRSTRLEN]; | |
275 | ||
276 | inet_ntop(AF_INET, &sin->sin_addr, str4, sizeof(str4)); | |
277 | ||
278 | retval = snprintf(str, strlen, "%s:%u", str4, ntohs(sin->sin_port)); | |
279 | } else if (sa->sa_family == AF_INET6) { | |
280 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa; | |
281 | char str6[INET6_ADDRSTRLEN]; | |
282 | char ifname[IF_NAMESIZE]; | |
283 | char scopestr[2 + IF_NAMESIZE]; | |
284 | ||
285 | inet_ntop(AF_INET6, &sin6->sin6_addr, str6, sizeof(str6)); | |
286 | ||
287 | if (sin6->sin6_scope_id == 0) | |
288 | *scopestr = '\0'; | |
289 | else { | |
290 | if_indextoname(sin6->sin6_scope_id, ifname); | |
291 | snprintf(scopestr, sizeof(scopestr), "%%%s", ifname); | |
292 | } | |
293 | ||
294 | retval = snprintf(str, strlen, "%s%s:%u", | |
295 | str6, | |
296 | scopestr, | |
297 | ntohs(sin6->sin6_port)); | |
298 | } | |
299 | return (retval); | |
300 | } | |
301 | ||
302 | int main(int argc, char * const *argv) | |
303 | { | |
304 | int sockfd, ps, portno; | |
305 | ssize_t n; | |
306 | int reqlen = 256; | |
307 | int rsplen = 256; | |
308 | int ntimes = 1; | |
309 | int connordrtest = 0; | |
310 | int longlived = 0; | |
311 | int fastjoin = 0; | |
312 | char *buffer = NULL; | |
313 | char *buffer1; | |
314 | char *buffer2; | |
315 | char *buffer3; | |
316 | struct addrinfo *ares = NULL, ahints; | |
317 | struct addrinfo *altres = NULL; | |
318 | int retval = 0; | |
319 | int which_buf = 0; | |
89c4ed63 | 320 | sae_connid_t cid1, cid2; |
342c141e A |
321 | int iter; |
322 | int bytes_to_rdwr; | |
323 | int peeled_off = 0; | |
324 | int nowaitforjoin = 0; | |
325 | int ch; | |
326 | const char *host_arg = NULL; | |
327 | const char *port_arg = NULL; | |
328 | const char *reqlen_arg = "256"; | |
329 | const char *rsplen_arg = "256"; | |
330 | const char *ntimes_arg = "1"; | |
331 | const char *alt_addr_arg = NULL; | |
332 | const char *alt_port_arg = "0"; | |
333 | const char *connorder_arg = NULL; | |
334 | const char *longlived_arg = NULL; | |
335 | const char *fastjoin_arg = NULL; | |
336 | const char *nowaitforjoin_arg = NULL; | |
337 | int gotopt = 0; | |
338 | ||
339 | thiszone = gmt2local(0); | |
340 | ||
341 | while ((ch = getopt_long(argc, argv, "a:c:f:hl:n:o:p:qr:R:vw:", longopts, NULL)) != -1) { | |
342 | gotopt = 1; | |
343 | switch (ch) { | |
344 | case 'a': | |
345 | alt_addr_arg = optarg; | |
346 | break; | |
347 | case 'c': | |
348 | host_arg = optarg; | |
349 | break; | |
350 | case 'f': | |
351 | fastjoin_arg = optarg; | |
352 | break; | |
353 | case 'l': | |
354 | longlived_arg = optarg; | |
355 | break; | |
356 | case 'n': | |
357 | ntimes_arg = optarg; | |
358 | break; | |
359 | case 'o': | |
360 | connorder_arg = optarg; | |
361 | break; | |
362 | case 'p': | |
363 | port_arg = optarg; | |
364 | break; | |
365 | case 'q': | |
366 | verbose--; | |
367 | break; | |
368 | case 'r': | |
369 | reqlen_arg = optarg; | |
370 | break; | |
371 | case 'R': | |
372 | rsplen_arg = optarg; | |
373 | break; | |
374 | case 'v': | |
375 | verbose++; | |
376 | break; | |
377 | case 'w': | |
378 | nowaitforjoin_arg = optarg; | |
379 | break; | |
380 | ||
381 | default: | |
382 | usage(argv[0]); | |
383 | exit(EX_USAGE); | |
384 | ||
385 | } | |
386 | } | |
387 | ||
388 | if (gotopt == 0) { | |
389 | if (argc == 12) { | |
390 | host_arg = argv[1]; | |
391 | port_arg = argv[2]; | |
392 | reqlen_arg = argv[3]; | |
393 | rsplen_arg = argv[4]; | |
394 | ntimes_arg = argv[5]; | |
395 | alt_addr_arg = argv[6]; | |
396 | connorder_arg = argv[8]; | |
397 | longlived_arg = argv[9]; | |
398 | fastjoin_arg = argv[10]; | |
399 | nowaitforjoin_arg = argv[11]; | |
400 | } else { | |
401 | usage(argv[0]); | |
402 | exit(EX_USAGE); | |
403 | } | |
404 | } | |
405 | ||
406 | if (host_arg == NULL) | |
407 | errx(EX_USAGE, "missing required host option\n"); | |
408 | ||
409 | if (port_arg == NULL) | |
410 | errx(EX_USAGE, "missing required port option\n"); | |
411 | portno = atoi(port_arg); | |
412 | if (portno < 0 || portno > 65535) | |
413 | errx(EX_USAGE, "invalid port %s\n", port_arg); | |
414 | ||
415 | if (reqlen_arg != NULL) { | |
416 | reqlen = atoi(reqlen_arg); | |
417 | if (reqlen < 0) | |
418 | errx(EX_USAGE, "invalid request length %s\n", reqlen_arg); | |
419 | } | |
420 | ||
421 | if (rsplen_arg != NULL) { | |
422 | rsplen = atoi(rsplen_arg); | |
423 | if (rsplen < 0) | |
424 | errx(EX_USAGE, "invalid response length %s\n", rsplen_arg); | |
425 | } | |
426 | ||
427 | if (ntimes_arg != NULL) { | |
428 | ntimes = atoi(ntimes_arg); | |
429 | if (ntimes < 1) | |
430 | errx(EX_USAGE, "invalid ntimes option %s\n", ntimes_arg); | |
431 | } | |
432 | ||
433 | if (connorder_arg != NULL) { | |
434 | connordrtest = atoi(connorder_arg); | |
435 | if (connordrtest != 0 && connordrtest != 1) | |
436 | errx(EX_USAGE, "invalid connorder count %s\n", connorder_arg); | |
437 | } | |
438 | ||
439 | if (longlived_arg != NULL) { | |
440 | longlived = atoi(longlived_arg); | |
441 | if (longlived < 0) | |
442 | errx(EX_USAGE, "invalid longlived count %s\n", longlived_arg); | |
443 | } | |
444 | ||
445 | if (fastjoin_arg != NULL) { | |
446 | fastjoin = atoi(fastjoin_arg); | |
447 | if (fastjoin != 0 && fastjoin != 1) | |
448 | errx(EX_USAGE, "invalid fastjoin option %s\n", fastjoin_arg); | |
449 | } | |
450 | ||
451 | if (nowaitforjoin_arg != NULL) { | |
452 | nowaitforjoin = atoi(nowaitforjoin_arg); | |
453 | if (nowaitforjoin != 0 && nowaitforjoin != 1) | |
454 | errx(EX_USAGE, "invalid nowaitforjoin option %s\n", nowaitforjoin_arg); | |
455 | } | |
456 | ||
457 | buffer1 = setup_buffer1(reqlen); | |
458 | if (!buffer1) { | |
459 | printf("client: failed to alloc buffer space \n"); | |
460 | return -1; | |
461 | } | |
462 | ||
463 | buffer2 = setup_buffer2(reqlen); | |
464 | if (!buffer2) { | |
465 | printf("client: failed to alloc buffer space \n"); | |
466 | return -1; | |
467 | } | |
468 | ||
469 | buffer3 = setup_buffer3(rsplen); | |
470 | if (!buffer3) { | |
471 | printf("client: failed to alloc buffer space \n"); | |
472 | return -1; | |
473 | } | |
474 | ||
475 | if (verbose > 0) | |
476 | printf("host: %s port: %s reqlen: %d rsplen: %d ntimes: %d alt_addr: %s connorder: %d longlived: %d fasjoin: %d nowaitforjoin: %d\n", | |
477 | host_arg, port_arg, reqlen, rsplen, ntimes, alt_addr_arg, connordrtest, longlived, fastjoin, nowaitforjoin); | |
478 | ||
479 | sockfd = socket(AF_MULTIPATH, SOCK_STREAM, 0); | |
480 | if (sockfd < 0) | |
481 | err(EX_OSERR, "ERROR opening socket"); | |
482 | #define SO_MPTCP_FASTJOIN 0x1111 | |
483 | opterr = setsockopt(sockfd, SOL_SOCKET, SO_MPTCP_FASTJOIN, &fastjoin, sizeof(fastjoin)); | |
484 | if (opterr != 0) | |
485 | warn("setsockopt(SO_MPTCP_FASTJOIN, %d)", fastjoin); | |
486 | ||
487 | memset(&ahints, 0, sizeof(struct addrinfo)); | |
488 | ahints.ai_family = AF_INET; | |
489 | ahints.ai_socktype = SOCK_STREAM; | |
490 | ahints.ai_protocol = IPPROTO_TCP; | |
491 | ||
492 | retval = getaddrinfo(host_arg, port_arg, &ahints, &ares); | |
493 | if (retval != 0) | |
494 | printf("getaddrinfo(%s, %s) failed %d\n", host_arg, port_arg, retval); | |
495 | ||
496 | bytes_to_rdwr = reqlen; | |
497 | connect_again: | |
498 | ||
89c4ed63 | 499 | cid1 = cid2 = SAE_CONNID_ANY; |
342c141e A |
500 | int ifscope = 0; |
501 | int error = 0; | |
502 | ||
503 | if (verbose > 0) { | |
504 | char str[2 * INET6_ADDRSTRLEN]; | |
505 | ||
506 | ts_print(); | |
507 | ||
508 | sprint_sockaddr(str, sizeof(str), ares->ai_addr); | |
509 | printf("connectx(%s, %d, %d)\n", str, ifscope, cid1); | |
510 | } | |
89c4ed63 A |
511 | sa_endpoints_t sa; |
512 | bzero(&sa, sizeof(sa)); | |
513 | sa.sae_dstaddr = ares->ai_addr; | |
514 | sa.sae_dstaddrlen = ares->ai_addrlen; | |
515 | sa.sae_srcif = ifscope; | |
516 | ||
517 | error = connectx(sockfd, &sa, SAE_ASSOCID_ANY, 0, NULL, 0, NULL, &cid1); | |
342c141e A |
518 | if ((error != 0) && (errno != EPROTO)) { |
519 | err(EX_OSERR, "ERROR connecting"); | |
520 | } else if ((error != 0) && (errno == EPROTO)) { | |
89c4ed63 | 521 | ps = peeloff(sockfd, SAE_ASSOCID_ANY); |
342c141e A |
522 | |
523 | if (ps != -1) { | |
524 | close(sockfd); | |
525 | sockfd = ps; | |
526 | } | |
527 | peeled_off = 1; | |
528 | ts_print(); | |
529 | printf("%s: peeled off\n", __func__); | |
530 | } | |
531 | ||
342c141e A |
532 | iter = 0; |
533 | ||
534 | while (ntimes) { | |
535 | ||
536 | if ((iter == 0) && (peeled_off == 0)) { | |
537 | /* Add alternate path if available */ | |
538 | ||
539 | if (alt_addr_arg && alt_addr_arg[0] != 0) { | |
540 | retval = getaddrinfo(alt_addr_arg, alt_port_arg, &ahints, &altres); | |
541 | ||
542 | if (retval != 0) | |
543 | printf("client: alternate address resolution failed. \n"); | |
544 | else { | |
545 | printf("client: connecting to alternate address (ifscope %d)\n", ifscope); | |
546 | ||
547 | if (verbose > 0) { | |
548 | char str[2 * INET6_ADDRSTRLEN]; | |
549 | ||
550 | ts_print(); | |
551 | ||
552 | sprint_sockaddr(str, sizeof(str), altres->ai_addr); | |
553 | printf("connectx(%s, %d, %d)\n", str, ifscope, cid1); | |
554 | } | |
89c4ed63 A |
555 | sa_endpoints_t sa; |
556 | bzero(&sa, sizeof(sa)); | |
557 | sa.sae_srcif = ifscope; | |
558 | sa.sae_srcaddr = altres->ai_addr; | |
559 | sa.sae_srcaddrlen = altres->ai_addrlen; | |
560 | sa.sae_dstaddr = ares->ai_addr; | |
561 | sa.sae_dstaddrlen = ares->ai_addrlen; | |
342c141e | 562 | |
89c4ed63 | 563 | error = connectx(sockfd, &sa, SAE_ASSOCID_ANY, 0, NULL, 0, NULL, &cid2); |
342c141e A |
564 | if (error < 0) { |
565 | err(EX_OSERR, "ERROR setting up alternate path"); | |
566 | } | |
567 | } | |
568 | } | |
569 | ||
570 | } | |
571 | ||
572 | if ((iter == 10) && (connordrtest == 1)) { | |
573 | int retval = 0; | |
574 | ||
575 | socorder.sco_cid = cid2; | |
576 | socorder.sco_rank = 1; | |
577 | retval = ioctl(sockfd, SIOCSCONNORDER, &socorder); | |
578 | if (retval != 0) | |
579 | warn("Error in changing priority"); | |
580 | ||
581 | bzero(&socorder, sizeof(socorder)); | |
582 | socorder.sco_cid = cid2; | |
583 | retval = ioctl(sockfd, SIOCGCONNORDER, &socorder); | |
584 | printf("cid %d rank %d", socorder.sco_cid, socorder.sco_rank); | |
585 | ||
586 | socorder.sco_cid = cid1; | |
587 | socorder.sco_rank = 0; | |
588 | retval = ioctl(sockfd, SIOCSCONNORDER, &socorder); | |
589 | if (retval != 0) | |
590 | warn("Error in changing priority"); | |
591 | ||
592 | bzero(&socorder, sizeof(socorder)); | |
593 | socorder.sco_cid = cid1; | |
594 | retval = ioctl(sockfd, SIOCGCONNORDER, &socorder); | |
595 | printf("cid %d rank %d \n", socorder.sco_cid, socorder.sco_rank); | |
596 | } | |
597 | ||
598 | if (which_buf == 0) { | |
599 | buffer = buffer1; | |
600 | which_buf = 1; | |
601 | } else { | |
602 | buffer = buffer2; | |
603 | which_buf = 0; | |
604 | } | |
605 | ||
606 | while (bytes_to_rdwr) { | |
607 | if (verbose) { | |
608 | ts_print(); | |
609 | printf("writing %d bytes\n", bytes_to_rdwr); | |
610 | } | |
611 | n = write(sockfd, buffer, bytes_to_rdwr); | |
612 | if (n <= 0) { | |
613 | err(EX_OSERR, "ERROR writing to socket"); | |
614 | } | |
615 | if (n <= bytes_to_rdwr) | |
616 | bytes_to_rdwr -= n; | |
617 | else { | |
618 | errx(EX_DATAERR, "ERROR extra data write %zd %d\n", n, bytes_to_rdwr); | |
619 | } | |
620 | } | |
621 | bytes_to_rdwr = rsplen; | |
622 | while (bytes_to_rdwr) { | |
623 | if (verbose) { | |
624 | ts_print(); | |
625 | printf("reading %d bytes\n", rsplen); | |
626 | } | |
627 | n = read(sockfd, buffer3, rsplen); | |
628 | ||
629 | if (n <= 0) { | |
630 | err(EX_OSERR, "ERROR reading from socket"); | |
631 | } | |
632 | if (n <= bytes_to_rdwr) | |
633 | bytes_to_rdwr -= n; | |
634 | else { | |
635 | errx(EX_DATAERR, "ERROR extra bytes read n:%zd expected:%d\n", n, bytes_to_rdwr); | |
636 | } | |
637 | } | |
638 | bytes_to_rdwr = reqlen; | |
639 | ntimes--; | |
640 | iter++; | |
641 | } | |
642 | ||
643 | printf("client: Req size %d Rsp size %d Read/Write %d times \n", reqlen, rsplen, iter); | |
644 | ||
645 | showmpinfo(sockfd); | |
646 | ||
647 | if ((!longlived) || (peeled_off == 1)) { | |
648 | if (verbose) { | |
649 | ts_print(); | |
650 | printf("close(%d)\n", sockfd); | |
651 | } | |
652 | close(sockfd); | |
653 | } else { | |
654 | printf("Longlived countdown # %d. \n", longlived); | |
655 | if (verbose) { | |
656 | ts_print(); | |
657 | printf("disconnectx(%d, %d)\n", sockfd, cid1); | |
658 | } | |
89c4ed63 A |
659 | disconnectx(sockfd, SAE_ASSOCID_ANY, cid1); |
660 | if (cid2 != SAE_CONNID_ANY) { | |
342c141e A |
661 | if (verbose) { |
662 | ts_print(); | |
663 | printf("disconnectx(%d, %d)\n", sockfd, cid2); | |
664 | } | |
89c4ed63 | 665 | disconnectx(sockfd, SAE_ASSOCID_ANY, cid2); |
342c141e A |
666 | } |
667 | if (!nowaitforjoin) { | |
668 | if (verbose) { | |
669 | ts_print(); | |
670 | printf("sleep(10)\n"); | |
671 | } | |
672 | sleep(10); | |
673 | } | |
674 | longlived--; | |
675 | ||
676 | ntimes = atoi(ntimes_arg); | |
677 | ||
678 | /* If fastjoin must be tested, write some data before doing the next connectx() */ | |
679 | bytes_to_rdwr = reqlen / 2; | |
680 | if (verbose) { | |
681 | ts_print(); | |
682 | printf("fastjoin writing %d bytes\n", bytes_to_rdwr); | |
683 | } | |
684 | n = write(sockfd, buffer, bytes_to_rdwr); | |
685 | if (n <= 0) { | |
686 | warnx("Fastjoin: Error writing to socket. \n"); | |
687 | } else { | |
688 | bytes_to_rdwr = reqlen - (int)n; | |
689 | printf("FastJoin: Wrote %zd bytes, remaining %d of %d \n", n, bytes_to_rdwr, reqlen); | |
690 | } | |
691 | ||
692 | goto connect_again; | |
693 | } | |
694 | if (ares) | |
695 | freeaddrinfo(ares); | |
696 | if (altres) | |
697 | freeaddrinfo(altres); | |
698 | return 0; | |
699 | } | |
700 | ||
701 | #define CIF_BITS \ | |
702 | "\020\1CONNECTING\2CONNECTED\3DISCONNECTING\4DISCONNECTED\5BOUND_IF"\ | |
703 | "\6BOUND_IP\7BOUND_PORT\10PREFERRED\11MP_CAPABLE\12MP_READY" \ | |
704 | "\13MP_DEGRADED" | |
705 | ||
706 | /* | |
707 | * Print a value a la the %b format of the kernel's printf | |
708 | */ | |
709 | static void | |
710 | printb(const char *s, unsigned v, const char *bits) | |
711 | { | |
712 | int i, any = 0; | |
713 | char c; | |
714 | ||
715 | if (bits && *bits == 8) | |
716 | printf("%s=%o", s, v); | |
717 | else | |
718 | printf("%s=%x", s, v); | |
719 | bits++; | |
720 | if (bits) { | |
721 | putchar('<'); | |
722 | while ((i = *bits++) != '\0') { | |
723 | if (v & (1 << (i-1))) { | |
724 | if (any) | |
725 | putchar(','); | |
726 | any = 1; | |
727 | for (; (c = *bits) > 32; bits++) | |
728 | putchar(c); | |
729 | } else { | |
730 | for (; *bits > 32; bits++) | |
731 | ; | |
732 | } | |
733 | } | |
734 | putchar('>'); | |
735 | } | |
736 | } | |
737 | ||
738 | static int | |
89c4ed63 | 739 | showconninfo(int s, sae_connid_t cid) |
342c141e A |
740 | { |
741 | char buf[INET6_ADDRSTRLEN]; | |
742 | conninfo_t *cfo = NULL; | |
743 | int err; | |
744 | ||
745 | err = copyconninfo(s, cid, &cfo); | |
746 | if (err != 0) { | |
747 | printf("getconninfo failed for cid %d\n", cid); | |
748 | goto out; | |
749 | } | |
750 | ||
751 | printf("%6d:\t", cid); | |
752 | printb("flags", cfo->ci_flags, CIF_BITS); | |
753 | printf("\n"); | |
754 | //printf("\toutif %s\n", if_indextoname(cfo->ci_ifindex, buf)); | |
755 | #if 1 | |
756 | if (cfo->ci_src != NULL) { | |
757 | printf("\tsrc %s port %d\n", inet_ntop(cfo->ci_src->sa_family, | |
758 | (cfo->ci_src->sa_family == AF_INET) ? | |
759 | (void *)&((struct sockaddr_in *)cfo->ci_src)-> | |
760 | sin_addr.s_addr : | |
761 | (void *)&((struct sockaddr_in6 *)cfo->ci_src)->sin6_addr, | |
762 | buf, sizeof (buf)), | |
763 | (cfo->ci_src->sa_family == AF_INET) ? | |
764 | ntohs(((struct sockaddr_in *)cfo->ci_src)->sin_port) : | |
765 | ntohs(((struct sockaddr_in6 *)cfo->ci_src)->sin6_port)); | |
766 | } | |
767 | if (cfo->ci_dst != NULL) { | |
768 | printf("\tdst %s port %d\n", inet_ntop(cfo->ci_dst->sa_family, | |
769 | (cfo->ci_dst->sa_family == AF_INET) ? | |
770 | (void *)&((struct sockaddr_in *)cfo->ci_dst)-> | |
771 | sin_addr.s_addr : | |
772 | (void *)&((struct sockaddr_in6 *)cfo->ci_dst)->sin6_addr, | |
773 | buf, sizeof (buf)), | |
774 | (cfo->ci_dst->sa_family == AF_INET) ? | |
775 | ntohs(((struct sockaddr_in *)cfo->ci_dst)->sin_port) : | |
776 | ntohs(((struct sockaddr_in6 *)cfo->ci_dst)->sin6_port)); | |
777 | } | |
778 | if (cfo->ci_aux_data != NULL) { | |
779 | switch (cfo->ci_aux_type) { | |
780 | case CIAUX_TCP: | |
781 | printf("\tTCP aux info available\n"); | |
782 | break; | |
783 | default: | |
784 | printf("\tUnknown aux type %d\n", cfo->ci_aux_type); | |
785 | break; | |
786 | } | |
787 | } | |
788 | #endif | |
789 | out: | |
790 | if (cfo != NULL) | |
791 | freeconninfo(cfo); | |
792 | ||
793 | return (err); | |
794 | } | |
795 | ||
796 | static void | |
797 | showmpinfo(int s) | |
798 | { | |
89c4ed63 A |
799 | uint32_t aid_cnt = 0, cid_cnt = 0; |
800 | sae_associd_t *aid = NULL; | |
801 | sae_connid_t *cid = NULL; | |
802 | int i, error = 0; | |
342c141e A |
803 | |
804 | error = copyassocids(s, &aid, &aid_cnt); | |
805 | if (error != 0) { | |
806 | printf("copyassocids failed\n"); | |
807 | goto done; | |
808 | } else { | |
809 | printf("found %d associations", aid_cnt); | |
810 | if (aid_cnt > 0) { | |
811 | printf(" with IDs:"); | |
812 | for (i = 0; i < aid_cnt; i++) | |
813 | printf(" %d\n", aid[i]); | |
814 | } | |
815 | printf("\n"); | |
816 | } | |
817 | ||
818 | /* just do an association for now */ | |
89c4ed63 | 819 | error = copyconnids(s, SAE_ASSOCID_ANY, &cid, &cid_cnt); |
342c141e A |
820 | if (error != 0) { |
821 | warn("getconnids failed\n"); | |
822 | goto done; | |
823 | } else { | |
824 | printf("found %d connections", cid_cnt); | |
825 | if (cid_cnt > 0) { | |
826 | printf(":\n"); | |
827 | for (i = 0; i < cid_cnt; i++) { | |
828 | if (showconninfo(s, cid[i]) != 0) | |
829 | break; | |
830 | } | |
831 | } | |
832 | printf("\n"); | |
833 | } | |
834 | ||
835 | done: | |
836 | if (aid != NULL) | |
837 | freeassocids(aid); | |
838 | if (cid != NULL) | |
839 | freeconnids(cid); | |
840 | } |