1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3 * trace-msg.c : define message protocol for communication between clients and
4 * a server
5 *
6 * Copyright (C) 2013 Hitachi, Ltd.
7 * Created by Yoshihiro YUNOMAE <yoshihiro.yunomae.ez@hitachi.com>
8 *
9 */
10
11 #include <errno.h>
12 #include <poll.h>
13 #include <fcntl.h>
14 #include <limits.h>
15 #include <stddef.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stdarg.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <arpa/inet.h>
22 #include <sys/types.h>
23 #include <linux/types.h>
24
25 #include "trace-write-local.h"
26 #include "trace-cmd-local.h"
27 #include "trace-local.h"
28 #include "trace-msg.h"
29 #include "trace-cmd.h"
30
31 typedef __u32 u32;
32 typedef __be32 be32;
33
34 #define dprint(fmt, ...) tracecmd_debug(fmt, ##__VA_ARGS__)
35
36 /* Two (4k) pages is the max transfer for now */
37 #define MSG_MAX_LEN 8192
38
39 #define MSG_HDR_LEN sizeof(struct tracecmd_msg_header)
40
41 #define MSG_MAX_DATA_LEN (MSG_MAX_LEN - MSG_HDR_LEN)
42
43 unsigned int page_size;
44
45 struct tracecmd_msg_tinit {
46 be32 cpus;
47 be32 page_size;
48 be32 opt_num;
49 } __packed;
50
51 struct tracecmd_msg_rinit {
52 be32 cpus;
53 } __packed;
54
55 #define TRACE_REQ_PARAM_SIZE (2 * sizeof(int))
56 enum trace_req_params {
57 TRACE_REQUEST_ARGS,
58 TRACE_REQUEST_TSYNC_PROTOS,
59 };
60
61 struct tracecmd_msg_trace_req_param {
62 int id;
63 int length;
64 char *value;
65 };
66
67 struct tracecmd_msg_trace_req {
68 be32 flags;
69 be32 argc;
70 u64 trace_id;
71 } __packed;
72
73 struct tracecmd_msg_trace_resp {
74 be32 flags;
75 be32 cpus;
76 be32 page_size;
77 u64 trace_id;
78 char tsync_proto_name[TRACECMD_TSYNC_PNAME_LENGTH];
79 be32 tsync_port;
80 } __packed;
81
82 struct tracecmd_msg_tsync {
83 char sync_protocol_name[TRACECMD_TSYNC_PNAME_LENGTH];
84 be32 sync_msg_id;
85 } __packed;
86
87 struct tracecmd_msg_header {
88 be32 size;
89 be32 cmd;
90 be32 cmd_size;
91 } __packed;
92
93 #define MSG_MAP \
94 C(CLOSE, 0, 0), \
95 C(TINIT, 1, sizeof(struct tracecmd_msg_tinit)), \
96 C(RINIT, 2, sizeof(struct tracecmd_msg_rinit)), \
97 C(SEND_DATA, 3, 0), \
98 C(FIN_DATA, 4, 0), \
99 C(NOT_SUPP, 5, 0), \
100 C(TRACE_REQ, 6, sizeof(struct tracecmd_msg_trace_req)), \
101 C(TRACE_RESP, 7, sizeof(struct tracecmd_msg_trace_resp)),\
102 C(CLOSE_RESP, 8, 0), \
103 C(TIME_SYNC, 9, sizeof(struct tracecmd_msg_tsync)),
104
105 #undef C
106 #define C(a,b,c) MSG_##a = b
107
108 enum tracecmd_msg_cmd {
109 MSG_MAP
110 MSG_NR_COMMANDS
111 };
112
113 #undef C
114 #define C(a,b,c) c
115
116 static be32 msg_cmd_sizes[] = { MSG_MAP };
117
118 #undef C
119 #define C(a,b,c) #a
120
121 static const char *msg_names[] = { MSG_MAP };
122
cmd_to_name(int cmd)123 static const char *cmd_to_name(int cmd)
124 {
125 if (cmd < 0 || cmd >= MSG_NR_COMMANDS)
126 return "Unknown";
127 return msg_names[cmd];
128 }
129
130 struct tracecmd_msg {
131 struct tracecmd_msg_header hdr;
132 union {
133 struct tracecmd_msg_tinit tinit;
134 struct tracecmd_msg_rinit rinit;
135 struct tracecmd_msg_trace_req trace_req;
136 struct tracecmd_msg_trace_resp trace_resp;
137 struct tracecmd_msg_tsync tsync;
138 };
139 char *buf;
140 } __packed;
141
msg_buf_len(struct tracecmd_msg * msg)142 static inline int msg_buf_len(struct tracecmd_msg *msg)
143 {
144 return ntohl(msg->hdr.size) - MSG_HDR_LEN - ntohl(msg->hdr.cmd_size);
145 }
146
__msg_write(int fd,struct tracecmd_msg * msg,bool network)147 static int __msg_write(int fd, struct tracecmd_msg *msg, bool network)
148 {
149 int msg_size, data_size;
150 int ret;
151 int cmd;
152
153 if (network) {
154 cmd = ntohl(msg->hdr.cmd);
155 if (cmd < 0 || cmd >= MSG_NR_COMMANDS)
156 return -EINVAL;
157 dprint("msg send: %d (%s) [%d]\n",
158 cmd, cmd_to_name(cmd), ntohl(msg->hdr.size));
159 }
160 msg_size = MSG_HDR_LEN + ntohl(msg->hdr.cmd_size);
161 data_size = ntohl(msg->hdr.size) - msg_size;
162 if (data_size < 0)
163 return -EINVAL;
164
165 if (network) {
166 ret = __do_write_check(fd, msg, msg_size);
167 if (ret < 0)
168 return ret;
169 }
170 if (!data_size)
171 return 0;
172
173 return __do_write_check(fd, msg->buf, data_size);
174 }
175
msg_lseek(struct tracecmd_msg_handle * msg_handle,off64_t offset,int whence)176 __hidden off64_t msg_lseek(struct tracecmd_msg_handle *msg_handle, off64_t offset, int whence)
177 {
178 /*
179 * lseek works only if the handle is in cache mode,
180 * cannot seek on a network socket
181 */
182 if (!msg_handle->cache || msg_handle->cfd < 0)
183 return (off64_t)-1;
184 return lseek64(msg_handle->cfd, offset, whence);
185 }
186
msg_write(struct tracecmd_msg_handle * msg_handle,struct tracecmd_msg * msg)187 static int msg_write(struct tracecmd_msg_handle *msg_handle, struct tracecmd_msg *msg)
188 {
189 if (msg_handle->cache && msg_handle->cfd >= 0)
190 return __msg_write(msg_handle->cfd, msg, false);
191
192
193 return __msg_write(msg_handle->fd, msg, true);
194 }
195
196 enum msg_trace_flags {
197 MSG_TRACE_USE_FIFOS = 1 << 0,
198 };
199
make_tinit(struct tracecmd_msg_handle * msg_handle,struct tracecmd_msg * msg)200 static int make_tinit(struct tracecmd_msg_handle *msg_handle,
201 struct tracecmd_msg *msg)
202 {
203 int cpu_count = msg_handle->cpu_count;
204 int opt_num = 0;
205 int data_size = 0;
206
207 if (msg_handle->flags & (TRACECMD_MSG_FL_USE_TCP |
208 TRACECMD_MSG_FL_USE_VSOCK)) {
209 msg->buf = msg_handle->flags & TRACECMD_MSG_FL_USE_TCP ?
210 strdup("tcp") : strdup("vsock");
211 if (!msg->buf)
212 return -1;
213 opt_num++;
214 data_size += strlen(msg->buf) + 1;
215 }
216
217 msg->tinit.cpus = htonl(cpu_count);
218 msg->tinit.page_size = htonl(page_size);
219 msg->tinit.opt_num = htonl(opt_num);
220
221 msg->hdr.size = htonl(ntohl(msg->hdr.size) + data_size);
222
223 return 0;
224 }
225
226 /* test a to u */
tatou(const char * s,unsigned int * res)227 static int tatou(const char *s, unsigned int *res)
228 {
229 long r;
230
231 r = atol(s);
232 if (r >= 0 && r <= UINT_MAX) {
233 *res = (unsigned int)r;
234 return 0;
235 }
236 return -1;
237 }
238
write_uints(char * buf,size_t buf_len,unsigned int * arr,int arr_len)239 static int write_uints(char *buf, size_t buf_len,
240 unsigned int *arr, int arr_len)
241 {
242 int i, ret, tot = 0;
243
244 for (i = 0; i < arr_len; i++) {
245 ret = snprintf(buf, buf_len, "%u", arr[i]);
246 if (ret < 0)
247 return ret;
248
249 /* Count the '\0' byte */
250 ret++;
251 tot += ret;
252 if (buf)
253 buf += ret;
254 if (buf_len >= ret)
255 buf_len -= ret;
256 else
257 buf_len = 0;
258 }
259
260 return tot;
261 }
262
make_rinit(struct tracecmd_msg * msg,int cpus,unsigned int * ports)263 static int make_rinit(struct tracecmd_msg *msg, int cpus, unsigned int *ports)
264 {
265 int data_size;
266
267 data_size = write_uints(NULL, 0, ports, cpus);
268 msg->buf = malloc(data_size);
269 if (!msg->buf)
270 return -ENOMEM;
271 write_uints(msg->buf, data_size, ports, cpus);
272
273 msg->rinit.cpus = htonl(cpus);
274 msg->hdr.size = htonl(ntohl(msg->hdr.size) + data_size);
275
276 return 0;
277 }
278
tracecmd_msg_init(u32 cmd,struct tracecmd_msg * msg)279 static void tracecmd_msg_init(u32 cmd, struct tracecmd_msg *msg)
280 {
281 memset(msg, 0, sizeof(*msg));
282 msg->hdr.size = htonl(MSG_HDR_LEN + msg_cmd_sizes[cmd]);
283 msg->hdr.cmd = htonl(cmd);
284 msg->hdr.cmd_size = htonl(msg_cmd_sizes[cmd]);
285 }
286
msg_free(struct tracecmd_msg * msg)287 static void msg_free(struct tracecmd_msg *msg)
288 {
289 free(msg->buf);
290 memset(msg, 0, sizeof(*msg));
291 }
292
tracecmd_msg_send(struct tracecmd_msg_handle * msg_handle,struct tracecmd_msg * msg)293 static int tracecmd_msg_send(struct tracecmd_msg_handle *msg_handle, struct tracecmd_msg *msg)
294 {
295 int ret = 0;
296
297 ret = msg_write(msg_handle, msg);
298 if (ret < 0)
299 ret = -ECOMM;
300
301 msg_free(msg);
302
303 return ret;
304 }
305
msg_send_nofree(struct tracecmd_msg_handle * msg_handle,struct tracecmd_msg * msg)306 static int msg_send_nofree(struct tracecmd_msg_handle *msg_handle, struct tracecmd_msg *msg)
307 {
308 int ret = 0;
309
310 ret = msg_write(msg_handle, msg);
311 if (ret < 0)
312 ret = -ECOMM;
313
314 return ret;
315 }
316
msg_read(int fd,void * buf,u32 size,int * n)317 static int msg_read(int fd, void *buf, u32 size, int *n)
318 {
319 ssize_t r;
320
321 while (size) {
322 r = read(fd, buf + *n, size);
323 if (r < 0) {
324 if (errno == EINTR)
325 continue;
326 return -errno;
327 } else if (!r)
328 return -ENOTCONN;
329 size -= r;
330 *n += r;
331 }
332
333 return 0;
334 }
335
336 static char scratch_buf[MSG_MAX_LEN];
337
msg_read_extra(int fd,struct tracecmd_msg * msg,int * n,int size)338 static int msg_read_extra(int fd, struct tracecmd_msg *msg,
339 int *n, int size)
340 {
341 int cmd, cmd_size, rsize;
342 int ret;
343
344 cmd = ntohl(msg->hdr.cmd);
345 if (cmd < 0 || cmd >= MSG_NR_COMMANDS)
346 return -EINVAL;
347
348 cmd_size = ntohl(msg->hdr.cmd_size);
349 if (cmd_size < 0)
350 return -EINVAL;
351
352 if (cmd_size > 0) {
353 rsize = cmd_size;
354 if (rsize > msg_cmd_sizes[cmd])
355 rsize = msg_cmd_sizes[cmd];
356
357 ret = msg_read(fd, msg, rsize, n);
358 if (ret < 0)
359 return ret;
360
361 ret = msg_read(fd, scratch_buf, cmd_size - rsize, n);
362 if (ret < 0)
363 return ret;
364 }
365
366 if (size > *n) {
367 size -= *n;
368 msg->buf = malloc(size);
369 if (!msg->buf)
370 return -ENOMEM;
371
372 *n = 0;
373 return msg_read(fd, msg->buf, size, n);
374 }
375
376 return 0;
377 }
378
379 /*
380 * Read header information of msg first, then read all data
381 */
tracecmd_msg_recv(int fd,struct tracecmd_msg * msg)382 static int tracecmd_msg_recv(int fd, struct tracecmd_msg *msg)
383 {
384 u32 size = 0;
385 int n = 0;
386 int ret;
387
388 ret = msg_read(fd, msg, MSG_HDR_LEN, &n);
389 if (ret < 0)
390 return ret;
391
392 dprint("msg received: %d (%s) [%d]\n",
393 ntohl(msg->hdr.cmd), cmd_to_name(ntohl(msg->hdr.cmd)),
394 ntohl(msg->hdr.size));
395
396 size = ntohl(msg->hdr.size);
397 if (size > MSG_MAX_LEN)
398 /* too big */
399 goto error;
400 else if (size < MSG_HDR_LEN)
401 /* too small */
402 goto error;
403 else if (size > MSG_HDR_LEN)
404 return msg_read_extra(fd, msg, &n, size);
405
406 return 0;
407 error:
408 tracecmd_plog("Receive an invalid message(size=%d)\n", size);
409 return -ENOMSG;
410 }
411
412 #define MSG_WAIT_MSEC 5000
413 static int msg_wait_to = MSG_WAIT_MSEC;
414
tracecmd_msg_done(struct tracecmd_msg_handle * msg_handle)415 bool tracecmd_msg_done(struct tracecmd_msg_handle *msg_handle)
416 {
417 return (volatile int)msg_handle->done;
418 }
419
tracecmd_msg_set_done(struct tracecmd_msg_handle * msg_handle)420 void tracecmd_msg_set_done(struct tracecmd_msg_handle *msg_handle)
421 {
422 msg_handle->done = true;
423 }
424
error_operation(struct tracecmd_msg * msg)425 static void error_operation(struct tracecmd_msg *msg)
426 {
427 tracecmd_warning("Message: cmd=%d size=%d", ntohl(msg->hdr.cmd), ntohl(msg->hdr.size));
428 }
429
430 /*
431 * A return value of 0 indicates time-out
432 */
tracecmd_msg_recv_wait(int fd,struct tracecmd_msg * msg)433 static int tracecmd_msg_recv_wait(int fd, struct tracecmd_msg *msg)
434 {
435 struct pollfd pfd;
436 int ret;
437
438 pfd.fd = fd;
439 pfd.events = POLLIN;
440 ret = poll(&pfd, 1, tracecmd_get_debug() ? -1 : msg_wait_to);
441 if (ret < 0)
442 return -errno;
443 else if (ret == 0)
444 return -ETIMEDOUT;
445
446 return tracecmd_msg_recv(fd, msg);
447 }
448
tracecmd_msg_wait_for_msg(int fd,struct tracecmd_msg * msg)449 static int tracecmd_msg_wait_for_msg(int fd, struct tracecmd_msg *msg)
450 {
451 u32 cmd;
452 int ret;
453
454 ret = tracecmd_msg_recv_wait(fd, msg);
455 if (ret < 0) {
456 if (ret == -ETIMEDOUT)
457 tracecmd_warning("Connection timed out");
458 return ret;
459 }
460
461 cmd = ntohl(msg->hdr.cmd);
462 if (cmd == MSG_CLOSE)
463 return -ECONNABORTED;
464
465 return 0;
466 }
467
tracecmd_msg_send_notsupp(struct tracecmd_msg_handle * msg_handle)468 static int tracecmd_msg_send_notsupp(struct tracecmd_msg_handle *msg_handle)
469 {
470 struct tracecmd_msg msg;
471
472 tracecmd_msg_init(MSG_NOT_SUPP, &msg);
473 return tracecmd_msg_send(msg_handle, &msg);
474 }
475
handle_unexpected_msg(struct tracecmd_msg_handle * msg_handle,struct tracecmd_msg * msg)476 static int handle_unexpected_msg(struct tracecmd_msg_handle *msg_handle,
477 struct tracecmd_msg *msg)
478 {
479 /* Don't send MSG_NOT_SUPP back if we just received one */
480 if (ntohl(msg->hdr.cmd) == MSG_NOT_SUPP)
481 return 0;
482
483 return tracecmd_msg_send_notsupp(msg_handle);
484
485 }
486
tracecmd_msg_send_init_data(struct tracecmd_msg_handle * msg_handle,unsigned int ** client_ports)487 int tracecmd_msg_send_init_data(struct tracecmd_msg_handle *msg_handle,
488 unsigned int **client_ports)
489 {
490 struct tracecmd_msg msg;
491 unsigned int *ports;
492 int i, cpus, ret;
493 char *p, *buf_end;
494 ssize_t buf_len;
495
496 *client_ports = NULL;
497
498 tracecmd_msg_init(MSG_TINIT, &msg);
499 ret = make_tinit(msg_handle, &msg);
500 if (ret < 0)
501 goto out;
502
503 ret = tracecmd_msg_send(msg_handle, &msg);
504 if (ret < 0)
505 goto out;
506
507 msg_free(&msg);
508
509 ret = tracecmd_msg_wait_for_msg(msg_handle->fd, &msg);
510 if (ret < 0)
511 goto out;
512
513 if (ntohl(msg.hdr.cmd) != MSG_RINIT) {
514 ret = -EOPNOTSUPP;
515 goto error;
516 }
517
518 buf_len = msg_buf_len(&msg);
519 if (buf_len <= 0) {
520 ret = -EINVAL;
521 goto error;
522 }
523
524 if (msg.buf[buf_len-1] != '\0') {
525 ret = -EINVAL;
526 goto error;
527 }
528
529 cpus = ntohl(msg.rinit.cpus);
530 ports = malloc(sizeof(*ports) * cpus);
531 if (!ports) {
532 ret = -ENOMEM;
533 goto out;
534 }
535
536 buf_end = msg.buf + buf_len;
537 for (i = 0, p = msg.buf; i < cpus; i++, p++) {
538 if (p >= buf_end || tatou(p, &ports[i])) {
539 free(ports);
540 ret = -EINVAL;
541 goto error;
542 }
543 p = strchr(p, '\0');
544 }
545
546 *client_ports = ports;
547
548 msg_free(&msg);
549 return 0;
550
551 error:
552 error_operation(&msg);
553 if (ret == -EOPNOTSUPP)
554 handle_unexpected_msg(msg_handle, &msg);
555 out:
556 msg_free(&msg);
557 return ret;
558 }
559
process_option(struct tracecmd_msg_handle * msg_handle,const char * opt)560 static bool process_option(struct tracecmd_msg_handle *msg_handle,
561 const char *opt)
562 {
563 if (strcmp(opt, "tcp") == 0) {
564 msg_handle->flags |= TRACECMD_MSG_FL_USE_TCP;
565 return true;
566 }
567 if (strcmp(opt, "vsock") == 0) {
568 msg_handle->flags |= TRACECMD_MSG_FL_USE_VSOCK;
569 return true;
570 }
571 return false;
572 }
573
574 struct tracecmd_msg_handle *
tracecmd_msg_handle_alloc(int fd,unsigned long flags)575 tracecmd_msg_handle_alloc(int fd, unsigned long flags)
576 {
577 struct tracecmd_msg_handle *handle;
578
579 handle = calloc(1, sizeof(struct tracecmd_msg_handle));
580 if (!handle)
581 return NULL;
582
583 handle->fd = fd;
584 handle->flags = flags;
585 handle->cfd = -1;
586 handle->cache = false;
587 return handle;
588 }
589
tracecmd_msg_handle_cache(struct tracecmd_msg_handle * msg_handle)590 int tracecmd_msg_handle_cache(struct tracecmd_msg_handle *msg_handle)
591 {
592 if (msg_handle->cfd < 0) {
593 strcpy(msg_handle->cfile, MSG_CACHE_FILE);
594 msg_handle->cfd = mkstemp(msg_handle->cfile);
595 if (msg_handle->cfd < 0)
596 return -1;
597 unlink(msg_handle->cfile);
598 }
599 msg_handle->cache = true;
600 return 0;
601 }
602
flush_cache(struct tracecmd_msg_handle * msg_handle)603 static int flush_cache(struct tracecmd_msg_handle *msg_handle)
604 {
605 char buf[MSG_MAX_DATA_LEN];
606 int ret;
607
608 if (!msg_handle->cache || msg_handle->cfd < 0)
609 return 0;
610 msg_handle->cache = false;
611 if (lseek64(msg_handle->cfd, 0, SEEK_SET) == (off64_t)-1)
612 return -1;
613 do {
614 ret = read(msg_handle->cfd, buf, MSG_MAX_DATA_LEN);
615 if (ret <= 0)
616 break;
617 ret = tracecmd_msg_data_send(msg_handle, buf, ret);
618 if (ret < 0)
619 break;
620 } while (ret >= 0);
621
622 close(msg_handle->cfd);
623 msg_handle->cfd = -1;
624 return ret;
625 }
626
tracecmd_msg_handle_close(struct tracecmd_msg_handle * msg_handle)627 void tracecmd_msg_handle_close(struct tracecmd_msg_handle *msg_handle)
628 {
629 if (msg_handle->fd >= 0)
630 close(msg_handle->fd);
631 if (msg_handle->cfd >= 0)
632 close(msg_handle->cfd);
633 free(msg_handle);
634 }
635
636 #define MAX_OPTION_SIZE 4096
637
tracecmd_msg_initial_setting(struct tracecmd_msg_handle * msg_handle)638 int tracecmd_msg_initial_setting(struct tracecmd_msg_handle *msg_handle)
639 {
640 struct tracecmd_msg msg;
641 char *p, *buf_end;
642 ssize_t buf_len;
643 int pagesize;
644 int options, i;
645 int cpus;
646 int ret;
647
648 memset(&msg, 0, sizeof(msg));
649 ret = tracecmd_msg_recv_wait(msg_handle->fd, &msg);
650 if (ret < 0) {
651 if (ret == -ETIMEDOUT)
652 tracecmd_warning("Connection timed out");
653 return ret;
654 }
655
656 if (ntohl(msg.hdr.cmd) != MSG_TINIT) {
657 ret = -EOPNOTSUPP;
658 goto error;
659 }
660
661 cpus = ntohl(msg.tinit.cpus);
662 tracecmd_plog("cpus=%d\n", cpus);
663 if (cpus < 0) {
664 ret = -EINVAL;
665 goto error;
666 }
667
668 msg_handle->cpu_count = cpus;
669
670 pagesize = ntohl(msg.tinit.page_size);
671 tracecmd_plog("pagesize=%d\n", pagesize);
672 if (pagesize <= 0) {
673 ret = -EINVAL;
674 goto error;
675 }
676
677 buf_len = msg_buf_len(&msg);
678 if (buf_len < 0) {
679 ret = -EINVAL;
680 goto error;
681 }
682
683 if (buf_len == 0)
684 goto no_options;
685
686 if (msg.buf[buf_len-1] != '\0') {
687 ret = -EINVAL;
688 goto error;
689 }
690
691 buf_end = msg.buf + buf_len;
692 options = ntohl(msg.tinit.opt_num);
693 for (i = 0, p = msg.buf; i < options; i++, p++) {
694 if (p >= buf_end) {
695 ret = -EINVAL;
696 goto error;
697 }
698
699 /* do we understand this option? */
700 if (!process_option(msg_handle, p))
701 tracecmd_plog("Cannot understand option '%s'\n", p);
702
703 p = strchr(p, '\0');
704 }
705
706 no_options:
707 msg_free(&msg);
708 return pagesize;
709
710 error:
711 error_operation(&msg);
712 if (ret == -EOPNOTSUPP)
713 handle_unexpected_msg(msg_handle, &msg);
714 msg_free(&msg);
715 return ret;
716 }
717
tracecmd_msg_send_port_array(struct tracecmd_msg_handle * msg_handle,unsigned int * ports)718 int tracecmd_msg_send_port_array(struct tracecmd_msg_handle *msg_handle,
719 unsigned int *ports)
720 {
721 struct tracecmd_msg msg;
722 int ret;
723
724 tracecmd_msg_init(MSG_RINIT, &msg);
725 ret = make_rinit(&msg, msg_handle->cpu_count, ports);
726 if (ret < 0)
727 return ret;
728
729 ret = tracecmd_msg_send(msg_handle, &msg);
730 if (ret < 0)
731 return ret;
732
733 return 0;
734 }
735
tracecmd_msg_send_close_msg(struct tracecmd_msg_handle * msg_handle)736 int tracecmd_msg_send_close_msg(struct tracecmd_msg_handle *msg_handle)
737 {
738 struct tracecmd_msg msg;
739
740 tracecmd_msg_init(MSG_CLOSE, &msg);
741 return tracecmd_msg_send(msg_handle, &msg);
742 }
743
tracecmd_msg_send_close_resp_msg(struct tracecmd_msg_handle * msg_handle)744 int tracecmd_msg_send_close_resp_msg(struct tracecmd_msg_handle *msg_handle)
745 {
746 struct tracecmd_msg msg;
747
748 tracecmd_msg_init(MSG_CLOSE_RESP, &msg);
749 return tracecmd_msg_send(msg_handle, &msg);
750 }
751
tracecmd_msg_data_send(struct tracecmd_msg_handle * msg_handle,const char * buf,int size)752 int tracecmd_msg_data_send(struct tracecmd_msg_handle *msg_handle,
753 const char *buf, int size)
754 {
755 struct tracecmd_msg msg;
756 int n;
757 int ret;
758 int count = 0;
759
760 /* Don't bother doing anything if there's nothing to do */
761 if (!size)
762 return 0;
763
764 tracecmd_msg_init(MSG_SEND_DATA, &msg);
765
766 msg.buf = malloc(MSG_MAX_DATA_LEN);
767 if (!msg.buf)
768 return -ENOMEM;
769
770 msg.hdr.size = htonl(MSG_MAX_LEN);
771
772 n = size;
773 while (n) {
774 if (n > MSG_MAX_DATA_LEN) {
775 memcpy(msg.buf, buf + count, MSG_MAX_DATA_LEN);
776 n -= MSG_MAX_DATA_LEN;
777 count += MSG_MAX_DATA_LEN;
778 } else {
779 msg.hdr.size = htonl(MSG_HDR_LEN + n);
780 memcpy(msg.buf, buf + count, n);
781 n = 0;
782 }
783 ret = msg_write(msg_handle, &msg);
784 if (ret < 0)
785 break;
786 }
787
788 msg_free(&msg);
789 return ret;
790 }
791
tracecmd_msg_finish_sending_data(struct tracecmd_msg_handle * msg_handle)792 int tracecmd_msg_finish_sending_data(struct tracecmd_msg_handle *msg_handle)
793 {
794 struct tracecmd_msg msg;
795 int ret;
796
797 flush_cache(msg_handle);
798 tracecmd_msg_init(MSG_FIN_DATA, &msg);
799 ret = tracecmd_msg_send(msg_handle, &msg);
800 if (ret < 0)
801 return ret;
802 return 0;
803 }
804
tracecmd_msg_read_data(struct tracecmd_msg_handle * msg_handle,int ofd)805 int tracecmd_msg_read_data(struct tracecmd_msg_handle *msg_handle, int ofd)
806 {
807 struct tracecmd_msg msg;
808 int t, n, cmd;
809 ssize_t s;
810 int ret;
811
812 while (!tracecmd_msg_done(msg_handle)) {
813 ret = tracecmd_msg_recv_wait(msg_handle->fd, &msg);
814 if (ret < 0) {
815 tracecmd_warning("reading client %d (%s)", ret, strerror(ret));
816 return ret;
817 }
818
819 cmd = ntohl(msg.hdr.cmd);
820 if (cmd == MSG_FIN_DATA) {
821 /* Finish receiving data */
822 break;
823 } else if (cmd != MSG_SEND_DATA) {
824 ret = handle_unexpected_msg(msg_handle, &msg);
825 if (ret < 0)
826 goto error;
827 goto next;
828 }
829
830 n = msg_buf_len(&msg);
831 t = n;
832 s = 0;
833 while (t > 0) {
834 s = write(ofd, msg.buf+s, t);
835 if (s < 0) {
836 if (errno == EINTR)
837 continue;
838 tracecmd_warning("writing to file");
839 ret = -errno;
840 goto error;
841 }
842 t -= s;
843 s = n - t;
844 }
845
846 next:
847 msg_free(&msg);
848 }
849
850 return 0;
851
852 error:
853 error_operation(&msg);
854 msg_free(&msg);
855 return ret;
856 }
857
tracecmd_msg_collect_data(struct tracecmd_msg_handle * msg_handle,int ofd)858 int tracecmd_msg_collect_data(struct tracecmd_msg_handle *msg_handle, int ofd)
859 {
860 int ret;
861
862 ret = tracecmd_msg_read_data(msg_handle, ofd);
863 if (ret)
864 return ret;
865
866 return tracecmd_msg_wait_close(msg_handle);
867 }
868
tracecmd_msg_wait_for_cmd(struct tracecmd_msg_handle * msg_handle,enum tracecmd_msg_cmd cmd)869 static int tracecmd_msg_wait_for_cmd(struct tracecmd_msg_handle *msg_handle, enum tracecmd_msg_cmd cmd)
870 {
871 struct tracecmd_msg msg;
872 int ret = -1;
873
874 memset(&msg, 0, sizeof(msg));
875 while (!tracecmd_msg_done(msg_handle)) {
876 ret = tracecmd_msg_recv(msg_handle->fd, &msg);
877 if (ret < 0)
878 goto error;
879
880 if (ntohl(msg.hdr.cmd) == cmd)
881 return 0;
882
883 error_operation(&msg);
884 ret = handle_unexpected_msg(msg_handle, &msg);
885 if (ret < 0)
886 goto error;
887
888 msg_free(&msg);
889 }
890
891 error:
892 msg_free(&msg);
893 return ret;
894 }
895
tracecmd_msg_wait_close(struct tracecmd_msg_handle * msg_handle)896 int tracecmd_msg_wait_close(struct tracecmd_msg_handle *msg_handle)
897 {
898 return tracecmd_msg_wait_for_cmd(msg_handle, MSG_CLOSE);
899 }
900
tracecmd_msg_wait_close_resp(struct tracecmd_msg_handle * msg_handle)901 int tracecmd_msg_wait_close_resp(struct tracecmd_msg_handle *msg_handle)
902 {
903 return tracecmd_msg_wait_for_cmd(msg_handle, MSG_CLOSE_RESP);
904 }
905
make_trace_req_protos(char ** buf,int * size,struct tracecmd_tsync_protos * protos)906 static int make_trace_req_protos(char **buf, int *size,
907 struct tracecmd_tsync_protos *protos)
908 {
909 int protos_size = 1;
910 size_t buf_size;
911 char **names;
912 char *nbuf;
913 char *p;
914
915 names = protos->names;
916 while (*names) {
917 protos_size += strlen(*names) + 1;
918 names++;
919 }
920
921 buf_size = TRACE_REQ_PARAM_SIZE + protos_size;
922 nbuf = realloc(*buf, *size + buf_size);
923 if (!nbuf)
924 return -1;
925
926 p = nbuf + *size;
927 memset(p, 0, buf_size);
928
929 *(unsigned int *)p = htonl(TRACE_REQUEST_TSYNC_PROTOS);
930 p += sizeof(int);
931 *(unsigned int *)p = htonl(protos_size);
932 p += sizeof(int);
933
934 names = protos->names;
935 while (*names) {
936 strcpy(p, *names);
937 p += strlen(*names) + 1;
938 names++;
939 }
940 p = NULL;
941
942 *size += buf_size;
943 *buf = nbuf;
944 return 0;
945 }
946
make_trace_req_args(char ** buf,int * size,int argc,char ** argv)947 static int make_trace_req_args(char **buf, int *size, int argc, char **argv)
948 {
949 size_t args_size;
950 size_t buf_size;
951 char *nbuf;
952 char *p;
953 int i;
954
955 args_size = sizeof(int);
956 for (i = 0; i < argc; i++)
957 args_size += strlen(argv[i]) + 1;
958
959 buf_size = TRACE_REQ_PARAM_SIZE + args_size;
960 nbuf = realloc(*buf, *size + buf_size);
961 if (!nbuf)
962 return -1;
963
964 p = nbuf + *size;
965 memset(p, 0, buf_size);
966
967 *(unsigned int *)p = htonl(TRACE_REQUEST_ARGS);
968 p += sizeof(int);
969 *(unsigned int *)p = htonl(args_size);
970 p += sizeof(int);
971
972 *(unsigned int *)p = htonl(argc);
973 p += sizeof(int);
974 for (i = 0; i < argc; i++)
975 p = stpcpy(p, argv[i]) + 1;
976
977 *size += buf_size;
978 *buf = nbuf;
979 return 0;
980 }
981
make_trace_req(struct tracecmd_msg * msg,int argc,char ** argv,bool use_fifos,unsigned long long trace_id,struct tracecmd_tsync_protos * protos)982 static int make_trace_req(struct tracecmd_msg *msg, int argc, char **argv,
983 bool use_fifos, unsigned long long trace_id,
984 struct tracecmd_tsync_protos *protos)
985 {
986 int size = 0;
987 char *buf = NULL;
988
989 msg->trace_req.flags = 0;
990 if (use_fifos)
991 msg->trace_req.flags |= MSG_TRACE_USE_FIFOS;
992 msg->trace_req.flags = htonl(msg->trace_req.flags);
993 msg->trace_req.trace_id = htonll(trace_id);
994
995 if (argc && argv)
996 make_trace_req_args(&buf, &size, argc, argv);
997 if (protos && protos->names)
998 make_trace_req_protos(&buf, &size, protos);
999
1000 msg->buf = buf;
1001 msg->hdr.size = htonl(ntohl(msg->hdr.size) + size);
1002
1003 return 0;
1004 }
1005
tracecmd_msg_send_trace_req(struct tracecmd_msg_handle * msg_handle,int argc,char ** argv,bool use_fifos,unsigned long long trace_id,struct tracecmd_tsync_protos * protos)1006 int tracecmd_msg_send_trace_req(struct tracecmd_msg_handle *msg_handle,
1007 int argc, char **argv, bool use_fifos,
1008 unsigned long long trace_id,
1009 struct tracecmd_tsync_protos *protos)
1010 {
1011 struct tracecmd_msg msg;
1012 int ret;
1013
1014 tracecmd_msg_init(MSG_TRACE_REQ, &msg);
1015 ret = make_trace_req(&msg, argc, argv, use_fifos, trace_id, protos);
1016 if (ret < 0)
1017 return ret;
1018
1019 return tracecmd_msg_send(msg_handle, &msg);
1020 }
1021
get_trace_req_protos(char * buf,int length,struct tracecmd_tsync_protos ** protos)1022 static int get_trace_req_protos(char *buf, int length,
1023 struct tracecmd_tsync_protos **protos)
1024 {
1025 struct tracecmd_tsync_protos *plist = NULL;
1026 int count = 0;
1027 char *p;
1028 int i, j;
1029
1030 i = length;
1031 p = buf;
1032 while (i > 0) {
1033 i -= strlen(p) + 1;
1034 count++;
1035 p += strlen(p) + 1;
1036 }
1037
1038 plist = calloc(1, sizeof(struct tracecmd_tsync_protos));
1039 if (!plist)
1040 goto error;
1041 plist->names = calloc(count + 1, sizeof(char *));
1042 if (!plist->names)
1043 goto error;
1044 i = length;
1045 p = buf;
1046 j = 0;
1047 while (i > 0 && j < (count - 1)) {
1048 i -= strlen(p) + 1;
1049 plist->names[j++] = strdup(p);
1050 p += strlen(p) + 1;
1051 }
1052
1053 *protos = plist;
1054 return 0;
1055 error:
1056 if (plist) {
1057 free(plist->names);
1058 free(plist);
1059 }
1060 return -1;
1061 }
1062
get_trace_req_args(char * buf,int length,int * argc,char *** argv)1063 static int get_trace_req_args(char *buf, int length, int *argc, char ***argv)
1064 {
1065 unsigned int nr_args;
1066 char *p, *buf_end;
1067 char **args = NULL;
1068 char *vagrs = NULL;
1069 int ret;
1070 int i;
1071
1072 if (length <= sizeof(int) || buf[length - 1] != '\0') {
1073 ret = -EINVAL;
1074 goto out;
1075 }
1076
1077 nr_args = ntohl(*(unsigned int *)buf);
1078 buf += sizeof(int);
1079 length -= sizeof(int);
1080
1081 args = calloc(nr_args, sizeof(*args));
1082 if (!args) {
1083 ret = -ENOMEM;
1084 goto out;
1085 }
1086
1087 vagrs = calloc(length, sizeof(char));
1088 if (!vagrs) {
1089 ret = -ENOMEM;
1090 goto out;
1091 }
1092
1093 memcpy(vagrs, buf, length);
1094 buf_end = vagrs + length;
1095 for (i = 0, p = vagrs; i < nr_args; i++, p++) {
1096 if (p >= buf_end) {
1097 ret = -EINVAL;
1098 goto out;
1099 }
1100 args[i] = p;
1101 p = strchr(p, '\0');
1102 }
1103
1104 *argc = nr_args;
1105 *argv = args;
1106 return 0;
1107
1108 out:
1109 free(args);
1110 free(vagrs);
1111 return ret;
1112
1113 }
1114
1115 /*
1116 * NOTE: On success, the returned `argv` should be freed with:
1117 * free(argv[0]);
1118 * free(argv);
1119 * and `tsync_protos` with free(tsync_protos);
1120 */
tracecmd_msg_recv_trace_req(struct tracecmd_msg_handle * msg_handle,int * argc,char *** argv,bool * use_fifos,unsigned long long * trace_id,struct tracecmd_tsync_protos ** protos)1121 int tracecmd_msg_recv_trace_req(struct tracecmd_msg_handle *msg_handle,
1122 int *argc, char ***argv, bool *use_fifos,
1123 unsigned long long *trace_id,
1124 struct tracecmd_tsync_protos **protos)
1125 {
1126 struct tracecmd_msg msg;
1127 unsigned int param_id;
1128 int param_length;
1129 ssize_t buf_len;
1130 char *p;
1131 int ret;
1132
1133 ret = tracecmd_msg_recv(msg_handle->fd, &msg);
1134 if (ret < 0)
1135 return ret;
1136
1137 if (ntohl(msg.hdr.cmd) != MSG_TRACE_REQ) {
1138 ret = -ENOTSUP;
1139 goto out;
1140 }
1141
1142 buf_len = ntohl(msg.hdr.size) - MSG_HDR_LEN - ntohl(msg.hdr.cmd_size);
1143 if (buf_len < 0) {
1144 ret = -EINVAL;
1145 goto out;
1146 }
1147
1148 *use_fifos = ntohl(msg.trace_req.flags) & MSG_TRACE_USE_FIFOS;
1149 *trace_id = ntohll(msg.trace_req.trace_id);
1150 p = msg.buf;
1151 while (buf_len > 2 * sizeof(int)) {
1152 param_id = ntohl(*((unsigned int *)p));
1153 p += sizeof(int);
1154 buf_len -= sizeof(int);
1155 param_length = ntohl(*((unsigned int *)p));
1156 p += sizeof(int);
1157 buf_len -= sizeof(int);
1158 if (buf_len < param_length)
1159 break;
1160 ret = 0;
1161 switch (param_id) {
1162 case TRACE_REQUEST_ARGS:
1163 ret = get_trace_req_args(p, param_length, argc, argv);
1164 break;
1165 case TRACE_REQUEST_TSYNC_PROTOS:
1166 ret = get_trace_req_protos(p, param_length, protos);
1167 break;
1168 default:
1169 break;
1170 }
1171 if (ret)
1172 break;
1173 buf_len -= param_length;
1174 p += param_length;
1175 }
1176
1177 msg_free(&msg);
1178 return 0;
1179
1180 out:
1181 error_operation(&msg);
1182 if (ret == -EOPNOTSUPP)
1183 handle_unexpected_msg(msg_handle, &msg);
1184 msg_free(&msg);
1185 return ret;
1186 }
1187
1188 /**
1189 * tracecmd_msg_send_time_sync - Send a time sync packet
1190 * @msg_handle: message handle, holding the communication context
1191 * @sync_protocol: name of the time synch protocol, string up to
1192 * TRACECMD_TSYNC_PNAME_LENGTH characters length.
1193 * @sync_msg_id: id if the time synch message, protocol dependent
1194 * @payload_size: size of the packet payload, 0 in case of no payload
1195 * @payload: pointer to the packet payload, or NULL in case of no payload
1196 *
1197 * Returns 0 if packet is sent successfully, or negative error otherwise.
1198 */
tracecmd_msg_send_time_sync(struct tracecmd_msg_handle * msg_handle,char * sync_protocol,unsigned int sync_msg_id,unsigned int payload_size,char * payload)1199 int tracecmd_msg_send_time_sync(struct tracecmd_msg_handle *msg_handle,
1200 char *sync_protocol, unsigned int sync_msg_id,
1201 unsigned int payload_size, char *payload)
1202 {
1203 struct tracecmd_msg msg;
1204
1205 tracecmd_msg_init(MSG_TIME_SYNC, &msg);
1206 strncpy(msg.tsync.sync_protocol_name, sync_protocol, TRACECMD_TSYNC_PNAME_LENGTH);
1207 msg.tsync.sync_msg_id = htonl(sync_msg_id);
1208 msg.hdr.size = htonl(ntohl(msg.hdr.size) + payload_size);
1209
1210 msg.buf = payload;
1211 return msg_send_nofree(msg_handle, &msg);
1212 }
1213
1214 /**
1215 * tracecmd_msg_recv_time_sync - Receive a time sync packet
1216 * @msg_handle: message handle, holding the communication context
1217 * @sync_protocol: return the name of the packet's time synch protocol.
1218 * It must point to a prealocated buffer with size
1219 * TRACECMD_TSYNC_PNAME_LENGTH
1220 * @sync_msg_id: return the id of the packet's time synch message
1221 * @payload_size: size of the packet's payload, can be:
1222 * NULL - the payload is not interested and should be ignored
1223 * pointer to int, with value 0 - update with the size of the payload
1224 * allocate memory and cpy the payload
1225 * into it
1226 * pointer to int, with value greater than 0 - expected size of the
1227 * payload, preallocated
1228 * memory is passed to the API
1229 * with that size
1230 *@payload: pointer to the packet payload, can be:
1231 * NULL - the payload is not interested and should be ignored
1232 * pointer to char *, with value NULL - a new memory is allocated and returned
1233 * here, containing the packet's payload
1234 * the @payload_size is updated with the
1235 * size of the allocated memory. It must be
1236 * freed by free()
1237 * pointer to char *, with no-NULL value - A prealocated array is passed, with size
1238 * @payload_size. If payload's size is equal
1239 * or less, it will be copied here.
1240 *
1241 * Returns 0 if packet is received successfully, or negative error otherwise.
1242 */
tracecmd_msg_recv_time_sync(struct tracecmd_msg_handle * msg_handle,char * sync_protocol,unsigned int * sync_msg_id,unsigned int * payload_size,char ** payload)1243 int tracecmd_msg_recv_time_sync(struct tracecmd_msg_handle *msg_handle,
1244 char *sync_protocol,
1245 unsigned int *sync_msg_id,
1246 unsigned int *payload_size, char **payload)
1247 {
1248 struct tracecmd_msg msg;
1249 int ret = -1;
1250 int buf_size;
1251
1252 memset(&msg, 0, sizeof(msg));
1253 ret = tracecmd_msg_recv(msg_handle->fd, &msg);
1254 if (ret < 0)
1255 goto out;
1256
1257 if (ntohl(msg.hdr.cmd) != MSG_TIME_SYNC) {
1258 ret = -EOPNOTSUPP;
1259 goto out;
1260 }
1261
1262 if (sync_protocol)
1263 strncpy(sync_protocol, msg.tsync.sync_protocol_name,
1264 TRACECMD_TSYNC_PNAME_LENGTH);
1265 if (sync_msg_id)
1266 *sync_msg_id = ntohl(msg.tsync.sync_msg_id);
1267
1268 buf_size = msg_buf_len(&msg);
1269 if (buf_size < 0) {
1270 ret = -EINVAL;
1271 goto out;
1272 }
1273
1274 if (buf_size && payload && payload_size) {
1275 if (*payload_size) {
1276 if (*payload_size < buf_size || *payload == NULL) {
1277 ret = -ENOMEM;
1278 goto out;
1279 }
1280 memcpy(*payload, msg.buf, buf_size);
1281 goto out;
1282 }
1283
1284 *payload = malloc(buf_size);
1285 if (*payload == NULL) {
1286 ret = -ENOMEM;
1287 goto out;
1288 }
1289 *payload_size = buf_size;
1290 memcpy(*payload, msg.buf, buf_size);
1291 }
1292
1293 out:
1294 msg_free(&msg);
1295 return ret;
1296 }
1297
make_trace_resp(struct tracecmd_msg * msg,int page_size,int nr_cpus,unsigned int * ports,bool use_fifos,unsigned long long trace_id,const char * tsync_proto,unsigned int tsync_port)1298 static int make_trace_resp(struct tracecmd_msg *msg, int page_size, int nr_cpus,
1299 unsigned int *ports, bool use_fifos,
1300 unsigned long long trace_id,
1301 const char *tsync_proto,
1302 unsigned int tsync_port)
1303 {
1304 int data_size;
1305
1306 if (!tsync_proto)
1307 tsync_proto = "";
1308
1309 data_size = write_uints(NULL, 0, ports, nr_cpus);
1310 msg->buf = malloc(data_size);
1311 if (!msg->buf)
1312 return -ENOMEM;
1313 write_uints(msg->buf, data_size, ports, nr_cpus);
1314
1315 msg->hdr.size = htonl(ntohl(msg->hdr.size) + data_size);
1316 msg->trace_resp.flags = use_fifos ? MSG_TRACE_USE_FIFOS : 0;
1317 msg->trace_resp.flags = htonl(msg->trace_resp.flags);
1318 strncpy(msg->trace_resp.tsync_proto_name, tsync_proto, TRACECMD_TSYNC_PNAME_LENGTH);
1319 msg->trace_resp.tsync_port = htonl(tsync_port);
1320
1321 msg->trace_resp.cpus = htonl(nr_cpus);
1322 msg->trace_resp.page_size = htonl(page_size);
1323 msg->trace_resp.trace_id = htonll(trace_id);
1324
1325 return 0;
1326 }
1327
tracecmd_msg_send_trace_resp(struct tracecmd_msg_handle * msg_handle,int nr_cpus,int page_size,unsigned int * ports,bool use_fifos,unsigned long long trace_id,const char * tsync_proto,unsigned int tsync_port)1328 int tracecmd_msg_send_trace_resp(struct tracecmd_msg_handle *msg_handle,
1329 int nr_cpus, int page_size,
1330 unsigned int *ports, bool use_fifos,
1331 unsigned long long trace_id,
1332 const char *tsync_proto, unsigned int tsync_port)
1333 {
1334 struct tracecmd_msg msg;
1335 int ret;
1336
1337 tracecmd_msg_init(MSG_TRACE_RESP, &msg);
1338 ret = make_trace_resp(&msg, page_size, nr_cpus, ports,
1339 use_fifos, trace_id, tsync_proto, tsync_port);
1340 if (ret < 0)
1341 return ret;
1342
1343 return tracecmd_msg_send(msg_handle, &msg);
1344 }
1345
tracecmd_msg_recv_trace_resp(struct tracecmd_msg_handle * msg_handle,int * nr_cpus,int * page_size,unsigned int ** ports,bool * use_fifos,unsigned long long * trace_id,char ** tsync_proto,unsigned int * tsync_port)1346 int tracecmd_msg_recv_trace_resp(struct tracecmd_msg_handle *msg_handle,
1347 int *nr_cpus, int *page_size,
1348 unsigned int **ports, bool *use_fifos,
1349 unsigned long long *trace_id,
1350 char **tsync_proto,
1351 unsigned int *tsync_port)
1352 {
1353 struct tracecmd_msg msg;
1354 char *p, *buf_end;
1355 ssize_t buf_len;
1356 int i, ret;
1357
1358 ret = tracecmd_msg_recv(msg_handle->fd, &msg);
1359 if (ret < 0)
1360 return ret;
1361
1362 if (ntohl(msg.hdr.cmd) != MSG_TRACE_RESP) {
1363 ret = -ENOTSUP;
1364 goto out;
1365 }
1366
1367 buf_len = msg_buf_len(&msg);
1368 if (buf_len <= 0) {
1369 ret = -EINVAL;
1370 goto out;
1371 }
1372
1373 *use_fifos = ntohl(msg.trace_resp.flags) & MSG_TRACE_USE_FIFOS;
1374 *nr_cpus = ntohl(msg.trace_resp.cpus);
1375 *page_size = ntohl(msg.trace_resp.page_size);
1376 *trace_id = ntohll(msg.trace_resp.trace_id);
1377 *tsync_proto = strdup(msg.trace_resp.tsync_proto_name);
1378 *tsync_port = ntohl(msg.trace_resp.tsync_port);
1379 *ports = calloc(*nr_cpus, sizeof(**ports));
1380 if (!*ports) {
1381 ret = -ENOMEM;
1382 goto out;
1383 }
1384
1385 buf_end = msg.buf + buf_len;
1386 for (i = 0, p = msg.buf; i < *nr_cpus; i++, p++) {
1387 if (p >= buf_end || tatou(p, &(*ports)[i])) {
1388 free(*ports);
1389 ret = -EINVAL;
1390 goto out;
1391 }
1392 p = strchr(p, '\0');
1393 }
1394
1395 msg_free(&msg);
1396 return 0;
1397
1398 out:
1399 error_operation(&msg);
1400 if (ret == -EOPNOTSUPP)
1401 handle_unexpected_msg(msg_handle, &msg);
1402 msg_free(&msg);
1403 return ret;
1404 }
1405