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