1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
4 *
5 */
6 #include <dirent.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <getopt.h>
11 #include <limits.h>
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <sys/wait.h>
15 #include <netdb.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <signal.h>
19 #include <errno.h>
20
21 #ifdef VSOCK
22 #include <linux/vm_sockets.h>
23 #endif
24
25 #include "trace-local.h"
26 #include "trace-msg.h"
27
28 #define dprint(fmt, ...) tracecmd_debug(fmt, ##__VA_ARGS__)
29
30 #define MAX_OPTION_SIZE 4096
31
32 #define _VAR_DIR_Q(dir) #dir
33 #define VAR_DIR_Q(dir) _VAR_DIR_Q(dir)
34
35 #define VAR_RUN_DIR VAR_DIR_Q(VAR_DIR) "/run"
36
37 #define LISTEN_PIDFILE "trace-cmd-net.pid"
38
39 static char *default_output_dir = ".";
40 static char *output_dir;
41 static char *default_output_file = "trace";
42 static char *output_file;
43
44 static bool use_vsock;
45
46 static int backlog = 5;
47
48 static int do_daemon;
49
50 /* Used for signaling INT to finish */
51 static struct tracecmd_msg_handle *stop_msg_handle;
52 static bool done;
53
54 #define pdie(fmt, ...) \
55 do { \
56 tracecmd_plog_error(fmt, ##__VA_ARGS__);\
57 if (do_daemon) \
58 remove_pid_file(LISTEN_PIDFILE);\
59 exit(-1); \
60 } while (0)
61
62 #define TEMP_FILE_STR "%s.%s:%s.cpu%d", output_file, host, port, cpu
get_temp_file(const char * host,const char * port,int cpu)63 static char *get_temp_file(const char *host, const char *port, int cpu)
64 {
65 char *file = NULL;
66 int size;
67
68 size = snprintf(file, 0, TEMP_FILE_STR);
69 file = malloc(size + 1);
70 if (!file)
71 return NULL;
72 sprintf(file, TEMP_FILE_STR);
73
74 return file;
75 }
76
put_temp_file(char * file)77 static void put_temp_file(char *file)
78 {
79 free(file);
80 }
81
signal_setup(int sig,sighandler_t handle)82 static void signal_setup(int sig, sighandler_t handle)
83 {
84 struct sigaction action;
85
86 sigaction(sig, NULL, &action);
87 /* Make accept return EINTR */
88 action.sa_flags &= ~SA_RESTART;
89 action.sa_handler = handle;
90 sigaction(sig, &action, NULL);
91 }
92
delete_temp_file(const char * host,const char * port,int cpu)93 static void delete_temp_file(const char *host, const char *port, int cpu)
94 {
95 char file[PATH_MAX];
96
97 snprintf(file, PATH_MAX, TEMP_FILE_STR);
98 unlink(file);
99 }
100
read_string(int fd,char * buf,size_t size)101 static int read_string(int fd, char *buf, size_t size)
102 {
103 size_t i;
104 int n;
105
106 for (i = 0; i < size; i++) {
107 n = read(fd, buf+i, 1);
108 if (!buf[i] || n <= 0)
109 break;
110 }
111
112 return i;
113 }
114
process_option(struct tracecmd_msg_handle * msg_handle,char * option)115 static int process_option(struct tracecmd_msg_handle *msg_handle, char *option)
116 {
117 /* currently the only option we have is to us TCP */
118 if (strcmp(option, "TCP") == 0) {
119 msg_handle->flags |= TRACECMD_MSG_FL_USE_TCP;
120 return 1;
121 }
122 return 0;
123 }
124
finish(int sig)125 static void finish(int sig)
126 {
127 if (stop_msg_handle)
128 tracecmd_msg_set_done(stop_msg_handle);
129 done = true;
130 }
131
make_pid_name(char * buf,const char * pidfile_basename)132 void make_pid_name(char *buf, const char *pidfile_basename)
133 {
134 snprintf(buf, PATH_MAX, VAR_RUN_DIR "/%s", pidfile_basename);
135 }
136
remove_pid_file(const char * pidfile_basename)137 void remove_pid_file(const char *pidfile_basename)
138 {
139 char buf[PATH_MAX];
140
141 make_pid_name(buf, pidfile_basename);
142 unlink(buf);
143 }
144
process_child(int sfd,const char * host,const char * port,int cpu,int page_size,enum port_type type)145 static int process_child(int sfd, const char *host, const char *port,
146 int cpu, int page_size, enum port_type type)
147 {
148 struct sockaddr_storage peer_addr;
149 #ifdef VSOCK
150 struct sockaddr_vm vm_addr;
151 #endif
152 struct sockaddr *addr;
153 socklen_t addr_len;
154 char buf[page_size];
155 char *tempfile;
156 int left;
157 int cfd;
158 int fd;
159 int r, w;
160 int once = 0;
161
162 signal_setup(SIGUSR1, finish);
163
164 tempfile = get_temp_file(host, port, cpu);
165 if (!tempfile)
166 return -ENOMEM;
167
168 fd = open(tempfile, O_WRONLY | O_TRUNC | O_CREAT, 0644);
169 if (fd < 0)
170 pdie("creating %s", tempfile);
171
172 if (type == USE_TCP) {
173 addr = (struct sockaddr *)&peer_addr;
174 addr_len = sizeof(peer_addr);
175 #ifdef VSOCK
176 } else if (type == USE_VSOCK) {
177 addr = (struct sockaddr *)&vm_addr;
178 addr_len = sizeof(vm_addr);
179 #endif
180 }
181
182 if (type == USE_TCP || type == USE_VSOCK) {
183 if (listen(sfd, backlog) < 0)
184 pdie("listen");
185
186 cfd = accept(sfd, addr, &addr_len);
187 if (cfd < 0 && errno == EINTR)
188 goto done;
189 if (cfd < 0)
190 pdie("accept");
191 close(sfd);
192 sfd = cfd;
193 }
194
195 for (;;) {
196 /* TODO, make this copyless! */
197 r = read(sfd, buf, page_size);
198 if (r < 0) {
199 if (errno == EINTR)
200 break;
201 pdie("reading pages from client");
202 }
203 if (!r)
204 break;
205 /* UDP requires that we get the full size in one go */
206 if (type == USE_UDP && r < page_size && !once) {
207 once = 1;
208 warning("read %d bytes, expected %d", r, page_size);
209 }
210
211 left = r;
212 do {
213 w = write(fd, buf + (r - left), left);
214 if (w > 0)
215 left -= w;
216 } while (w >= 0 && left);
217 }
218
219 done:
220 put_temp_file(tempfile);
221 exit(0);
222 }
223
setup_vsock_port(int start_port,int * sfd)224 static int setup_vsock_port(int start_port, int *sfd)
225 {
226 int sd;
227
228 sd = trace_vsock_make(start_port);
229 if (sd < 0)
230 return -errno;
231 *sfd = sd;
232
233 return start_port;
234 }
235
trace_net_make(int port,enum port_type type)236 int trace_net_make(int port, enum port_type type)
237 {
238 struct addrinfo hints;
239 struct addrinfo *result, *rp;
240 char buf[BUFSIZ];
241 int sd;
242 int s;
243
244 snprintf(buf, BUFSIZ, "%d", port);
245
246 memset(&hints, 0, sizeof(hints));
247 hints.ai_family = AF_UNSPEC;
248 hints.ai_flags = AI_PASSIVE;
249
250 switch (type) {
251 case USE_TCP:
252 hints.ai_socktype = SOCK_STREAM;
253 break;
254 case USE_UDP:
255 hints.ai_socktype = SOCK_DGRAM;
256 break;
257 default:
258 return -1;
259 }
260
261 s = getaddrinfo(NULL, buf, &hints, &result);
262 if (s != 0)
263 pdie("getaddrinfo: error opening socket");
264
265 for (rp = result; rp != NULL; rp = rp->ai_next) {
266 sd = socket(rp->ai_family, rp->ai_socktype,
267 rp->ai_protocol);
268 if (sd < 0)
269 continue;
270
271 set_tcp_no_delay(sd, rp->ai_socktype);
272 if (bind(sd, rp->ai_addr, rp->ai_addrlen) == 0)
273 break;
274
275 close(sd);
276 }
277 freeaddrinfo(result);
278
279 if (rp == NULL)
280 return -1;
281
282 dprint("Create listen port: %d fd:%d\n", port, sd);
283
284 return sd;
285 }
286
trace_net_search(int start_port,int * sfd,enum port_type type)287 int trace_net_search(int start_port, int *sfd, enum port_type type)
288 {
289 int num_port = start_port;
290
291 if (type == USE_VSOCK)
292 return setup_vsock_port(start_port, sfd);
293 again:
294 *sfd = trace_net_make(num_port, type);
295 if (*sfd < 0) {
296 if (++num_port > MAX_PORT_SEARCH)
297 pdie("No available ports to bind");
298 goto again;
299 }
300
301 return num_port;
302 }
303
fork_reader(int sfd,const char * node,const char * port,int * pid,int cpu,int pagesize,enum port_type type)304 static void fork_reader(int sfd, const char *node, const char *port,
305 int *pid, int cpu, int pagesize, enum port_type type)
306 {
307 int ret;
308
309 *pid = fork();
310
311 if (*pid < 0)
312 pdie("creating reader");
313
314 if (!*pid) {
315 ret = process_child(sfd, node, port, cpu, pagesize, type);
316 if (ret < 0)
317 pdie("Problem with reader %d", ret);
318 }
319
320 close(sfd);
321 }
322
open_port(const char * node,const char * port,int * pid,int cpu,int pagesize,int start_port,enum port_type type)323 static int open_port(const char *node, const char *port, int *pid,
324 int cpu, int pagesize, int start_port, enum port_type type)
325 {
326 int sfd;
327 int num_port;
328
329 /*
330 * trace_net_search() currently does not return an error, but if that
331 * changes in the future, we have a check for it now.
332 */
333 num_port = trace_net_search(start_port, &sfd, type);
334 if (num_port < 0)
335 return num_port;
336
337 fork_reader(sfd, node, port, pid, cpu, pagesize, type);
338
339 return num_port;
340 }
341
communicate_with_client(struct tracecmd_msg_handle * msg_handle)342 static int communicate_with_client(struct tracecmd_msg_handle *msg_handle)
343 {
344 char *last_proto = NULL;
345 char buf[BUFSIZ];
346 char *option;
347 int pagesize = 0;
348 int options;
349 int size;
350 int cpus;
351 int n, s, t, i;
352 int ret = -EINVAL;
353 int fd = msg_handle->fd;
354
355 /* Let the client know what we are */
356 write(fd, "tracecmd", 8);
357
358 try_again:
359 /* read back the CPU count */
360 n = read_string(fd, buf, BUFSIZ);
361 if (n == BUFSIZ)
362 /** ERROR **/
363 return -EINVAL;
364
365 cpus = atoi(buf);
366
367 /* Is the client using the new protocol? */
368 if (cpus == -1) {
369 if (memcmp(buf, V3_CPU, n) != 0) {
370 /* If it did not send a version, then bail */
371 if (memcmp(buf, "-1V", 3)) {
372 tracecmd_plog("Unknown string %s\n", buf);
373 goto out;
374 }
375 /* Skip "-1" */
376 tracecmd_plog("Cannot handle the protocol %s\n", buf+2);
377
378 /* If it returned the same command as last time, bail! */
379 if (last_proto && strncmp(last_proto, buf, n) == 0) {
380 tracecmd_plog("Repeat of version %s sent\n", last_proto);
381 goto out;
382 }
383 free(last_proto);
384 last_proto = malloc(n + 1);
385 if (last_proto) {
386 memcpy(last_proto, buf, n);
387 last_proto[n] = 0;
388 }
389 /* Return the highest protocol we can use */
390 write(fd, "V3", 3);
391 goto try_again;
392 }
393
394 /* Let the client know we use v3 protocol */
395 write(fd, "V3", 3);
396
397 /* read the rest of dummy data */
398 n = read(fd, buf, sizeof(V3_MAGIC));
399 if (memcmp(buf, V3_MAGIC, n) != 0)
400 goto out;
401
402 /* We're off! */
403 write(fd, "OK", 2);
404
405 msg_handle->version = V3_PROTOCOL;
406
407 /* read the CPU count, the page size, and options */
408 if ((pagesize = tracecmd_msg_initial_setting(msg_handle)) < 0)
409 goto out;
410 } else {
411 /* The client is using the v1 protocol */
412
413 tracecmd_plog("cpus=%d\n", cpus);
414 if (cpus < 0)
415 goto out;
416
417 msg_handle->cpu_count = cpus;
418
419 /* next read the page size */
420 n = read_string(fd, buf, BUFSIZ);
421 if (n == BUFSIZ)
422 /** ERROR **/
423 goto out;
424
425 pagesize = atoi(buf);
426
427 tracecmd_plog("pagesize=%d\n", pagesize);
428 if (pagesize <= 0)
429 goto out;
430
431 /* Now the number of options */
432 n = read_string(fd, buf, BUFSIZ);
433 if (n == BUFSIZ)
434 /** ERROR **/
435 return -EINVAL;
436
437 options = atoi(buf);
438
439 for (i = 0; i < options; i++) {
440 /* next is the size of the options */
441 n = read_string(fd, buf, BUFSIZ);
442 if (n == BUFSIZ)
443 /** ERROR **/
444 goto out;
445 size = atoi(buf);
446 /* prevent a client from killing us */
447 if (size > MAX_OPTION_SIZE)
448 goto out;
449
450 ret = -ENOMEM;
451 option = malloc(size);
452 if (!option)
453 goto out;
454
455 ret = -EIO;
456 t = size;
457 s = 0;
458 do {
459 s = read(fd, option+s, t);
460 if (s <= 0) {
461 free(option);
462 goto out;
463 }
464 t -= s;
465 s = size - t;
466 } while (t);
467
468 s = process_option(msg_handle, option);
469 free(option);
470 /* do we understand this option? */
471 ret = -EINVAL;
472 if (!s)
473 goto out;
474 }
475 }
476
477 if (msg_handle->flags & TRACECMD_MSG_FL_USE_TCP)
478 tracecmd_plog("Using TCP for live connection\n");
479
480 ret = pagesize;
481 out:
482 free(last_proto);
483
484 return ret;
485 }
486
create_client_file(const char * node,const char * port)487 static int create_client_file(const char *node, const char *port)
488 {
489 char buf[BUFSIZ];
490 int ofd;
491
492 snprintf(buf, BUFSIZ, "%s.%s:%s.dat", output_file, node, port);
493
494 ofd = open(buf, O_RDWR | O_CREAT | O_TRUNC, 0644);
495 if (ofd < 0)
496 pdie("Can not create file %s", buf);
497 return ofd;
498 }
499
destroy_all_readers(int cpus,int * pid_array,const char * node,const char * port)500 static void destroy_all_readers(int cpus, int *pid_array, const char *node,
501 const char *port)
502 {
503 int cpu;
504
505 for (cpu = 0; cpu < cpus; cpu++) {
506 if (pid_array[cpu] > 0) {
507 kill(pid_array[cpu], SIGKILL);
508 waitpid(pid_array[cpu], NULL, 0);
509 delete_temp_file(node, port, cpu);
510 pid_array[cpu] = 0;
511 }
512 }
513
514 free(pid_array);
515 }
516
create_all_readers(const char * node,const char * port,int pagesize,struct tracecmd_msg_handle * msg_handle)517 static int *create_all_readers(const char *node, const char *port,
518 int pagesize, struct tracecmd_msg_handle *msg_handle)
519 {
520 enum port_type port_type = USE_UDP;
521 char buf[BUFSIZ];
522 unsigned int *port_array;
523 int *pid_array;
524 unsigned int start_port;
525 unsigned int connect_port;
526 int cpus = msg_handle->cpu_count;
527 int cpu;
528 int pid;
529
530 if (!pagesize)
531 return NULL;
532
533 if (msg_handle->flags & TRACECMD_MSG_FL_USE_TCP)
534 port_type = USE_TCP;
535 else if (msg_handle->flags & TRACECMD_MSG_FL_USE_VSOCK)
536 port_type = USE_VSOCK;
537
538 port_array = malloc(sizeof(*port_array) * cpus);
539 if (!port_array)
540 return NULL;
541
542 pid_array = malloc(sizeof(*pid_array) * cpus);
543 if (!pid_array) {
544 free(port_array);
545 return NULL;
546 }
547
548 memset(pid_array, 0, sizeof(int) * cpus);
549
550 start_port = START_PORT_SEARCH;
551
552 /* Now create a port for each CPU */
553 for (cpu = 0; cpu < cpus; cpu++) {
554 connect_port = open_port(node, port, &pid, cpu,
555 pagesize, start_port, port_type);
556 if (connect_port < 0)
557 goto out_free;
558 port_array[cpu] = connect_port;
559 pid_array[cpu] = pid;
560 /*
561 * Due to some bugging finding ports,
562 * force search after last port
563 */
564 start_port = connect_port + 1;
565 }
566
567 if (msg_handle->version == V3_PROTOCOL) {
568 /* send set of port numbers to the client */
569 if (tracecmd_msg_send_port_array(msg_handle, port_array) < 0) {
570 tracecmd_plog("Failed sending port array\n");
571 goto out_free;
572 }
573 } else {
574 /* send the client a comma deliminated set of port numbers */
575 for (cpu = 0; cpu < cpus; cpu++) {
576 snprintf(buf, BUFSIZ, "%s%d",
577 cpu ? "," : "", port_array[cpu]);
578 write(msg_handle->fd, buf, strlen(buf));
579 }
580 /* end with null terminator */
581 write(msg_handle->fd, "\0", 1);
582 }
583
584 free(port_array);
585 return pid_array;
586
587 out_free:
588 free(port_array);
589 destroy_all_readers(cpus, pid_array, node, port);
590 return NULL;
591 }
592
593 static int
collect_metadata_from_client(struct tracecmd_msg_handle * msg_handle,int ofd)594 collect_metadata_from_client(struct tracecmd_msg_handle *msg_handle,
595 int ofd)
596 {
597 char buf[BUFSIZ];
598 int n, s, t;
599 int ifd = msg_handle->fd;
600 int ret = 0;
601
602 do {
603 n = read(ifd, buf, BUFSIZ);
604 if (n < 0) {
605 if (errno == EINTR)
606 continue;
607 ret = -errno;
608 break;
609 }
610 t = n;
611 s = 0;
612 do {
613 s = write(ofd, buf+s, t);
614 if (s < 0) {
615 if (errno == EINTR)
616 break;
617 ret = -errno;
618 goto out;
619 }
620 t -= s;
621 s = n - t;
622 } while (t);
623 } while (n > 0 && !tracecmd_msg_done(msg_handle));
624
625 out:
626 return ret;
627 }
628
stop_all_readers(int cpus,int * pid_array)629 static void stop_all_readers(int cpus, int *pid_array)
630 {
631 int cpu;
632
633 for (cpu = 0; cpu < cpus; cpu++) {
634 if (pid_array[cpu] > 0)
635 kill(pid_array[cpu], SIGUSR1);
636 }
637 }
638
put_together_file(int cpus,int ofd,const char * node,const char * port,bool write_options)639 static int put_together_file(int cpus, int ofd, const char *node,
640 const char *port, bool write_options)
641 {
642 struct tracecmd_output *handle = NULL;
643 char **temp_files;
644 int cpu;
645 int ret = -ENOMEM;
646
647 /* Now put together the file */
648 temp_files = malloc(sizeof(*temp_files) * cpus);
649 if (!temp_files)
650 return -ENOMEM;
651
652 for (cpu = 0; cpu < cpus; cpu++) {
653 temp_files[cpu] = get_temp_file(node, port, cpu);
654 if (!temp_files[cpu])
655 goto out;
656 }
657
658 handle = tracecmd_get_output_handle_fd(ofd);
659 if (!handle) {
660 ret = -1;
661 goto out;
662 }
663
664 if (write_options) {
665 ret = tracecmd_write_cpus(handle, cpus);
666 if (ret)
667 goto out;
668 ret = tracecmd_write_buffer_info(handle);
669 if (ret)
670 goto out;
671 ret = tracecmd_write_options(handle);
672 if (ret)
673 goto out;
674 }
675 ret = tracecmd_write_cpu_data(handle, cpus, temp_files, NULL);
676
677 out:
678 tracecmd_output_close(handle);
679 for (cpu--; cpu >= 0; cpu--) {
680 put_temp_file(temp_files[cpu]);
681 }
682 free(temp_files);
683 return ret;
684 }
685
process_client(struct tracecmd_msg_handle * msg_handle,const char * node,const char * port)686 static int process_client(struct tracecmd_msg_handle *msg_handle,
687 const char *node, const char *port)
688 {
689 int *pid_array;
690 int pagesize;
691 int cpus;
692 int ofd;
693 int ret;
694
695 pagesize = communicate_with_client(msg_handle);
696 if (pagesize < 0)
697 return pagesize;
698
699 ofd = create_client_file(node, port);
700
701 pid_array = create_all_readers(node, port, pagesize, msg_handle);
702 if (!pid_array) {
703 close(ofd);
704 return -ENOMEM;
705 }
706
707 /* on signal stop this msg */
708 stop_msg_handle = msg_handle;
709
710 /* Now we are ready to start reading data from the client */
711 if (msg_handle->version == V3_PROTOCOL)
712 ret = tracecmd_msg_collect_data(msg_handle, ofd);
713 else
714 ret = collect_metadata_from_client(msg_handle, ofd);
715 stop_msg_handle = NULL;
716
717 /* wait a little to let our readers finish reading */
718 sleep(1);
719
720 cpus = msg_handle->cpu_count;
721
722 /* stop our readers */
723 stop_all_readers(cpus, pid_array);
724
725 /* wait a little to have the readers clean up */
726 sleep(1);
727
728 if (!ret)
729 ret = put_together_file(cpus, ofd, node, port,
730 msg_handle->version < V3_PROTOCOL);
731
732 destroy_all_readers(cpus, pid_array, node, port);
733 close(ofd);
734
735 return ret;
736 }
737
do_fork(int cfd)738 static int do_fork(int cfd)
739 {
740 pid_t pid;
741
742 /* in debug mode, we do not fork off children */
743 if (tracecmd_get_debug())
744 return 0;
745
746 pid = fork();
747 if (pid < 0) {
748 warning("failed to create child");
749 return -1;
750 }
751
752 if (pid > 0) {
753 close(cfd);
754 return pid;
755 }
756
757 signal_setup(SIGINT, finish);
758
759 return 0;
760 }
761
trace_net_cmp_connection(struct sockaddr_storage * addr,const char * name)762 bool trace_net_cmp_connection(struct sockaddr_storage *addr, const char *name)
763 {
764 char host[NI_MAXHOST], nhost[NI_MAXHOST];
765 char service[NI_MAXSERV];
766 socklen_t addr_len = sizeof(*addr);
767 struct addrinfo *result, *rp;
768 struct addrinfo hints;
769 bool found = false;
770 int s;
771
772 if (getnameinfo((struct sockaddr *)addr, addr_len,
773 host, NI_MAXHOST,
774 service, NI_MAXSERV, NI_NUMERICSERV))
775 return -1;
776
777 if (strcmp(host, name) == 0)
778 return true;
779
780 /* Check other IPs that name could be for */
781
782 memset(&hints, 0, sizeof(hints));
783 hints.ai_family = AF_UNSPEC;
784 hints.ai_socktype = SOCK_STREAM;
785
786 /* Check other IPs that name could be for */
787 s = getaddrinfo(name, NULL, &hints, &result);
788 if (s != 0)
789 return false;
790
791 for (rp = result; rp != NULL; rp = rp->ai_next) {
792 if (getnameinfo(rp->ai_addr, rp->ai_addrlen,
793 nhost, NI_MAXHOST,
794 service, NI_MAXSERV, NI_NUMERICSERV))
795 continue;
796 if (strcmp(host, nhost) == 0) {
797 found = 1;
798 break;
799 }
800 }
801
802 freeaddrinfo(result);
803 return found;
804 }
805
trace_net_cmp_connection_fd(int fd,const char * name)806 bool trace_net_cmp_connection_fd(int fd, const char *name)
807 {
808 struct sockaddr_storage addr;
809 socklen_t addr_len = sizeof(addr);
810
811 if (getpeername(fd, (struct sockaddr *)&addr, &addr_len))
812 return false;
813
814 return trace_net_cmp_connection(&addr, name);
815 };
816
trace_net_print_connection(int fd)817 int trace_net_print_connection(int fd)
818 {
819 char host[NI_MAXHOST], service[NI_MAXSERV];
820 struct sockaddr_storage net_addr;
821 socklen_t addr_len;
822
823 addr_len = sizeof(net_addr);
824 if (getpeername(fd, (struct sockaddr *)&net_addr, &addr_len))
825 return -1;
826
827 if (getnameinfo((struct sockaddr *)&net_addr, addr_len,
828 host, NI_MAXHOST,
829 service, NI_MAXSERV, NI_NUMERICSERV))
830 return -1;
831
832 if (tracecmd_get_debug())
833 tracecmd_debug("Connected to %s:%s fd:%d\n", host, service, fd);
834 else
835 tracecmd_plog("Connected to %s:%s\n", host, service);
836 return 0;
837 }
838
do_connection(int cfd,struct sockaddr * addr,socklen_t addr_len)839 static int do_connection(int cfd, struct sockaddr *addr,
840 socklen_t addr_len)
841 {
842 struct tracecmd_msg_handle *msg_handle;
843 char host[NI_MAXHOST], service[NI_MAXSERV];
844 int s;
845 int ret;
846
847 ret = do_fork(cfd);
848 if (ret)
849 return ret;
850
851 msg_handle = tracecmd_msg_handle_alloc(cfd, 0);
852
853 if (use_vsock) {
854 #ifdef VSOCK
855 struct sockaddr_vm *vm_addr = (struct sockaddr_vm *)addr;
856 snprintf(host, NI_MAXHOST, "V%d", vm_addr->svm_cid);
857 snprintf(service, NI_MAXSERV, "%d", vm_addr->svm_port);
858 #endif
859 } else {
860 s = getnameinfo((struct sockaddr *)addr, addr_len,
861 host, NI_MAXHOST,
862 service, NI_MAXSERV, NI_NUMERICSERV);
863
864 if (s == 0)
865 tracecmd_plog("Connected with %s:%s\n", host, service);
866 else {
867 tracecmd_plog("Error with getnameinfo: %s\n", gai_strerror(s));
868 close(cfd);
869 tracecmd_msg_handle_close(msg_handle);
870 return -1;
871 }
872 }
873
874 process_client(msg_handle, host, service);
875
876 tracecmd_msg_handle_close(msg_handle);
877
878 if (!tracecmd_get_debug())
879 exit(0);
880
881 return 0;
882 }
883
884 static int *client_pids;
885 static int free_pids;
886 static int saved_pids;
887
add_process(int pid)888 static void add_process(int pid)
889 {
890 int *client = NULL;
891 int i;
892
893 if (free_pids) {
894 for (i = 0; i < saved_pids; i++) {
895 if (!client_pids[i]) {
896 client = &client_pids[i];
897 break;
898 }
899 }
900 free_pids--;
901 if (!client)
902 warning("Could not find free pid");
903 }
904 if (!client) {
905 client_pids = realloc(client_pids,
906 sizeof(*client_pids) * (saved_pids + 1));
907 if (!client_pids)
908 pdie("allocating pids");
909 client = &client_pids[saved_pids++];
910 }
911 *client = pid;
912 }
913
remove_process(int pid)914 static void remove_process(int pid)
915 {
916 int i;
917
918 for (i = 0; i < saved_pids; i++) {
919 if (client_pids[i] == pid)
920 break;
921 }
922
923 if (i == saved_pids)
924 return;
925
926 client_pids[i] = 0;
927 free_pids++;
928 }
929
kill_clients(void)930 static void kill_clients(void)
931 {
932 int status;
933 int i;
934
935 for (i = 0; i < saved_pids; i++) {
936 if (!client_pids[i])
937 continue;
938 /* Only kill the clients if we received SIGINT or SIGTERM */
939 if (done)
940 kill(client_pids[i], SIGINT);
941 waitpid(client_pids[i], &status, 0);
942 }
943
944 saved_pids = 0;
945 }
946
clean_up(void)947 static void clean_up(void)
948 {
949 int status;
950 int ret;
951
952 /* Clean up any children that has started before */
953 do {
954 ret = waitpid(0, &status, WNOHANG);
955 if (ret > 0)
956 remove_process(ret);
957 } while (ret > 0);
958 }
959
do_accept_loop(int sfd)960 static void do_accept_loop(int sfd)
961 {
962 struct sockaddr_storage peer_addr;
963 #ifdef VSOCK
964 struct sockaddr_vm vm_addr;
965 #endif
966 struct sockaddr *addr;
967 socklen_t addr_len;
968 int cfd, pid;
969
970 if (use_vsock) {
971 #ifdef VSOCK
972 addr = (struct sockaddr *)&vm_addr;
973 addr_len = sizeof(vm_addr);
974 #endif
975 } else {
976 addr = (struct sockaddr *)&peer_addr;
977 addr_len = sizeof(peer_addr);
978 }
979
980 do {
981 cfd = accept(sfd, addr, &addr_len);
982 if (cfd < 0 && errno == EINTR) {
983 clean_up();
984 continue;
985 }
986 if (cfd < 0)
987 pdie("connecting");
988
989 pid = do_connection(cfd, addr, addr_len);
990 if (pid > 0)
991 add_process(pid);
992
993 } while (!done);
994 /* Get any final stragglers */
995 clean_up();
996 }
997
make_pid_file(const char * pidfile_basename)998 void make_pid_file(const char *pidfile_basename)
999 {
1000 char buf[PATH_MAX];
1001 int fd;
1002
1003 make_pid_name(buf, pidfile_basename);
1004
1005 fd = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1006 if (fd < 0) {
1007 perror(buf);
1008 return;
1009 }
1010
1011 sprintf(buf, "%d\n", getpid());
1012 write(fd, buf, strlen(buf));
1013 close(fd);
1014 }
1015
sigstub(int sig)1016 static void sigstub(int sig)
1017 {
1018 }
1019
get_vsock(const char * port)1020 static int get_vsock(const char *port)
1021 {
1022 unsigned int cid;
1023 int sd;
1024
1025 sd = trace_vsock_make(atoi(port));
1026 if (sd < 0)
1027 return sd;
1028
1029 cid = trace_vsock_local_cid();
1030 if (cid >= 0)
1031 printf("listening on @%u:%s\n", cid, port);
1032
1033 return sd;
1034 }
1035
get_network(char * port)1036 static int get_network(char *port)
1037 {
1038 struct addrinfo hints;
1039 struct addrinfo *result, *rp;
1040 int sfd, s;
1041
1042 memset(&hints, 0, sizeof(hints));
1043 hints.ai_family = AF_UNSPEC;
1044 hints.ai_socktype = SOCK_STREAM;
1045 hints.ai_flags = AI_PASSIVE;
1046
1047 s = getaddrinfo(NULL, port, &hints, &result);
1048 if (s != 0)
1049 pdie("getaddrinfo: error opening %s", port);
1050
1051 for (rp = result; rp != NULL; rp = rp->ai_next) {
1052 sfd = socket(rp->ai_family, rp->ai_socktype,
1053 rp->ai_protocol);
1054 if (sfd < 0)
1055 continue;
1056
1057 set_tcp_no_delay(sfd, rp->ai_socktype);
1058 if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
1059 break;
1060
1061 close(sfd);
1062 }
1063
1064 if (rp == NULL)
1065 pdie("Could not bind");
1066
1067 freeaddrinfo(result);
1068
1069 return sfd;
1070 }
1071
do_listen(char * port)1072 static void do_listen(char *port)
1073 {
1074 int sfd;
1075
1076 if (!tracecmd_get_debug())
1077 signal_setup(SIGCHLD, sigstub);
1078
1079 if (do_daemon)
1080 make_pid_file(LISTEN_PIDFILE);
1081
1082 if (use_vsock)
1083 sfd = get_vsock(port);
1084 else
1085 sfd = get_network(port);
1086
1087
1088 if (listen(sfd, backlog) < 0)
1089 pdie("listen");
1090
1091 do_accept_loop(sfd);
1092
1093 kill_clients();
1094
1095 if (do_daemon)
1096 remove_pid_file(LISTEN_PIDFILE);
1097 }
1098
start_daemon(void)1099 static void start_daemon(void)
1100 {
1101 do_daemon = 1;
1102
1103 if (daemon(1, 0) < 0)
1104 die("starting daemon");
1105 }
1106
1107 enum {
1108 OPT_verbose = 254,
1109 OPT_debug = 255,
1110 };
1111
trace_listen(int argc,char ** argv)1112 void trace_listen(int argc, char **argv)
1113 {
1114 char *logfile = NULL;
1115 char *port = NULL;
1116 int daemon = 0;
1117 int c;
1118
1119 if (argc < 2)
1120 usage(argv);
1121
1122 if (strcmp(argv[1], "listen") != 0)
1123 usage(argv);
1124
1125 for (;;) {
1126 int option_index = 0;
1127 static struct option long_options[] = {
1128 {"port", required_argument, NULL, 'p'},
1129 {"help", no_argument, NULL, '?'},
1130 {"debug", no_argument, NULL, OPT_debug},
1131 {"verbose", optional_argument, NULL, OPT_verbose},
1132 {NULL, 0, NULL, 0}
1133 };
1134
1135 c = getopt_long (argc-1, argv+1, "+hp:Vo:d:l:D",
1136 long_options, &option_index);
1137 if (c == -1)
1138 break;
1139 switch (c) {
1140 case 'h':
1141 usage(argv);
1142 break;
1143 case 'p':
1144 port = optarg;
1145 break;
1146 case 'd':
1147 output_dir = optarg;
1148 break;
1149 case 'V':
1150 use_vsock = true;
1151 break;
1152 case 'o':
1153 output_file = optarg;
1154 break;
1155 case 'l':
1156 logfile = optarg;
1157 break;
1158 case 'D':
1159 daemon = 1;
1160 break;
1161 case OPT_debug:
1162 tracecmd_set_debug(true);
1163 break;
1164 case OPT_verbose:
1165 if (trace_set_verbose(optarg) < 0)
1166 die("invalid verbose level %s", optarg);
1167 break;
1168 default:
1169 usage(argv);
1170 }
1171 }
1172
1173 if (!port)
1174 usage(argv);
1175
1176 if ((argc - optind) >= 2)
1177 usage(argv);
1178
1179 if (!output_file)
1180 output_file = default_output_file;
1181
1182 if (!output_dir)
1183 output_dir = default_output_dir;
1184
1185 if (logfile) {
1186 /* set the writes to a logfile instead */
1187 if (tracecmd_set_logfile(logfile) < 0)
1188 die("creating log file %s", logfile);
1189 }
1190
1191 if (chdir(output_dir) < 0)
1192 die("Can't access directory %s", output_dir);
1193
1194 if (daemon)
1195 start_daemon();
1196
1197 signal_setup(SIGINT, finish);
1198 signal_setup(SIGTERM, finish);
1199
1200 do_listen(port);
1201
1202 return;
1203 }
1204