2 * Copyright (c) 2012-2014 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * The Regents of the University of California. All rights reserved.
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
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.
50 // Created by Anumita Biswas on 7/17/12.
58 #include <sys/types.h>
59 #include <sys/socket.h>
60 #include <sys/ioctl.h>
62 #include <netinet/in.h>
65 #include <arpa/inet.h>
72 struct so_cordreq socorder
;
73 static void showmpinfo(int s
);
75 #define MSG_HDR "Message Header"
76 #define RESPONSE "I got your message"
78 static int verbose
= 0;
80 static int32_t thiszone
= 0; /* time difference with gmt */
82 char *setup_buffer1(int bufsz
)
92 strlcpy(buf
, MSG_HDR
, bufsz
);
94 for (i
= sizeof(MSG_HDR
); i
< bufsz
; i
++) {
103 char *setup_buffer2(int bufsz
)
114 strlcpy(buf
, MSG_HDR
, bufsz
);
116 for (i
= sizeof(MSG_HDR
); i
< bufsz
; i
++) {
125 char *setup_buffer3(int bufsz
)
138 * Returns the difference between gmt and local time in seconds.
139 * Use gmtime() and localtime() to keep things simple.
140 * from tcpdump/gmt2local.c
146 struct tm
*gmt
, *loc
;
154 dt
= (loc
->tm_hour
- gmt
->tm_hour
) * 60 * 60 +
155 (loc
->tm_min
- gmt
->tm_min
) * 60;
158 * If the year or julian day is different, we span 00:00 GMT
159 * and must add or subtract a day. Check the year first to
160 * avoid problems when the julian day wraps.
162 dir
= loc
->tm_year
- gmt
->tm_year
;
164 dir
= loc
->tm_yday
- gmt
->tm_yday
;
165 dt
+= dir
* 24 * 60 * 60;
171 * Print the timestamp
172 * from tcpdump/util.c
180 gettimeofday(&tv
, NULL
);
183 s
= (tv
.tv_sec
+ thiszone
) % 86400;
184 printf("%02d:%02d:%02d.%06u ", s
/ 3600, (s
% 3600) / 60, s
% 60,
185 (u_int32_t
)tv
.tv_usec
);
189 basename(const char * str
)
191 const char *last_slash
= strrchr(str
, '/');
193 if (last_slash
== NULL
)
196 return (last_slash
+ 1);
201 const char *description
;
205 struct option_desc option_desc_list
[] = {
206 { "--host addr", "address of server to connect to", 1 },
207 { "--port n", "port of server to connect to", 1 },
208 { "--reqlen n", "length of request (256 by default)", 0 },
209 { "--rsplen n", "length of response (256 by default)", 0 },
210 { "--ntimes n", "number of time to send request (1 by default)", 0 },
211 { "--alt_addr addr", "alternate server to connect to", 0 },
212 { "--verbose", "increase verbosity", 0 },
213 { "--help", "display this help", 0 },
215 { NULL
, NULL
, 0 } /* Mark end of list */
219 usage(const char *cmd
)
221 struct option_desc
*option_desc
;
222 char *usage_str
= malloc(LINE_MAX
);
225 if (usage_str
== NULL
)
226 err(1, "%s: malloc(%d)", __func__
, LINE_MAX
);
228 usage_len
= snprintf(usage_str
, LINE_MAX
, "# usage: %s ", basename(cmd
));
230 for (option_desc
= option_desc_list
; option_desc
->option
!= NULL
; option_desc
++) {
233 if (option_desc
->required
)
234 len
= snprintf(usage_str
+ usage_len
, LINE_MAX
- usage_len
, "%s ", option_desc
->option
);
236 len
= snprintf(usage_str
+ usage_len
, LINE_MAX
- usage_len
, "[%s] ", option_desc
->option
);
238 err(1, "%s: snprintf(", __func__
);
241 if (usage_len
> LINE_MAX
)
244 printf("%s\n", usage_str
);
245 printf("options:\n");
247 for (option_desc
= option_desc_list
; option_desc
->option
!= NULL
; option_desc
++) {
248 printf(" %-24s # %s\n", option_desc
->option
, option_desc
->description
);
251 printf("# legacy usage: ");
254 static struct option longopts
[] = {
255 { "host", required_argument
, NULL
, 'c' },
256 { "port", required_argument
, NULL
, 'p' },
257 { "reqlen", required_argument
, NULL
, 'r' },
258 { "rsplen", required_argument
, NULL
, 'R' },
259 { "ntimes", required_argument
, NULL
, 'n' },
260 { "alt_addr", required_argument
, NULL
, 'a' },
261 { "help", no_argument
, NULL
, 'h' },
262 { "verbose", no_argument
, NULL
, 'v' },
263 { "quiet", no_argument
, NULL
, 'q' },
268 sprint_sockaddr(char *str
, socklen_t strlen
, struct sockaddr
*sa
)
272 if (sa
->sa_family
== AF_INET
) {
273 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
274 char str4
[INET_ADDRSTRLEN
];
276 inet_ntop(AF_INET
, &sin
->sin_addr
, str4
, sizeof(str4
));
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
];
285 inet_ntop(AF_INET6
, &sin6
->sin6_addr
, str6
, sizeof(str6
));
287 if (sin6
->sin6_scope_id
== 0)
290 if_indextoname(sin6
->sin6_scope_id
, ifname
);
291 snprintf(scopestr
, sizeof(scopestr
), "%%%s", ifname
);
294 retval
= snprintf(str
, strlen
, "%s%s:%u",
297 ntohs(sin6
->sin6_port
));
302 int main(int argc
, char * const *argv
)
313 struct addrinfo
*ares
= NULL
, ahints
;
314 struct addrinfo
*altres
= NULL
;
317 sae_connid_t cid1
, cid2
;
321 const char *host_arg
= NULL
;
322 const char *port_arg
= NULL
;
323 const char *reqlen_arg
= "256";
324 const char *rsplen_arg
= "256";
325 const char *ntimes_arg
= "1";
326 const char *alt_addr_arg
= NULL
;
327 const char *alt_port_arg
= "0";
330 thiszone
= gmt2local(0);
332 while ((ch
= getopt_long(argc
, argv
, "a:c:hn:p:qr:R:v", longopts
, NULL
)) != -1) {
336 alt_addr_arg
= optarg
;
369 reqlen_arg
= argv
[3];
370 rsplen_arg
= argv
[4];
371 ntimes_arg
= argv
[5];
372 alt_addr_arg
= argv
[6];
379 if (host_arg
== NULL
)
380 errx(EX_USAGE
, "missing required host option\n");
382 if (port_arg
== NULL
)
383 errx(EX_USAGE
, "missing required port option\n");
384 portno
= atoi(port_arg
);
385 if (portno
< 0 || portno
> 65535)
386 errx(EX_USAGE
, "invalid port %s\n", port_arg
);
388 if (reqlen_arg
!= NULL
) {
389 reqlen
= atoi(reqlen_arg
);
390 if (reqlen
< 0 || reqlen
> 1024 * 1024)
391 errx(EX_USAGE
, "invalid request length %s\n", reqlen_arg
);
394 if (rsplen_arg
!= NULL
) {
395 rsplen
= atoi(rsplen_arg
);
396 if (rsplen
< 0 || rsplen
> 1024 * 1024)
397 errx(EX_USAGE
, "invalid response length %s\n", rsplen_arg
);
400 if (ntimes_arg
!= NULL
) {
401 ntimes
= atoi(ntimes_arg
);
403 errx(EX_USAGE
, "invalid ntimes option %s\n", ntimes_arg
);
406 buffer1
= setup_buffer1(reqlen
);
408 printf("client: failed to alloc buffer space \n");
412 buffer2
= setup_buffer2(reqlen
);
414 printf("client: failed to alloc buffer space \n");
418 buffer3
= setup_buffer3(rsplen
);
420 printf("client: failed to alloc buffer space \n");
425 printf("host: %s port: %s reqlen: %d rsplen: %d ntimes: %d alt_addr: %s\n",
426 host_arg
, port_arg
, reqlen
, rsplen
, ntimes
, alt_addr_arg
);
428 sockfd
= socket(AF_MULTIPATH
, SOCK_STREAM
, 0);
430 err(EX_OSERR
, "ERROR opening socket");
432 memset(&ahints
, 0, sizeof(struct addrinfo
));
433 ahints
.ai_family
= AF_INET
;
434 ahints
.ai_socktype
= SOCK_STREAM
;
435 ahints
.ai_protocol
= IPPROTO_TCP
;
437 retval
= getaddrinfo(host_arg
, port_arg
, &ahints
, &ares
);
439 printf("getaddrinfo(%s, %s) failed %d\n", host_arg
, port_arg
, retval
);
441 bytes_to_rdwr
= reqlen
;
443 cid1
= cid2
= SAE_CONNID_ANY
;
448 char str
[2 * INET6_ADDRSTRLEN
];
452 sprint_sockaddr(str
, sizeof(str
), ares
->ai_addr
);
453 printf("connectx(%s, %d, %d)\n", str
, ifscope
, cid1
);
456 bzero(&sa
, sizeof(sa
));
457 sa
.sae_dstaddr
= ares
->ai_addr
;
458 sa
.sae_dstaddrlen
= ares
->ai_addrlen
;
459 sa
.sae_srcif
= ifscope
;
461 error
= connectx(sockfd
, &sa
, SAE_ASSOCID_ANY
, 0, NULL
, 0, NULL
, &cid1
);
463 err(EX_OSERR
, "ERROR connecting");
469 /* Add alternate path if available */
471 if (alt_addr_arg
&& alt_addr_arg
[0] != 0) {
472 retval
= getaddrinfo(alt_addr_arg
, alt_port_arg
, &ahints
, &altres
);
475 printf("client: alternate address resolution failed. \n");
477 printf("client: connecting to alternate address (ifscope %d)\n", ifscope
);
480 char str
[2 * INET6_ADDRSTRLEN
];
484 sprint_sockaddr(str
, sizeof(str
), altres
->ai_addr
);
485 printf("connectx(%s, %d, %d)\n", str
, ifscope
, cid1
);
488 bzero(&sa
, sizeof(sa
));
489 sa
.sae_srcif
= ifscope
;
490 sa
.sae_srcaddr
= altres
->ai_addr
;
491 sa
.sae_srcaddrlen
= altres
->ai_addrlen
;
492 sa
.sae_dstaddr
= ares
->ai_addr
;
493 sa
.sae_dstaddrlen
= ares
->ai_addrlen
;
495 error
= connectx(sockfd
, &sa
, SAE_ASSOCID_ANY
, 0, NULL
, 0, NULL
, &cid2
);
497 err(EX_OSERR
, "ERROR setting up alternate path");
503 if (which_buf
== 0) {
511 while (bytes_to_rdwr
) {
514 printf("writing %d bytes\n", bytes_to_rdwr
);
516 n
= write(sockfd
, buffer
, bytes_to_rdwr
);
518 err(EX_OSERR
, "ERROR writing to socket");
520 if (n
<= bytes_to_rdwr
)
523 errx(EX_DATAERR
, "ERROR extra data write %zd %d\n", n
, bytes_to_rdwr
);
526 bytes_to_rdwr
= rsplen
;
527 while (bytes_to_rdwr
) {
530 printf("reading %d bytes\n", rsplen
);
532 n
= read(sockfd
, buffer3
, rsplen
);
535 err(EX_OSERR
, "ERROR reading from socket");
537 if (n
<= bytes_to_rdwr
)
540 errx(EX_DATAERR
, "ERROR extra bytes read n:%zd expected:%d\n", n
, bytes_to_rdwr
);
543 bytes_to_rdwr
= reqlen
;
548 printf("client: Req size %d Rsp size %d Read/Write %d times \n", reqlen
, rsplen
, iter
);
554 printf("close(%d)\n", sockfd
);
560 freeaddrinfo(altres
);
565 "\020\1CONNECTING\2CONNECTED\3DISCONNECTING\4DISCONNECTED\5BOUND_IF"\
566 "\6BOUND_IP\7BOUND_PORT\10PREFERRED\11MP_CAPABLE\12MP_READY" \
570 * Print a value a la the %b format of the kernel's printf
573 printb(const char *s
, unsigned v
, const char *bits
)
578 if (bits
&& *bits
== 8)
579 printf("%s=%o", s
, v
);
581 printf("%s=%x", s
, v
);
585 while ((i
= *bits
++) != '\0') {
586 if (v
& (1 << (i
-1))) {
590 for (; (c
= *bits
) > 32; bits
++)
593 for (; *bits
> 32; bits
++)
602 showconninfo(int s
, sae_connid_t cid
)
604 char buf
[INET6_ADDRSTRLEN
];
605 conninfo_t
*cfo
= NULL
;
608 err
= copyconninfo(s
, cid
, &cfo
);
610 printf("getconninfo failed for cid %d\n", cid
);
614 printf("%6d:\t", cid
);
615 printb("flags", cfo
->ci_flags
, CIF_BITS
);
618 if (cfo
->ci_src
!= NULL
) {
619 printf("\tsrc %s port %d\n", inet_ntop(cfo
->ci_src
->sa_family
,
620 (cfo
->ci_src
->sa_family
== AF_INET
) ?
621 (void *)&((struct sockaddr_in
*)cfo
->ci_src
)->
623 (void *)&((struct sockaddr_in6
*)cfo
->ci_src
)->sin6_addr
,
625 (cfo
->ci_src
->sa_family
== AF_INET
) ?
626 ntohs(((struct sockaddr_in
*)cfo
->ci_src
)->sin_port
) :
627 ntohs(((struct sockaddr_in6
*)cfo
->ci_src
)->sin6_port
));
629 if (cfo
->ci_dst
!= NULL
) {
630 printf("\tdst %s port %d\n", inet_ntop(cfo
->ci_dst
->sa_family
,
631 (cfo
->ci_dst
->sa_family
== AF_INET
) ?
632 (void *)&((struct sockaddr_in
*)cfo
->ci_dst
)->
634 (void *)&((struct sockaddr_in6
*)cfo
->ci_dst
)->sin6_addr
,
636 (cfo
->ci_dst
->sa_family
== AF_INET
) ?
637 ntohs(((struct sockaddr_in
*)cfo
->ci_dst
)->sin_port
) :
638 ntohs(((struct sockaddr_in6
*)cfo
->ci_dst
)->sin6_port
));
640 if (cfo
->ci_aux_data
!= NULL
) {
641 switch (cfo
->ci_aux_type
) {
643 printf("\tTCP aux info available\n");
646 printf("\tUnknown aux type %d\n", cfo
->ci_aux_type
);
660 uint32_t aid_cnt
= 0, cid_cnt
= 0;
661 sae_associd_t
*aid
= NULL
;
662 sae_connid_t
*cid
= NULL
;
665 error
= copyassocids(s
, &aid
, &aid_cnt
);
667 printf("copyassocids failed\n");
670 printf("found %d associations", aid_cnt
);
672 printf(" with IDs:");
673 for (i
= 0; i
< aid_cnt
; i
++)
674 printf(" %d\n", aid
[i
]);
679 /* just do an association for now */
680 error
= copyconnids(s
, SAE_ASSOCID_ANY
, &cid
, &cid_cnt
);
682 warn("getconnids failed\n");
685 printf("found %d connections", cid_cnt
);
688 for (i
= 0; i
< cid_cnt
; i
++) {
689 if (showconninfo(s
, cid
[i
]) != 0)