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