]>
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 | ||
d9520f62 | 82 | char *setup_buffer1(int bufsz) |
342c141e A |
83 | { |
84 | int i = 0, j = 1; | |
d9520f62 A |
85 | char *buf; |
86 | ||
87 | buf = malloc(bufsz); | |
88 | if (!buf) | |
89 | return NULL; | |
90 | ||
91 | bzero(buf, bufsz); | |
e0b07f2d | 92 | strlcpy(buf, MSG_HDR, bufsz); |
d9520f62 | 93 | |
342c141e A |
94 | for (i = sizeof(MSG_HDR); i < bufsz; i++) { |
95 | buf[i] = j; | |
96 | j++; | |
97 | if (j >= 255) | |
98 | j = 1; | |
99 | } | |
100 | return buf; | |
101 | } | |
102 | ||
d9520f62 | 103 | char *setup_buffer2(int bufsz) |
342c141e A |
104 | { |
105 | int i = 0; | |
106 | char j = 'A'; | |
d9520f62 A |
107 | char *buf; |
108 | ||
109 | buf = malloc(bufsz); | |
110 | if (!buf) | |
111 | return NULL; | |
112 | ||
113 | bzero(buf, bufsz); | |
e0b07f2d | 114 | strlcpy(buf, MSG_HDR, bufsz); |
d9520f62 | 115 | |
342c141e A |
116 | for (i = sizeof(MSG_HDR); i < bufsz; i++) { |
117 | buf[i] = j; | |
118 | j++; | |
119 | if (j >= 'z') | |
120 | j = 'A'; | |
121 | } | |
122 | return buf; | |
123 | } | |
124 | ||
125 | char *setup_buffer3(int bufsz) | |
126 | { | |
d9520f62 A |
127 | char *buf; |
128 | ||
129 | buf = malloc(bufsz); | |
130 | if (!buf) | |
131 | return NULL; | |
132 | ||
133 | bzero(buf, bufsz); | |
342c141e A |
134 | return buf; |
135 | } | |
136 | ||
137 | /* | |
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 | |
141 | */ | |
142 | static int32_t | |
143 | gmt2local(time_t t) | |
144 | { | |
145 | int dt, dir; | |
146 | struct tm *gmt, *loc; | |
147 | struct tm sgmt; | |
d9520f62 | 148 | |
342c141e A |
149 | if (t == 0) |
150 | t = time(NULL); | |
151 | gmt = &sgmt; | |
152 | *gmt = *gmtime(&t); | |
153 | loc = localtime(&t); | |
154 | dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + | |
155 | (loc->tm_min - gmt->tm_min) * 60; | |
d9520f62 | 156 | |
342c141e A |
157 | /* |
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. | |
161 | */ | |
162 | dir = loc->tm_year - gmt->tm_year; | |
163 | if (dir == 0) | |
164 | dir = loc->tm_yday - gmt->tm_yday; | |
165 | dt += dir * 24 * 60 * 60; | |
d9520f62 | 166 | |
342c141e A |
167 | return (dt); |
168 | } | |
169 | ||
170 | /* | |
171 | * Print the timestamp | |
172 | * from tcpdump/util.c | |
173 | */ | |
174 | static void | |
175 | ts_print(void) | |
176 | { | |
177 | int s; | |
178 | struct timeval tv; | |
d9520f62 | 179 | |
342c141e | 180 | gettimeofday(&tv, NULL); |
d9520f62 | 181 | |
342c141e A |
182 | /* Default */ |
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); | |
186 | } | |
187 | ||
188 | static const char * | |
189 | basename(const char * str) | |
190 | { | |
191 | const char *last_slash = strrchr(str, '/'); | |
d9520f62 | 192 | |
342c141e A |
193 | if (last_slash == NULL) |
194 | return (str); | |
195 | else | |
196 | return (last_slash + 1); | |
197 | } | |
198 | ||
199 | struct option_desc { | |
200 | const char *option; | |
201 | const char *description; | |
202 | int required; | |
203 | }; | |
204 | ||
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 }, | |
342c141e A |
212 | { "--verbose", "increase verbosity", 0 }, |
213 | { "--help", "display this help", 0 }, | |
214 | ||
215 | { NULL, NULL, 0 } /* Mark end of list */ | |
216 | }; | |
217 | ||
218 | static void | |
219 | usage(const char *cmd) | |
220 | { | |
221 | struct option_desc *option_desc; | |
222 | char *usage_str = malloc(LINE_MAX); | |
223 | size_t usage_len; | |
d9520f62 | 224 | |
342c141e A |
225 | if (usage_str == NULL) |
226 | err(1, "%s: malloc(%d)", __func__, LINE_MAX); | |
d9520f62 | 227 | |
342c141e | 228 | usage_len = snprintf(usage_str, LINE_MAX, "# usage: %s ", basename(cmd)); |
d9520f62 | 229 | |
342c141e A |
230 | for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) { |
231 | int len; | |
d9520f62 | 232 | |
342c141e A |
233 | if (option_desc->required) |
234 | len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "%s ", option_desc->option); | |
235 | else | |
236 | len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "[%s] ", option_desc->option); | |
237 | if (len < 0) | |
238 | err(1, "%s: snprintf(", __func__); | |
d9520f62 | 239 | |
342c141e A |
240 | usage_len += len; |
241 | if (usage_len > LINE_MAX) | |
242 | break; | |
243 | } | |
244 | printf("%s\n", usage_str); | |
245 | printf("options:\n"); | |
d9520f62 | 246 | |
342c141e A |
247 | for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) { |
248 | printf(" %-24s # %s\n", option_desc->option, option_desc->description); | |
249 | } | |
250 | printf("\n"); | |
251 | printf("# legacy usage: "); | |
342c141e A |
252 | } |
253 | ||
254 | static struct option longopts[] = { | |
d9520f62 A |
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' }, | |
264 | { NULL, 0, NULL, 0 } | |
342c141e A |
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]; | |
d9520f62 | 275 | |
342c141e | 276 | inet_ntop(AF_INET, &sin->sin_addr, str4, sizeof(str4)); |
d9520f62 | 277 | |
342c141e A |
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]; | |
d9520f62 | 284 | |
342c141e A |
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 | } | |
d9520f62 | 293 | |
342c141e A |
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 | { | |
d9520f62 | 304 | int sockfd, portno; |
342c141e A |
305 | ssize_t n; |
306 | int reqlen = 256; | |
307 | int rsplen = 256; | |
308 | int ntimes = 1; | |
342c141e A |
309 | char *buffer = NULL; |
310 | char *buffer1; | |
311 | char *buffer2; | |
312 | char *buffer3; | |
313 | struct addrinfo *ares = NULL, ahints; | |
314 | struct addrinfo *altres = NULL; | |
315 | int retval = 0; | |
316 | int which_buf = 0; | |
89c4ed63 | 317 | sae_connid_t cid1, cid2; |
342c141e A |
318 | int iter; |
319 | int bytes_to_rdwr; | |
342c141e A |
320 | int ch; |
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"; | |
342c141e A |
328 | int gotopt = 0; |
329 | ||
330 | thiszone = gmt2local(0); | |
d9520f62 A |
331 | |
332 | while ((ch = getopt_long(argc, argv, "a:c:hn:p:qr:R:v", longopts, NULL)) != -1) { | |
342c141e A |
333 | gotopt = 1; |
334 | switch (ch) { | |
335 | case 'a': | |
336 | alt_addr_arg = optarg; | |
337 | break; | |
338 | case 'c': | |
339 | host_arg = optarg; | |
340 | break; | |
342c141e A |
341 | case 'n': |
342 | ntimes_arg = optarg; | |
343 | break; | |
342c141e A |
344 | case 'p': |
345 | port_arg = optarg; | |
346 | break; | |
347 | case 'q': | |
348 | verbose--; | |
349 | break; | |
350 | case 'r': | |
351 | reqlen_arg = optarg; | |
352 | break; | |
353 | case 'R': | |
354 | rsplen_arg = optarg; | |
355 | break; | |
356 | case 'v': | |
357 | verbose++; | |
358 | break; | |
342c141e A |
359 | default: |
360 | usage(argv[0]); | |
361 | exit(EX_USAGE); | |
342c141e A |
362 | } |
363 | } | |
d9520f62 | 364 | |
342c141e A |
365 | if (gotopt == 0) { |
366 | if (argc == 12) { | |
367 | host_arg = argv[1]; | |
368 | port_arg = argv[2]; | |
369 | reqlen_arg = argv[3]; | |
370 | rsplen_arg = argv[4]; | |
371 | ntimes_arg = argv[5]; | |
372 | alt_addr_arg = argv[6]; | |
342c141e A |
373 | } else { |
374 | usage(argv[0]); | |
375 | exit(EX_USAGE); | |
376 | } | |
377 | } | |
d9520f62 | 378 | |
342c141e A |
379 | if (host_arg == NULL) |
380 | errx(EX_USAGE, "missing required host option\n"); | |
381 | ||
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); | |
387 | ||
388 | if (reqlen_arg != NULL) { | |
389 | reqlen = atoi(reqlen_arg); | |
d9520f62 | 390 | if (reqlen < 0 || reqlen > 1024 * 1024) |
342c141e A |
391 | errx(EX_USAGE, "invalid request length %s\n", reqlen_arg); |
392 | } | |
393 | ||
394 | if (rsplen_arg != NULL) { | |
395 | rsplen = atoi(rsplen_arg); | |
d9520f62 | 396 | if (rsplen < 0 || rsplen > 1024 * 1024) |
342c141e A |
397 | errx(EX_USAGE, "invalid response length %s\n", rsplen_arg); |
398 | } | |
d9520f62 | 399 | |
342c141e A |
400 | if (ntimes_arg != NULL) { |
401 | ntimes = atoi(ntimes_arg); | |
402 | if (ntimes < 1) | |
403 | errx(EX_USAGE, "invalid ntimes option %s\n", ntimes_arg); | |
404 | } | |
d9520f62 | 405 | |
342c141e A |
406 | buffer1 = setup_buffer1(reqlen); |
407 | if (!buffer1) { | |
408 | printf("client: failed to alloc buffer space \n"); | |
409 | return -1; | |
410 | } | |
d9520f62 | 411 | |
342c141e A |
412 | buffer2 = setup_buffer2(reqlen); |
413 | if (!buffer2) { | |
414 | printf("client: failed to alloc buffer space \n"); | |
415 | return -1; | |
416 | } | |
d9520f62 | 417 | |
342c141e A |
418 | buffer3 = setup_buffer3(rsplen); |
419 | if (!buffer3) { | |
420 | printf("client: failed to alloc buffer space \n"); | |
421 | return -1; | |
422 | } | |
d9520f62 | 423 | |
342c141e | 424 | if (verbose > 0) |
d9520f62 A |
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); | |
427 | ||
342c141e A |
428 | sockfd = socket(AF_MULTIPATH, SOCK_STREAM, 0); |
429 | if (sockfd < 0) | |
430 | err(EX_OSERR, "ERROR opening socket"); | |
d9520f62 | 431 | |
342c141e A |
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; | |
d9520f62 | 436 | |
342c141e A |
437 | retval = getaddrinfo(host_arg, port_arg, &ahints, &ares); |
438 | if (retval != 0) | |
439 | printf("getaddrinfo(%s, %s) failed %d\n", host_arg, port_arg, retval); | |
d9520f62 | 440 | |
342c141e | 441 | bytes_to_rdwr = reqlen; |
d9520f62 | 442 | |
89c4ed63 | 443 | cid1 = cid2 = SAE_CONNID_ANY; |
342c141e A |
444 | int ifscope = 0; |
445 | int error = 0; | |
d9520f62 | 446 | |
342c141e A |
447 | if (verbose > 0) { |
448 | char str[2 * INET6_ADDRSTRLEN]; | |
d9520f62 | 449 | |
342c141e | 450 | ts_print(); |
d9520f62 | 451 | |
342c141e A |
452 | sprint_sockaddr(str, sizeof(str), ares->ai_addr); |
453 | printf("connectx(%s, %d, %d)\n", str, ifscope, cid1); | |
454 | } | |
89c4ed63 A |
455 | sa_endpoints_t sa; |
456 | bzero(&sa, sizeof(sa)); | |
457 | sa.sae_dstaddr = ares->ai_addr; | |
458 | sa.sae_dstaddrlen = ares->ai_addrlen; | |
459 | sa.sae_srcif = ifscope; | |
460 | ||
461 | error = connectx(sockfd, &sa, SAE_ASSOCID_ANY, 0, NULL, 0, NULL, &cid1); | |
d9520f62 | 462 | if (error != 0) |
342c141e | 463 | err(EX_OSERR, "ERROR connecting"); |
d9520f62 | 464 | |
342c141e | 465 | iter = 0; |
d9520f62 | 466 | |
342c141e | 467 | while (ntimes) { |
d9520f62 | 468 | if (iter == 0) { |
342c141e | 469 | /* Add alternate path if available */ |
d9520f62 | 470 | |
342c141e A |
471 | if (alt_addr_arg && alt_addr_arg[0] != 0) { |
472 | retval = getaddrinfo(alt_addr_arg, alt_port_arg, &ahints, &altres); | |
d9520f62 | 473 | |
342c141e A |
474 | if (retval != 0) |
475 | printf("client: alternate address resolution failed. \n"); | |
476 | else { | |
477 | printf("client: connecting to alternate address (ifscope %d)\n", ifscope); | |
478 | ||
479 | if (verbose > 0) { | |
480 | char str[2 * INET6_ADDRSTRLEN]; | |
481 | ||
482 | ts_print(); | |
d9520f62 | 483 | |
342c141e A |
484 | sprint_sockaddr(str, sizeof(str), altres->ai_addr); |
485 | printf("connectx(%s, %d, %d)\n", str, ifscope, cid1); | |
486 | } | |
89c4ed63 A |
487 | sa_endpoints_t sa; |
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; | |
d9520f62 | 494 | |
89c4ed63 | 495 | error = connectx(sockfd, &sa, SAE_ASSOCID_ANY, 0, NULL, 0, NULL, &cid2); |
342c141e A |
496 | if (error < 0) { |
497 | err(EX_OSERR, "ERROR setting up alternate path"); | |
498 | } | |
499 | } | |
500 | } | |
342c141e | 501 | } |
d9520f62 | 502 | |
342c141e A |
503 | if (which_buf == 0) { |
504 | buffer = buffer1; | |
505 | which_buf = 1; | |
506 | } else { | |
507 | buffer = buffer2; | |
508 | which_buf = 0; | |
509 | } | |
d9520f62 | 510 | |
342c141e A |
511 | while (bytes_to_rdwr) { |
512 | if (verbose) { | |
513 | ts_print(); | |
514 | printf("writing %d bytes\n", bytes_to_rdwr); | |
515 | } | |
516 | n = write(sockfd, buffer, bytes_to_rdwr); | |
517 | if (n <= 0) { | |
518 | err(EX_OSERR, "ERROR writing to socket"); | |
519 | } | |
520 | if (n <= bytes_to_rdwr) | |
521 | bytes_to_rdwr -= n; | |
522 | else { | |
523 | errx(EX_DATAERR, "ERROR extra data write %zd %d\n", n, bytes_to_rdwr); | |
524 | } | |
525 | } | |
526 | bytes_to_rdwr = rsplen; | |
527 | while (bytes_to_rdwr) { | |
528 | if (verbose) { | |
529 | ts_print(); | |
530 | printf("reading %d bytes\n", rsplen); | |
531 | } | |
532 | n = read(sockfd, buffer3, rsplen); | |
d9520f62 | 533 | |
342c141e A |
534 | if (n <= 0) { |
535 | err(EX_OSERR, "ERROR reading from socket"); | |
536 | } | |
537 | if (n <= bytes_to_rdwr) | |
538 | bytes_to_rdwr -= n; | |
539 | else { | |
540 | errx(EX_DATAERR, "ERROR extra bytes read n:%zd expected:%d\n", n, bytes_to_rdwr); | |
541 | } | |
542 | } | |
543 | bytes_to_rdwr = reqlen; | |
544 | ntimes--; | |
545 | iter++; | |
546 | } | |
d9520f62 | 547 | |
342c141e | 548 | printf("client: Req size %d Rsp size %d Read/Write %d times \n", reqlen, rsplen, iter); |
d9520f62 | 549 | |
342c141e | 550 | showmpinfo(sockfd); |
d9520f62 A |
551 | |
552 | if (verbose) { | |
553 | ts_print(); | |
554 | printf("close(%d)\n", sockfd); | |
342c141e | 555 | } |
d9520f62 A |
556 | close(sockfd); |
557 | ||
558 | freeaddrinfo(ares); | |
342c141e A |
559 | if (altres) |
560 | freeaddrinfo(altres); | |
561 | return 0; | |
562 | } | |
563 | ||
564 | #define CIF_BITS \ | |
565 | "\020\1CONNECTING\2CONNECTED\3DISCONNECTING\4DISCONNECTED\5BOUND_IF"\ | |
566 | "\6BOUND_IP\7BOUND_PORT\10PREFERRED\11MP_CAPABLE\12MP_READY" \ | |
567 | "\13MP_DEGRADED" | |
568 | ||
569 | /* | |
570 | * Print a value a la the %b format of the kernel's printf | |
571 | */ | |
572 | static void | |
573 | printb(const char *s, unsigned v, const char *bits) | |
574 | { | |
575 | int i, any = 0; | |
576 | char c; | |
d9520f62 | 577 | |
342c141e A |
578 | if (bits && *bits == 8) |
579 | printf("%s=%o", s, v); | |
580 | else | |
581 | printf("%s=%x", s, v); | |
582 | bits++; | |
583 | if (bits) { | |
584 | putchar('<'); | |
585 | while ((i = *bits++) != '\0') { | |
586 | if (v & (1 << (i-1))) { | |
587 | if (any) | |
588 | putchar(','); | |
589 | any = 1; | |
590 | for (; (c = *bits) > 32; bits++) | |
591 | putchar(c); | |
592 | } else { | |
593 | for (; *bits > 32; bits++) | |
594 | ; | |
595 | } | |
596 | } | |
597 | putchar('>'); | |
598 | } | |
599 | } | |
600 | ||
601 | static int | |
89c4ed63 | 602 | showconninfo(int s, sae_connid_t cid) |
342c141e A |
603 | { |
604 | char buf[INET6_ADDRSTRLEN]; | |
605 | conninfo_t *cfo = NULL; | |
606 | int err; | |
d9520f62 | 607 | |
342c141e A |
608 | err = copyconninfo(s, cid, &cfo); |
609 | if (err != 0) { | |
610 | printf("getconninfo failed for cid %d\n", cid); | |
611 | goto out; | |
612 | } | |
d9520f62 | 613 | |
342c141e A |
614 | printf("%6d:\t", cid); |
615 | printb("flags", cfo->ci_flags, CIF_BITS); | |
616 | printf("\n"); | |
d9520f62 | 617 | |
342c141e A |
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)-> | |
622 | sin_addr.s_addr : | |
623 | (void *)&((struct sockaddr_in6 *)cfo->ci_src)->sin6_addr, | |
624 | buf, sizeof (buf)), | |
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)); | |
628 | } | |
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)-> | |
633 | sin_addr.s_addr : | |
634 | (void *)&((struct sockaddr_in6 *)cfo->ci_dst)->sin6_addr, | |
635 | buf, sizeof (buf)), | |
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)); | |
639 | } | |
640 | if (cfo->ci_aux_data != NULL) { | |
641 | switch (cfo->ci_aux_type) { | |
642 | case CIAUX_TCP: | |
643 | printf("\tTCP aux info available\n"); | |
644 | break; | |
645 | default: | |
646 | printf("\tUnknown aux type %d\n", cfo->ci_aux_type); | |
647 | break; | |
648 | } | |
649 | } | |
342c141e A |
650 | out: |
651 | if (cfo != NULL) | |
652 | freeconninfo(cfo); | |
d9520f62 | 653 | |
342c141e A |
654 | return (err); |
655 | } | |
656 | ||
657 | static void | |
658 | showmpinfo(int s) | |
659 | { | |
89c4ed63 A |
660 | uint32_t aid_cnt = 0, cid_cnt = 0; |
661 | sae_associd_t *aid = NULL; | |
662 | sae_connid_t *cid = NULL; | |
663 | int i, error = 0; | |
d9520f62 | 664 | |
342c141e A |
665 | error = copyassocids(s, &aid, &aid_cnt); |
666 | if (error != 0) { | |
667 | printf("copyassocids failed\n"); | |
668 | goto done; | |
669 | } else { | |
670 | printf("found %d associations", aid_cnt); | |
671 | if (aid_cnt > 0) { | |
672 | printf(" with IDs:"); | |
673 | for (i = 0; i < aid_cnt; i++) | |
674 | printf(" %d\n", aid[i]); | |
675 | } | |
676 | printf("\n"); | |
677 | } | |
d9520f62 | 678 | |
342c141e | 679 | /* just do an association for now */ |
89c4ed63 | 680 | error = copyconnids(s, SAE_ASSOCID_ANY, &cid, &cid_cnt); |
342c141e A |
681 | if (error != 0) { |
682 | warn("getconnids failed\n"); | |
683 | goto done; | |
684 | } else { | |
685 | printf("found %d connections", cid_cnt); | |
686 | if (cid_cnt > 0) { | |
687 | printf(":\n"); | |
688 | for (i = 0; i < cid_cnt; i++) { | |
689 | if (showconninfo(s, cid[i]) != 0) | |
690 | break; | |
691 | } | |
692 | } | |
693 | printf("\n"); | |
694 | } | |
d9520f62 | 695 | |
342c141e A |
696 | done: |
697 | if (aid != NULL) | |
698 | freeassocids(aid); | |
699 | if (cid != NULL) | |
700 | freeconnids(cid); | |
701 | } |