]> git.saurik.com Git - apple/network_cmds.git/blob - mptcp_client/mptcp_client.c
network_cmds-457.tar.gz
[apple/network_cmds.git] / mptcp_client / mptcp_client.c
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;
320 connid_t cid1, cid2;
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
499 cid1 = cid2 = CONNID_ANY;
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 }
511
512 error = connectx(sockfd, NULL, 0, ares->ai_addr,
513 ares->ai_addrlen, ifscope, ASSOCID_ANY, &cid1);
514 if ((error != 0) && (errno != EPROTO)) {
515 err(EX_OSERR, "ERROR connecting");
516 } else if ((error != 0) && (errno == EPROTO)) {
517 ps = peeloff(sockfd, ASSOCID_ANY);
518
519 if (ps != -1) {
520 close(sockfd);
521 sockfd = ps;
522 }
523 peeled_off = 1;
524 ts_print();
525 printf("%s: peeled off\n", __func__);
526 }
527
528
529 iter = 0;
530
531 while (ntimes) {
532
533 if ((iter == 0) && (peeled_off == 0)) {
534 /* Add alternate path if available */
535
536 if (alt_addr_arg && alt_addr_arg[0] != 0) {
537 retval = getaddrinfo(alt_addr_arg, alt_port_arg, &ahints, &altres);
538
539 if (retval != 0)
540 printf("client: alternate address resolution failed. \n");
541 else {
542 printf("client: connecting to alternate address (ifscope %d)\n", ifscope);
543
544 if (verbose > 0) {
545 char str[2 * INET6_ADDRSTRLEN];
546
547 ts_print();
548
549 sprint_sockaddr(str, sizeof(str), altres->ai_addr);
550 printf("connectx(%s, %d, %d)\n", str, ifscope, cid1);
551 }
552
553 error = connectx(sockfd, altres->ai_addr, altres->ai_addrlen,
554 ares->ai_addr, ares->ai_addrlen,
555 ifscope, ASSOCID_ANY, &cid2);
556 if (error < 0) {
557 err(EX_OSERR, "ERROR setting up alternate path");
558 }
559 }
560 }
561
562 }
563
564 if ((iter == 10) && (connordrtest == 1)) {
565 int retval = 0;
566
567 socorder.sco_cid = cid2;
568 socorder.sco_rank = 1;
569 retval = ioctl(sockfd, SIOCSCONNORDER, &socorder);
570 if (retval != 0)
571 warn("Error in changing priority");
572
573 bzero(&socorder, sizeof(socorder));
574 socorder.sco_cid = cid2;
575 retval = ioctl(sockfd, SIOCGCONNORDER, &socorder);
576 printf("cid %d rank %d", socorder.sco_cid, socorder.sco_rank);
577
578 socorder.sco_cid = cid1;
579 socorder.sco_rank = 0;
580 retval = ioctl(sockfd, SIOCSCONNORDER, &socorder);
581 if (retval != 0)
582 warn("Error in changing priority");
583
584 bzero(&socorder, sizeof(socorder));
585 socorder.sco_cid = cid1;
586 retval = ioctl(sockfd, SIOCGCONNORDER, &socorder);
587 printf("cid %d rank %d \n", socorder.sco_cid, socorder.sco_rank);
588 }
589
590 if (which_buf == 0) {
591 buffer = buffer1;
592 which_buf = 1;
593 } else {
594 buffer = buffer2;
595 which_buf = 0;
596 }
597
598 while (bytes_to_rdwr) {
599 if (verbose) {
600 ts_print();
601 printf("writing %d bytes\n", bytes_to_rdwr);
602 }
603 n = write(sockfd, buffer, bytes_to_rdwr);
604 if (n <= 0) {
605 err(EX_OSERR, "ERROR writing to socket");
606 }
607 if (n <= bytes_to_rdwr)
608 bytes_to_rdwr -= n;
609 else {
610 errx(EX_DATAERR, "ERROR extra data write %zd %d\n", n, bytes_to_rdwr);
611 }
612 }
613 bytes_to_rdwr = rsplen;
614 while (bytes_to_rdwr) {
615 if (verbose) {
616 ts_print();
617 printf("reading %d bytes\n", rsplen);
618 }
619 n = read(sockfd, buffer3, rsplen);
620
621 if (n <= 0) {
622 err(EX_OSERR, "ERROR reading from socket");
623 }
624 if (n <= bytes_to_rdwr)
625 bytes_to_rdwr -= n;
626 else {
627 errx(EX_DATAERR, "ERROR extra bytes read n:%zd expected:%d\n", n, bytes_to_rdwr);
628 }
629 }
630 bytes_to_rdwr = reqlen;
631 ntimes--;
632 iter++;
633 }
634
635 printf("client: Req size %d Rsp size %d Read/Write %d times \n", reqlen, rsplen, iter);
636
637 showmpinfo(sockfd);
638
639 if ((!longlived) || (peeled_off == 1)) {
640 if (verbose) {
641 ts_print();
642 printf("close(%d)\n", sockfd);
643 }
644 close(sockfd);
645 } else {
646 printf("Longlived countdown # %d. \n", longlived);
647 if (verbose) {
648 ts_print();
649 printf("disconnectx(%d, %d)\n", sockfd, cid1);
650 }
651 disconnectx(sockfd, ASSOCID_ANY, cid1);
652 if (cid2 != CONNID_ANY) {
653 if (verbose) {
654 ts_print();
655 printf("disconnectx(%d, %d)\n", sockfd, cid2);
656 }
657 disconnectx(sockfd, ASSOCID_ANY, cid2);
658 }
659 if (!nowaitforjoin) {
660 if (verbose) {
661 ts_print();
662 printf("sleep(10)\n");
663 }
664 sleep(10);
665 }
666 longlived--;
667
668 ntimes = atoi(ntimes_arg);
669
670 /* If fastjoin must be tested, write some data before doing the next connectx() */
671 bytes_to_rdwr = reqlen / 2;
672 if (verbose) {
673 ts_print();
674 printf("fastjoin writing %d bytes\n", bytes_to_rdwr);
675 }
676 n = write(sockfd, buffer, bytes_to_rdwr);
677 if (n <= 0) {
678 warnx("Fastjoin: Error writing to socket. \n");
679 } else {
680 bytes_to_rdwr = reqlen - (int)n;
681 printf("FastJoin: Wrote %zd bytes, remaining %d of %d \n", n, bytes_to_rdwr, reqlen);
682 }
683
684 goto connect_again;
685 }
686 if (ares)
687 freeaddrinfo(ares);
688 if (altres)
689 freeaddrinfo(altres);
690 return 0;
691 }
692
693 #define CIF_BITS \
694 "\020\1CONNECTING\2CONNECTED\3DISCONNECTING\4DISCONNECTED\5BOUND_IF"\
695 "\6BOUND_IP\7BOUND_PORT\10PREFERRED\11MP_CAPABLE\12MP_READY" \
696 "\13MP_DEGRADED"
697
698 /*
699 * Print a value a la the %b format of the kernel's printf
700 */
701 static void
702 printb(const char *s, unsigned v, const char *bits)
703 {
704 int i, any = 0;
705 char c;
706
707 if (bits && *bits == 8)
708 printf("%s=%o", s, v);
709 else
710 printf("%s=%x", s, v);
711 bits++;
712 if (bits) {
713 putchar('<');
714 while ((i = *bits++) != '\0') {
715 if (v & (1 << (i-1))) {
716 if (any)
717 putchar(',');
718 any = 1;
719 for (; (c = *bits) > 32; bits++)
720 putchar(c);
721 } else {
722 for (; *bits > 32; bits++)
723 ;
724 }
725 }
726 putchar('>');
727 }
728 }
729
730 static int
731 showconninfo(int s, connid_t cid)
732 {
733 char buf[INET6_ADDRSTRLEN];
734 conninfo_t *cfo = NULL;
735 int err;
736
737 err = copyconninfo(s, cid, &cfo);
738 if (err != 0) {
739 printf("getconninfo failed for cid %d\n", cid);
740 goto out;
741 }
742
743 printf("%6d:\t", cid);
744 printb("flags", cfo->ci_flags, CIF_BITS);
745 printf("\n");
746 //printf("\toutif %s\n", if_indextoname(cfo->ci_ifindex, buf));
747 #if 1
748 if (cfo->ci_src != NULL) {
749 printf("\tsrc %s port %d\n", inet_ntop(cfo->ci_src->sa_family,
750 (cfo->ci_src->sa_family == AF_INET) ?
751 (void *)&((struct sockaddr_in *)cfo->ci_src)->
752 sin_addr.s_addr :
753 (void *)&((struct sockaddr_in6 *)cfo->ci_src)->sin6_addr,
754 buf, sizeof (buf)),
755 (cfo->ci_src->sa_family == AF_INET) ?
756 ntohs(((struct sockaddr_in *)cfo->ci_src)->sin_port) :
757 ntohs(((struct sockaddr_in6 *)cfo->ci_src)->sin6_port));
758 }
759 if (cfo->ci_dst != NULL) {
760 printf("\tdst %s port %d\n", inet_ntop(cfo->ci_dst->sa_family,
761 (cfo->ci_dst->sa_family == AF_INET) ?
762 (void *)&((struct sockaddr_in *)cfo->ci_dst)->
763 sin_addr.s_addr :
764 (void *)&((struct sockaddr_in6 *)cfo->ci_dst)->sin6_addr,
765 buf, sizeof (buf)),
766 (cfo->ci_dst->sa_family == AF_INET) ?
767 ntohs(((struct sockaddr_in *)cfo->ci_dst)->sin_port) :
768 ntohs(((struct sockaddr_in6 *)cfo->ci_dst)->sin6_port));
769 }
770 if (cfo->ci_aux_data != NULL) {
771 switch (cfo->ci_aux_type) {
772 case CIAUX_TCP:
773 printf("\tTCP aux info available\n");
774 break;
775 default:
776 printf("\tUnknown aux type %d\n", cfo->ci_aux_type);
777 break;
778 }
779 }
780 #endif
781 out:
782 if (cfo != NULL)
783 freeconninfo(cfo);
784
785 return (err);
786 }
787
788 static void
789 showmpinfo(int s)
790 {
791 uint32_t aid_cnt, cid_cnt;
792 associd_t *aid = NULL;
793 connid_t *cid = NULL;
794 int i, error;
795
796 error = copyassocids(s, &aid, &aid_cnt);
797 if (error != 0) {
798 printf("copyassocids failed\n");
799 goto done;
800 } else {
801 printf("found %d associations", aid_cnt);
802 if (aid_cnt > 0) {
803 printf(" with IDs:");
804 for (i = 0; i < aid_cnt; i++)
805 printf(" %d\n", aid[i]);
806 }
807 printf("\n");
808 }
809
810 /* just do an association for now */
811 error = copyconnids(s, ASSOCID_ANY, &cid, &cid_cnt);
812 if (error != 0) {
813 warn("getconnids failed\n");
814 goto done;
815 } else {
816 printf("found %d connections", cid_cnt);
817 if (cid_cnt > 0) {
818 printf(":\n");
819 for (i = 0; i < cid_cnt; i++) {
820 if (showconninfo(s, cid[i]) != 0)
821 break;
822 }
823 }
824 printf("\n");
825 }
826
827 done:
828 if (aid != NULL)
829 freeassocids(aid);
830 if (cid != NULL)
831 freeconnids(cid);
832 }