diff options
Diffstat (limited to 'network_cmds/mptcp_client')
-rw-r--r-- | network_cmds/mptcp_client/conn_lib.c | 233 | ||||
-rw-r--r-- | network_cmds/mptcp_client/conn_lib.h | 53 | ||||
-rw-r--r-- | network_cmds/mptcp_client/mptcp_client.1 | 21 | ||||
-rw-r--r-- | network_cmds/mptcp_client/mptcp_client.c | 701 |
4 files changed, 1008 insertions, 0 deletions
diff --git a/network_cmds/mptcp_client/conn_lib.c b/network_cmds/mptcp_client/conn_lib.c new file mode 100644 index 0000000..1c83915 --- /dev/null +++ b/network_cmds/mptcp_client/conn_lib.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2012-2014 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +// +// Created by Anumita Biswas on 10/30/12. +// + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <errno.h> + + +#include "conn_lib.h" + +int +copyassocids(int s, sae_associd_t **aidpp, uint32_t *cnt) +{ + struct so_aidreq aidr; + sae_associd_t *buf; + int err; + + if (aidpp == NULL || cnt == NULL) { + errno = EINVAL; + return (-1); + } + *aidpp = NULL; + *cnt = 0; + + bzero(&aidr, sizeof (aidr)); + + err = ioctl(s, SIOCGASSOCIDS, &aidr); + if (err != 0) + return (-1); + + /* none, just return */ + if (aidr.sar_cnt == 0) + return (0); + + buf = calloc(aidr.sar_cnt, sizeof (sae_associd_t)); + if (buf == NULL) + return (-1); + + aidr.sar_aidp = buf; + err = ioctl(s, SIOCGASSOCIDS, &aidr); + if (err != 0) { + free(buf); + return (-1); + } + + *aidpp = buf; + *cnt = aidr.sar_cnt; + + return (0); +} + +void +freeassocids(sae_associd_t *aidp) +{ + free(aidp); +} + +int +copyconnids(int s, sae_associd_t aid, sae_connid_t **cidp, uint32_t *cnt) +{ + struct so_cidreq cidr; + sae_connid_t *buf; + int err; + + if (cidp == NULL || cnt == NULL) { + errno = EINVAL; + return (-1); + } + *cidp = NULL; + *cnt = 0; + + bzero(&cidr, sizeof (cidr)); + + cidr.scr_aid = aid; + err = ioctl(s, SIOCGCONNIDS, &cidr); + if (err != 0) + return (-1); + + /* none, just return */ + if (cidr.scr_cnt == 0) + return (0); + + buf = calloc(cidr.scr_cnt, sizeof (sae_connid_t)); + if (buf == NULL) + return (-1); + + cidr.scr_cidp = buf; + err = ioctl(s, SIOCGCONNIDS, &cidr); + if (err != 0) { + free(buf); + return (-1); + } + + *cidp = buf; + *cnt = cidr.scr_cnt; + + return (0); +} + +void +freeconnids(sae_connid_t *cidp) +{ + free(cidp); +} + +int +copyconninfo(int s, sae_connid_t cid, conninfo_t **cfop) +{ + struct sockaddr *src = NULL, *dst = NULL, *aux = NULL; + struct so_cinforeq scir; + conninfo_t *buf = NULL; + + if (cfop == NULL) { + errno = EINVAL; + goto error; + } + *cfop = NULL; + + bzero(&scir, sizeof (scir)); + + scir.scir_cid = cid; + if (ioctl(s, SIOCGCONNINFO, &scir) != 0) + goto error; + + if (scir.scir_src_len != 0) { + src = calloc(1, scir.scir_src_len); + if (src == NULL) + goto error; + scir.scir_src = src; + } + if (scir.scir_dst_len != 0) { + dst = calloc(1, scir.scir_dst_len); + if (dst == NULL) + goto error; + scir.scir_dst = dst; + } + if (scir.scir_aux_len != 0) { + aux = calloc(1, scir.scir_aux_len); + if (aux == NULL) + goto error; + scir.scir_aux_data = aux; + } + + if (ioctl(s, SIOCGCONNINFO, &scir) != 0) + goto error; + + buf = calloc(1, sizeof (*buf)); + if (buf == NULL) + goto error; + + // When we query for the length using the first ioctl call above, the kernel + // tells us the length of the aux structure so we know how much to allocate + // memory. There may not be any aux data, which will be indicated by the aux + // data length using the second ioctl call. + if (scir.scir_aux_len == 0 && aux != NULL) { + free(aux); + aux = NULL; + scir.scir_aux_data = NULL; + } + + buf->ci_flags = scir.scir_flags; + buf->ci_ifindex = scir.scir_ifindex; + buf->ci_src = src; + buf->ci_dst = dst; + buf->ci_error = scir.scir_error; + buf->ci_aux_type = scir.scir_aux_type; + buf->ci_aux_data = aux; + *cfop = (conninfo_t*)buf; + + return (0); + +error: + if (src != NULL) + free(src); + if (dst != NULL) + free(dst); + if (aux != NULL) + free(aux); + if (buf != NULL) + free(buf); + + return (-1); +} + +void +freeconninfo(conninfo_t *cfo) +{ + if (cfo->ci_src != NULL) + free(cfo->ci_src); + + if (cfo->ci_dst != NULL) + free(cfo->ci_dst); + + if (cfo->ci_aux_data != NULL) + free(cfo->ci_aux_data); + + free(cfo); +} diff --git a/network_cmds/mptcp_client/conn_lib.h b/network_cmds/mptcp_client/conn_lib.h new file mode 100644 index 0000000..b69b73c --- /dev/null +++ b/network_cmds/mptcp_client/conn_lib.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2012-2014 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +// +// Created by Anumita Biswas on 10/30/12. +// + +#ifndef mptcp_client_conn_lib_h +#define mptcp_client_conn_lib_h + +typedef struct conninfo { + __uint32_t ci_flags; /* see flags in sys/socket.h (CIF_CONNECTING, etc...) */ + __uint32_t ci_ifindex; /* outbound interface */ + struct sockaddr *ci_src; /* source address */ + struct sockaddr *ci_dst; /* destination address */ + int ci_error; /* saved error */ + __uint32_t ci_aux_type; /* auxiliary data type */ + void *ci_aux_data; /* auxiliary data */ +} conninfo_t; + +extern int copyassocids(int, sae_associd_t **, uint32_t *); +extern void freeassocids(sae_associd_t *); +extern int copyconnids(int, sae_associd_t, sae_connid_t **, uint32_t *); +extern void freeconnids(sae_connid_t *); +extern int copyconninfo(int, sae_connid_t, conninfo_t **); +extern void freeconninfo(conninfo_t *); + +#endif diff --git a/network_cmds/mptcp_client/mptcp_client.1 b/network_cmds/mptcp_client/mptcp_client.1 new file mode 100644 index 0000000..2ca3cad --- /dev/null +++ b/network_cmds/mptcp_client/mptcp_client.1 @@ -0,0 +1,21 @@ +.Dd 6/12/14
+.Dt mptcp_client 1
+.Os Darwin
+.Sh NAME
+.Nm mptcp_client
+.Nd Tool to exercise MPTCP.
+.Sh SYNOPSIS
+.Nm
+.Ar hostname
+.Ar port
+.Ar reqlen
+.Ar rsplen
+.Ar times
+.Ar alt_addr
+.Ar 0
+.Ar longlived
+.Sh DESCRIPTION
+.Nm
+is as an MPTCP client test tool that use the
+.Xr socket 2
+API.
diff --git a/network_cmds/mptcp_client/mptcp_client.c b/network_cmds/mptcp_client/mptcp_client.c new file mode 100644 index 0000000..770aabc --- /dev/null +++ b/network_cmds/mptcp_client/mptcp_client.c @@ -0,0 +1,701 @@ +/* + * Copyright (c) 2012-2014 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * Copyright (c) 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +// +// Created by Anumita Biswas on 7/17/12. +// + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netdb.h> +#include <errno.h> +#include <arpa/inet.h> +#include <err.h> +#include <sysexits.h> +#include <getopt.h> + +#include "conn_lib.h" + +struct so_cordreq socorder; +static void showmpinfo(int s); + +#define MSG_HDR "Message Header" +#define RESPONSE "I got your message" + +static int verbose = 0; + +static int32_t thiszone = 0; /* time difference with gmt */ + +char *setup_buffer1(int bufsz) +{ + int i = 0, j = 1; + char *buf; + + buf = malloc(bufsz); + if (!buf) + return NULL; + + bzero(buf, bufsz); + strlcpy(buf, MSG_HDR, bufsz); + + for (i = sizeof(MSG_HDR); i < bufsz; i++) { + buf[i] = j; + j++; + if (j >= 255) + j = 1; + } + return buf; +} + +char *setup_buffer2(int bufsz) +{ + int i = 0; + char j = 'A'; + char *buf; + + buf = malloc(bufsz); + if (!buf) + return NULL; + + bzero(buf, bufsz); + strlcpy(buf, MSG_HDR, bufsz); + + for (i = sizeof(MSG_HDR); i < bufsz; i++) { + buf[i] = j; + j++; + if (j >= 'z') + j = 'A'; + } + return buf; +} + +char *setup_buffer3(int bufsz) +{ + char *buf; + + buf = malloc(bufsz); + if (!buf) + return NULL; + + bzero(buf, bufsz); + return buf; +} + +/* + * Returns the difference between gmt and local time in seconds. + * Use gmtime() and localtime() to keep things simple. + * from tcpdump/gmt2local.c + */ +static int32_t +gmt2local(time_t t) +{ + int dt, dir; + struct tm *gmt, *loc; + struct tm sgmt; + + if (t == 0) + t = time(NULL); + gmt = &sgmt; + *gmt = *gmtime(&t); + loc = localtime(&t); + dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + + (loc->tm_min - gmt->tm_min) * 60; + + /* + * If the year or julian day is different, we span 00:00 GMT + * and must add or subtract a day. Check the year first to + * avoid problems when the julian day wraps. + */ + dir = loc->tm_year - gmt->tm_year; + if (dir == 0) + dir = loc->tm_yday - gmt->tm_yday; + dt += dir * 24 * 60 * 60; + + return (dt); +} + +/* + * Print the timestamp + * from tcpdump/util.c + */ +static void +ts_print(void) +{ + int s; + struct timeval tv; + + gettimeofday(&tv, NULL); + + /* Default */ + s = (tv.tv_sec + thiszone) % 86400; + printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60, + (u_int32_t)tv.tv_usec); +} + +static const char * +basename(const char * str) +{ + const char *last_slash = strrchr(str, '/'); + + if (last_slash == NULL) + return (str); + else + return (last_slash + 1); +} + +struct option_desc { + const char *option; + const char *description; + int required; +}; + +struct option_desc option_desc_list[] = { + { "--host addr", "address of server to connect to", 1 }, + { "--port n", "port of server to connect to", 1 }, + { "--reqlen n", "length of request (256 by default)", 0 }, + { "--rsplen n", "length of response (256 by default)", 0 }, + { "--ntimes n", "number of time to send request (1 by default)", 0 }, + { "--alt_addr addr", "alternate server to connect to", 0 }, + { "--verbose", "increase verbosity", 0 }, + { "--help", "display this help", 0 }, + + { NULL, NULL, 0 } /* Mark end of list */ +}; + +static void +usage(const char *cmd) +{ + struct option_desc *option_desc; + char *usage_str = malloc(LINE_MAX); + size_t usage_len; + + if (usage_str == NULL) + err(1, "%s: malloc(%d)", __func__, LINE_MAX); + + usage_len = snprintf(usage_str, LINE_MAX, "# usage: %s ", basename(cmd)); + + for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) { + int len; + + if (option_desc->required) + len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "%s ", option_desc->option); + else + len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "[%s] ", option_desc->option); + if (len < 0) + err(1, "%s: snprintf(", __func__); + + usage_len += len; + if (usage_len > LINE_MAX) + break; + } + printf("%s\n", usage_str); + printf("options:\n"); + + for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) { + printf(" %-24s # %s\n", option_desc->option, option_desc->description); + } + printf("\n"); + printf("# legacy usage: "); +} + +static struct option longopts[] = { + { "host", required_argument, NULL, 'c' }, + { "port", required_argument, NULL, 'p' }, + { "reqlen", required_argument, NULL, 'r' }, + { "rsplen", required_argument, NULL, 'R' }, + { "ntimes", required_argument, NULL, 'n' }, + { "alt_addr", required_argument, NULL, 'a' }, + { "help", no_argument, NULL, 'h' }, + { "verbose", no_argument, NULL, 'v' }, + { "quiet", no_argument, NULL, 'q' }, + { NULL, 0, NULL, 0 } +}; + +static int +sprint_sockaddr(char *str, socklen_t strlen, struct sockaddr *sa) +{ + int retval = 0; + + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in*)sa; + char str4[INET_ADDRSTRLEN]; + + inet_ntop(AF_INET, &sin->sin_addr, str4, sizeof(str4)); + + retval = snprintf(str, strlen, "%s:%u", str4, ntohs(sin->sin_port)); + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa; + char str6[INET6_ADDRSTRLEN]; + char ifname[IF_NAMESIZE]; + char scopestr[2 + IF_NAMESIZE]; + + inet_ntop(AF_INET6, &sin6->sin6_addr, str6, sizeof(str6)); + + if (sin6->sin6_scope_id == 0) + *scopestr = '\0'; + else { + if_indextoname(sin6->sin6_scope_id, ifname); + snprintf(scopestr, sizeof(scopestr), "%%%s", ifname); + } + + retval = snprintf(str, strlen, "%s%s:%u", + str6, + scopestr, + ntohs(sin6->sin6_port)); + } + return (retval); +} + +int main(int argc, char * const *argv) +{ + int sockfd, portno; + ssize_t n; + int reqlen = 256; + int rsplen = 256; + int ntimes = 1; + char *buffer = NULL; + char *buffer1; + char *buffer2; + char *buffer3; + struct addrinfo *ares = NULL, ahints; + struct addrinfo *altres = NULL; + int retval = 0; + int which_buf = 0; + sae_connid_t cid1, cid2; + int iter; + int bytes_to_rdwr; + int ch; + const char *host_arg = NULL; + const char *port_arg = NULL; + const char *reqlen_arg = "256"; + const char *rsplen_arg = "256"; + const char *ntimes_arg = "1"; + const char *alt_addr_arg = NULL; + const char *alt_port_arg = "0"; + int gotopt = 0; + + thiszone = gmt2local(0); + + while ((ch = getopt_long(argc, argv, "a:c:hn:p:qr:R:v", longopts, NULL)) != -1) { + gotopt = 1; + switch (ch) { + case 'a': + alt_addr_arg = optarg; + break; + case 'c': + host_arg = optarg; + break; + case 'n': + ntimes_arg = optarg; + break; + case 'p': + port_arg = optarg; + break; + case 'q': + verbose--; + break; + case 'r': + reqlen_arg = optarg; + break; + case 'R': + rsplen_arg = optarg; + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(EX_USAGE); + } + } + + if (gotopt == 0) { + if (argc == 12) { + host_arg = argv[1]; + port_arg = argv[2]; + reqlen_arg = argv[3]; + rsplen_arg = argv[4]; + ntimes_arg = argv[5]; + alt_addr_arg = argv[6]; + } else { + usage(argv[0]); + exit(EX_USAGE); + } + } + + if (host_arg == NULL) + errx(EX_USAGE, "missing required host option\n"); + + if (port_arg == NULL) + errx(EX_USAGE, "missing required port option\n"); + portno = atoi(port_arg); + if (portno < 0 || portno > 65535) + errx(EX_USAGE, "invalid port %s\n", port_arg); + + if (reqlen_arg != NULL) { + reqlen = atoi(reqlen_arg); + if (reqlen < 0 || reqlen > 1024 * 1024) + errx(EX_USAGE, "invalid request length %s\n", reqlen_arg); + } + + if (rsplen_arg != NULL) { + rsplen = atoi(rsplen_arg); + if (rsplen < 0 || rsplen > 1024 * 1024) + errx(EX_USAGE, "invalid response length %s\n", rsplen_arg); + } + + if (ntimes_arg != NULL) { + ntimes = atoi(ntimes_arg); + if (ntimes < 1) + errx(EX_USAGE, "invalid ntimes option %s\n", ntimes_arg); + } + + buffer1 = setup_buffer1(reqlen); + if (!buffer1) { + printf("client: failed to alloc buffer space \n"); + return -1; + } + + buffer2 = setup_buffer2(reqlen); + if (!buffer2) { + printf("client: failed to alloc buffer space \n"); + return -1; + } + + buffer3 = setup_buffer3(rsplen); + if (!buffer3) { + printf("client: failed to alloc buffer space \n"); + return -1; + } + + if (verbose > 0) + printf("host: %s port: %s reqlen: %d rsplen: %d ntimes: %d alt_addr: %s\n", + host_arg, port_arg, reqlen, rsplen, ntimes, alt_addr_arg); + + sockfd = socket(AF_MULTIPATH, SOCK_STREAM, 0); + if (sockfd < 0) + err(EX_OSERR, "ERROR opening socket"); + + memset(&ahints, 0, sizeof(struct addrinfo)); + ahints.ai_family = AF_INET; + ahints.ai_socktype = SOCK_STREAM; + ahints.ai_protocol = IPPROTO_TCP; + + retval = getaddrinfo(host_arg, port_arg, &ahints, &ares); + if (retval != 0) + printf("getaddrinfo(%s, %s) failed %d\n", host_arg, port_arg, retval); + + bytes_to_rdwr = reqlen; + + cid1 = cid2 = SAE_CONNID_ANY; + int ifscope = 0; + int error = 0; + + if (verbose > 0) { + char str[2 * INET6_ADDRSTRLEN]; + + ts_print(); + + sprint_sockaddr(str, sizeof(str), ares->ai_addr); + printf("connectx(%s, %d, %d)\n", str, ifscope, cid1); + } + sa_endpoints_t sa; + bzero(&sa, sizeof(sa)); + sa.sae_dstaddr = ares->ai_addr; + sa.sae_dstaddrlen = ares->ai_addrlen; + sa.sae_srcif = ifscope; + + error = connectx(sockfd, &sa, SAE_ASSOCID_ANY, 0, NULL, 0, NULL, &cid1); + if (error != 0) + err(EX_OSERR, "ERROR connecting"); + + iter = 0; + + while (ntimes) { + if (iter == 0) { + /* Add alternate path if available */ + + if (alt_addr_arg && alt_addr_arg[0] != 0) { + retval = getaddrinfo(alt_addr_arg, alt_port_arg, &ahints, &altres); + + if (retval != 0) + printf("client: alternate address resolution failed. \n"); + else { + printf("client: connecting to alternate address (ifscope %d)\n", ifscope); + + if (verbose > 0) { + char str[2 * INET6_ADDRSTRLEN]; + + ts_print(); + + sprint_sockaddr(str, sizeof(str), altres->ai_addr); + printf("connectx(%s, %d, %d)\n", str, ifscope, cid1); + } + sa_endpoints_t sa; + bzero(&sa, sizeof(sa)); + sa.sae_srcif = ifscope; + sa.sae_srcaddr = altres->ai_addr; + sa.sae_srcaddrlen = altres->ai_addrlen; + sa.sae_dstaddr = ares->ai_addr; + sa.sae_dstaddrlen = ares->ai_addrlen; + + error = connectx(sockfd, &sa, SAE_ASSOCID_ANY, 0, NULL, 0, NULL, &cid2); + if (error < 0) { + err(EX_OSERR, "ERROR setting up alternate path"); + } + } + } + } + + if (which_buf == 0) { + buffer = buffer1; + which_buf = 1; + } else { + buffer = buffer2; + which_buf = 0; + } + + while (bytes_to_rdwr) { + if (verbose) { + ts_print(); + printf("writing %d bytes\n", bytes_to_rdwr); + } + n = write(sockfd, buffer, bytes_to_rdwr); + if (n <= 0) { + err(EX_OSERR, "ERROR writing to socket"); + } + if (n <= bytes_to_rdwr) + bytes_to_rdwr -= n; + else { + errx(EX_DATAERR, "ERROR extra data write %zd %d\n", n, bytes_to_rdwr); + } + } + bytes_to_rdwr = rsplen; + while (bytes_to_rdwr) { + if (verbose) { + ts_print(); + printf("reading %d bytes\n", rsplen); + } + n = read(sockfd, buffer3, rsplen); + + if (n <= 0) { + err(EX_OSERR, "ERROR reading from socket"); + } + if (n <= bytes_to_rdwr) + bytes_to_rdwr -= n; + else { + errx(EX_DATAERR, "ERROR extra bytes read n:%zd expected:%d\n", n, bytes_to_rdwr); + } + } + bytes_to_rdwr = reqlen; + ntimes--; + iter++; + } + + printf("client: Req size %d Rsp size %d Read/Write %d times \n", reqlen, rsplen, iter); + + showmpinfo(sockfd); + + if (verbose) { + ts_print(); + printf("close(%d)\n", sockfd); + } + close(sockfd); + + freeaddrinfo(ares); + if (altres) + freeaddrinfo(altres); + return 0; +} + +#define CIF_BITS \ +"\020\1CONNECTING\2CONNECTED\3DISCONNECTING\4DISCONNECTED\5BOUND_IF"\ +"\6BOUND_IP\7BOUND_PORT\10PREFERRED\11MP_CAPABLE\12MP_READY" \ +"\13MP_DEGRADED" + +/* + * Print a value a la the %b format of the kernel's printf + */ +static void +printb(const char *s, unsigned v, const char *bits) +{ + int i, any = 0; + char c; + + if (bits && *bits == 8) + printf("%s=%o", s, v); + else + printf("%s=%x", s, v); + bits++; + if (bits) { + putchar('<'); + while ((i = *bits++) != '\0') { + if (v & (1 << (i-1))) { + if (any) + putchar(','); + any = 1; + for (; (c = *bits) > 32; bits++) + putchar(c); + } else { + for (; *bits > 32; bits++) + ; + } + } + putchar('>'); + } +} + +static int +showconninfo(int s, sae_connid_t cid) +{ + char buf[INET6_ADDRSTRLEN]; + conninfo_t *cfo = NULL; + int err; + + err = copyconninfo(s, cid, &cfo); + if (err != 0) { + printf("getconninfo failed for cid %d\n", cid); + goto out; + } + + printf("%6d:\t", cid); + printb("flags", cfo->ci_flags, CIF_BITS); + printf("\n"); + + if (cfo->ci_src != NULL) { + printf("\tsrc %s port %d\n", inet_ntop(cfo->ci_src->sa_family, + (cfo->ci_src->sa_family == AF_INET) ? + (void *)&((struct sockaddr_in *)cfo->ci_src)-> + sin_addr.s_addr : + (void *)&((struct sockaddr_in6 *)cfo->ci_src)->sin6_addr, + buf, sizeof (buf)), + (cfo->ci_src->sa_family == AF_INET) ? + ntohs(((struct sockaddr_in *)cfo->ci_src)->sin_port) : + ntohs(((struct sockaddr_in6 *)cfo->ci_src)->sin6_port)); + } + if (cfo->ci_dst != NULL) { + printf("\tdst %s port %d\n", inet_ntop(cfo->ci_dst->sa_family, + (cfo->ci_dst->sa_family == AF_INET) ? + (void *)&((struct sockaddr_in *)cfo->ci_dst)-> + sin_addr.s_addr : + (void *)&((struct sockaddr_in6 *)cfo->ci_dst)->sin6_addr, + buf, sizeof (buf)), + (cfo->ci_dst->sa_family == AF_INET) ? + ntohs(((struct sockaddr_in *)cfo->ci_dst)->sin_port) : + ntohs(((struct sockaddr_in6 *)cfo->ci_dst)->sin6_port)); + } + if (cfo->ci_aux_data != NULL) { + switch (cfo->ci_aux_type) { + case CIAUX_TCP: + printf("\tTCP aux info available\n"); + break; + default: + printf("\tUnknown aux type %d\n", cfo->ci_aux_type); + break; + } + } +out: + if (cfo != NULL) + freeconninfo(cfo); + + return (err); +} + +static void +showmpinfo(int s) +{ + uint32_t aid_cnt = 0, cid_cnt = 0; + sae_associd_t *aid = NULL; + sae_connid_t *cid = NULL; + int i, error = 0; + + error = copyassocids(s, &aid, &aid_cnt); + if (error != 0) { + printf("copyassocids failed\n"); + goto done; + } else { + printf("found %d associations", aid_cnt); + if (aid_cnt > 0) { + printf(" with IDs:"); + for (i = 0; i < aid_cnt; i++) + printf(" %d\n", aid[i]); + } + printf("\n"); + } + + /* just do an association for now */ + error = copyconnids(s, SAE_ASSOCID_ANY, &cid, &cid_cnt); + if (error != 0) { + warn("getconnids failed\n"); + goto done; + } else { + printf("found %d connections", cid_cnt); + if (cid_cnt > 0) { + printf(":\n"); + for (i = 0; i < cid_cnt; i++) { + if (showconninfo(s, cid[i]) != 0) + break; + } + } + printf("\n"); + } + +done: + if (aid != NULL) + freeassocids(aid); + if (cid != NULL) + freeconnids(cid); +} |