• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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