]> git.saurik.com Git - apple/network_cmds.git/blame - mptcp_client/mptcp_client.c
network_cmds-511.50.3.tar.gz
[apple/network_cmds.git] / mptcp_client / mptcp_client.c
CommitLineData
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
72struct so_cordreq socorder;
73static void showmpinfo(int s);
74
75#define MSG_HDR "Message Header"
76#define RESPONSE "I got your message"
77
78static int verbose = 0;
79
80static int32_t thiszone = 0; /* time difference with gmt */
81
82char* 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
99char* 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
117char *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 */
131static int32_t
132gmt2local(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 */
163static void
164ts_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
177static const char *
178basename(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
188struct option_desc {
189 const char *option;
190 const char *description;
191 int required;
192};
193
194struct 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
211static void
212usage(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
249static 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
267static int
268sprint_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
302int 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;
497connect_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 */
709static void
710printb(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
738static int
89c4ed63 739showconninfo(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
789out:
790 if (cfo != NULL)
791 freeconninfo(cfo);
792
793 return (err);
794}
795
796static void
797showmpinfo(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
835done:
836 if (aid != NULL)
837 freeassocids(aid);
838 if (cid != NULL)
839 freeconnids(cid);
840}