aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2010-02-24 12:42:03 -0500
committerSteven Rostedt <rostedt@goodmis.org>2010-02-24 13:07:16 -0500
commit56c42d46eab682f96acab8ec6058f22a76725d2f (patch)
tree941933e4758cb443cd527f63953eb8c74f2439ca
parenta1f5e80613a2e1a8064b95aa4898ad15eaba9609 (diff)
trace-cmd: Add new trace-cmd listen, and record -N
Add a way to record the trace remotely. On a remote box, one can start trace-cmd like: trace-cmd listen -p 1234 Then the local box that wants to trace can run: trace-cmd record -e all -N otherhost:1234 command Instead of writing to trace.dat, the record will send the data over the network using TCP and UDP and the trace.dat file will be created on the remote host. The remote host will save the file as trace.host:port.dat TCP is used to send the recording box information, and UDP is used to send the live data from the trace. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--Makefile2
-rw-r--r--trace-cmd.c196
-rw-r--r--trace-listen.c450
-rw-r--r--trace-local.h2
4 files changed, 639 insertions, 11 deletions
diff --git a/Makefile b/Makefile
index 08f488c..481b1a7 100644
--- a/Makefile
+++ b/Makefile
@@ -140,7 +140,7 @@ endef
140 $(Q)$(call check_gui) 140 $(Q)$(call check_gui)
141 141
142 142
143TRACE_CMD_OBJS = trace-cmd.o trace-read.o trace-split.o 143TRACE_CMD_OBJS = trace-cmd.o trace-read.o trace-split.o trace-listen.o
144TRACE_VIEW_OBJS = trace-view.o trace-view-store.o trace-filter.o trace-compat.o \ 144TRACE_VIEW_OBJS = trace-view.o trace-view-store.o trace-filter.o trace-compat.o \
145 trace-hash.o 145 trace-hash.o
146TRACE_GRAPH_OBJS = trace-graph.o trace-compat.o trace-hash.o trace-filter.o \ 146TRACE_GRAPH_OBJS = trace-graph.o trace-compat.o trace-hash.o trace-filter.o \
diff --git a/trace-cmd.c b/trace-cmd.c
index e89362d..cdd78f4 100644
--- a/trace-cmd.c
+++ b/trace-cmd.c
@@ -27,6 +27,8 @@
27#include <sys/types.h> 27#include <sys/types.h>
28#include <sys/stat.h> 28#include <sys/stat.h>
29#include <sys/wait.h> 29#include <sys/wait.h>
30#include <sys/socket.h>
31#include <netdb.h>
30#include <pthread.h> 32#include <pthread.h>
31#include <fcntl.h> 33#include <fcntl.h>
32#include <unistd.h> 34#include <unistd.h>
@@ -48,7 +50,7 @@
48#define ITER_CTRL "trace_options" 50#define ITER_CTRL "trace_options"
49#define MAX_LATENCY "tracing_max_latency" 51#define MAX_LATENCY "tracing_max_latency"
50 52
51unsigned int page_size; 53static unsigned int page_size;
52 54
53static const char *output_file = "trace.dat"; 55static const char *output_file = "trace.dat";
54 56
@@ -57,6 +59,10 @@ static int sleep_time = 1000;
57static int cpu_count; 59static int cpu_count;
58static int *pids; 60static int *pids;
59 61
62static char *host;
63static int *client_ports;
64static int sfd;
65
60static int filter_task; 66static int filter_task;
61static int filter_pid = -1; 67static int filter_pid = -1;
62 68
@@ -116,7 +122,7 @@ static void kill_threads(void)
116{ 122{
117 int i; 123 int i;
118 124
119 if (!cpu_count) 125 if (!cpu_count || !pids)
120 return; 126 return;
121 127
122 for (i = 0; i < cpu_count; i++) { 128 for (i = 0; i < cpu_count; i++) {
@@ -895,6 +901,41 @@ static void flush(int sig)
895 tracecmd_stop_recording(recorder); 901 tracecmd_stop_recording(recorder);
896} 902}
897 903
904static void connect_port(int cpu)
905{
906 struct addrinfo hints;
907 struct addrinfo *results, *rp;
908 int s;
909 char buf[BUFSIZ];
910
911 snprintf(buf, BUFSIZ, "%d", client_ports[cpu]);
912
913 memset(&hints, 0, sizeof(hints));
914 hints.ai_family = AF_UNSPEC;
915 hints.ai_socktype = SOCK_DGRAM;
916
917 s = getaddrinfo(host, buf, &hints, &results);
918 if (s != 0)
919 die("connecting to UDP server %s:%s", host, buf);
920
921 for (rp = results; rp != NULL; rp = rp->ai_next) {
922 sfd = socket(rp->ai_family, rp->ai_socktype,
923 rp->ai_protocol);
924 if (sfd == -1)
925 continue;
926 if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != 1)
927 break;
928 close(sfd);
929 }
930
931 if (rp == NULL)
932 die("Can not connect to UDP server %s:%s", host, buf);
933
934 freeaddrinfo(results);
935
936 client_ports[cpu] = sfd;
937}
938
898static int create_recorder(int cpu) 939static int create_recorder(int cpu)
899{ 940{
900 char *file; 941 char *file;
@@ -913,10 +954,14 @@ static int create_recorder(int cpu)
913 /* do not kill tasks on error */ 954 /* do not kill tasks on error */
914 cpu_count = 0; 955 cpu_count = 0;
915 956
916 file = get_temp_file(cpu); 957 if (client_ports) {
917 958 connect_port(cpu);
918 recorder = tracecmd_create_recorder(file, cpu); 959 recorder = tracecmd_create_recorder_fd(client_ports[cpu], cpu);
919 put_temp_file(file); 960 } else {
961 file = get_temp_file(cpu);
962 recorder = tracecmd_create_recorder(file, cpu);
963 put_temp_file(file);
964 }
920 965
921 if (!recorder) 966 if (!recorder)
922 die ("can't create recorder"); 967 die ("can't create recorder");
@@ -927,18 +972,125 @@ static int create_recorder(int cpu)
927 exit(0); 972 exit(0);
928} 973}
929 974
975static void setup_network(void)
976{
977 struct tracecmd_output *handle;
978 struct addrinfo hints;
979 struct addrinfo *result, *rp;
980 int sfd, s;
981 ssize_t n;
982 char buf[BUFSIZ];
983 char *server;
984 char *port;
985 char *p;
986 int cpu;
987 int i;
988
989 if (!strchr(host, ':')) {
990 server = strdup("localhost");
991 if (!server)
992 die("alloctating server");
993 port = host;
994 host = server;
995 } else {
996 host = strdup(host);
997 if (!host)
998 die("alloctating server");
999 server = strtok_r(host, ":", &p);
1000 port = strtok_r(NULL, ":", &p);
1001 }
1002
1003 memset(&hints, 0, sizeof(hints));
1004 hints.ai_family = AF_UNSPEC;
1005 hints.ai_socktype = SOCK_STREAM;
1006
1007 s = getaddrinfo(server, port, &hints, &result);
1008 if (s != 0)
1009 die("getaddrinfo: %s", gai_strerror(s));
1010
1011 for (rp = result; rp != NULL; rp = rp->ai_next) {
1012 sfd = socket(rp->ai_family, rp->ai_socktype,
1013 rp->ai_protocol);
1014 if (sfd == -1)
1015 continue;
1016
1017 if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
1018 break;
1019 close(sfd);
1020 }
1021
1022 if (!rp)
1023 die("Can not connect to %s:%d", server, port);
1024
1025 freeaddrinfo(result);
1026
1027 n = read(sfd, buf, 8);
1028
1029 /* Make sure the server is the tracecmd server */
1030 if (memcmp(buf, "tracecmd", 8) != 0)
1031 die("server not tracecmd server");
1032
1033 /* write the number of CPUs we have (in ASCII) */
1034
1035 sprintf(buf, "%d", cpu_count);
1036
1037 /* include \0 */
1038 write(sfd, buf, strlen(buf)+1);
1039
1040 /* write the pagesize (in ASCII) */
1041
1042 page_size = getpagesize();
1043 sprintf(buf, "%d", page_size);
1044
1045 /* include \0 */
1046 write(sfd, buf, strlen(buf)+1);
1047
1048 client_ports = malloc_or_die(sizeof(int) * cpu_count);
1049
1050 /*
1051 * Now we will receive back a comma deliminated list
1052 * of client ports to connect to.
1053 */
1054 for (cpu = 0; cpu < cpu_count; cpu++) {
1055 for (i = 0; i < BUFSIZ; i++) {
1056 n = read(sfd, buf+i, 1);
1057 if (n != 1)
1058 die("Error, reading server ports");
1059 if (!buf[i] || buf[i] == ',')
1060 break;
1061 }
1062 if (i == BUFSIZ)
1063 die("read bad port number");
1064 buf[i] = 0;
1065 client_ports[cpu] = atoi(buf);
1066 }
1067
1068 /* Now create the handle through this socket */
1069 handle = tracecmd_create_init_fd(sfd, cpu_count);
1070
1071 /* OK, we are all set, let'r rip! */
1072}
1073
1074static void finish_network(void)
1075{
1076 close(sfd);
1077 free(host);
1078}
1079
930static void start_threads(void) 1080static void start_threads(void)
931{ 1081{
932 int i; 1082 int i;
933 1083
934 cpu_count = count_cpus(); 1084 cpu_count = count_cpus();
935 1085
1086 if (host)
1087 setup_network();
1088
936 /* make a thread for every CPU we have */ 1089 /* make a thread for every CPU we have */
937 pids = malloc_or_die(sizeof(*pids) * cpu_count); 1090 pids = malloc_or_die(sizeof(*pids) * cpu_count);
938 1091
939 memset(pids, 0, sizeof(*pids) * cpu_count); 1092 memset(pids, 0, sizeof(*pids) * cpu_count);
940 1093
941
942 for (i = 0; i < cpu_count; i++) { 1094 for (i = 0; i < cpu_count; i++) {
943 pids[i] = create_recorder(i); 1095 pids[i] = create_recorder(i);
944 } 1096 }
@@ -950,6 +1102,11 @@ static void record_data(void)
950 char **temp_files; 1102 char **temp_files;
951 int i; 1103 int i;
952 1104
1105 if (host) {
1106 finish_network();
1107 return;
1108 }
1109
953 if (latency) 1110 if (latency)
954 handle = tracecmd_create_file_latency(output_file, cpu_count); 1111 handle = tracecmd_create_file_latency(output_file, cpu_count);
955 else { 1112 else {
@@ -1066,7 +1223,7 @@ void usage(char **argv)
1066 "usage:\n" 1223 "usage:\n"
1067 " %s record [-v][-e event [-f filter]][-p plugin][-F][-d][-o file] \\\n" 1224 " %s record [-v][-e event [-f filter]][-p plugin][-F][-d][-o file] \\\n"
1068 " [-s usecs][-O option ][-l func][-g func][-n func]\n" 1225 " [-s usecs][-O option ][-l func][-g func][-n func]\n"
1069 " [-P pid][command ...]\n" 1226 " [-P pid][-N host:port][command ...]\n"
1070 " -e run command with event enabled\n" 1227 " -e run command with event enabled\n"
1071 " -f filter for previous -e event\n" 1228 " -f filter for previous -e event\n"
1072 " -p run command with plugin enabled\n" 1229 " -p run command with plugin enabled\n"
@@ -1080,6 +1237,7 @@ void usage(char **argv)
1080 " -o data output file [default trace.dat]\n" 1237 " -o data output file [default trace.dat]\n"
1081 " -O option to enable (or disable)\n" 1238 " -O option to enable (or disable)\n"
1082 " -s sleep interval between recording (in usecs) [default: 1000]\n" 1239 " -s sleep interval between recording (in usecs) [default: 1000]\n"
1240 " -N host:port to connect to (see listen)\n"
1083 "\n" 1241 "\n"
1084 " %s start [-e event][-p plugin][-d][-O option ][-P pid]\n" 1242 " %s start [-e event][-p plugin][-d][-O option ][-P pid]\n"
1085 " Uses same options as record, but does not run a command.\n" 1243 " Uses same options as record, but does not run a command.\n"
@@ -1122,11 +1280,17 @@ void usage(char **argv)
1122 " if left out, will start at beginning of file\n" 1280 " if left out, will start at beginning of file\n"
1123 " end - decimal end time in seconds\n" 1281 " end - decimal end time in seconds\n"
1124 "\n" 1282 "\n"
1283 " %s listen -p port[-D][-o file][-d dir]\n"
1284 " Creates a socket to listen for clients.\n"
1285 " -D create it in daemon mode.\n"
1286 " -o file name to use for clients.\n"
1287 " -d diretory to store client files.\n"
1288 "\n"
1125 " %s list [-e][-p]\n" 1289 " %s list [-e][-p]\n"
1126 " -e list available events\n" 1290 " -e list available events\n"
1127 " -p list available plugins\n" 1291 " -p list available plugins\n"
1128 " -o list available options\n" 1292 " -o list available options\n"
1129 "\n", p, VERSION_STRING, p, p, p, p, p, p, p, p); 1293 "\n", p, VERSION_STRING, p, p, p, p, p, p, p, p, p);
1130 exit(-1); 1294 exit(-1);
1131} 1295}
1132 1296
@@ -1159,6 +1323,9 @@ int main (int argc, char **argv)
1159 if (strcmp(argv[1], "report") == 0) { 1323 if (strcmp(argv[1], "report") == 0) {
1160 trace_report(argc, argv); 1324 trace_report(argc, argv);
1161 exit(0); 1325 exit(0);
1326 } else if (strcmp(argv[1], "listen") == 0) {
1327 trace_listen(argc, argv);
1328 exit(0);
1162 } else if (strcmp(argv[1], "split") == 0) { 1329 } else if (strcmp(argv[1], "split") == 0) {
1163 trace_split(argc, argv); 1330 trace_split(argc, argv);
1164 exit(0); 1331 exit(0);
@@ -1166,7 +1333,7 @@ int main (int argc, char **argv)
1166 (strcmp(argv[1], "start") == 0) || 1333 (strcmp(argv[1], "start") == 0) ||
1167 ((extract = strcmp(argv[1], "extract") == 0))) { 1334 ((extract = strcmp(argv[1], "extract") == 0))) {
1168 1335
1169 while ((c = getopt(argc-1, argv+1, "+he:f:Fp:do:O:s:vg:l:n:P:")) >= 0) { 1336 while ((c = getopt(argc-1, argv+1, "+he:f:Fp:do:O:s:vg:l:n:P:N:")) >= 0) {
1170 switch (c) { 1337 switch (c) {
1171 case 'h': 1338 case 'h':
1172 usage(argv); 1339 usage(argv);
@@ -1241,6 +1408,8 @@ int main (int argc, char **argv)
1241 disable = 1; 1408 disable = 1;
1242 break; 1409 break;
1243 case 'o': 1410 case 'o':
1411 if (host)
1412 die("-o incompatible with -N");
1244 if (!record && !extract) 1413 if (!record && !extract)
1245 die("start does not take output\n" 1414 die("start does not take output\n"
1246 "Did you mean 'record'?"); 1415 "Did you mean 'record'?");
@@ -1257,6 +1426,13 @@ int main (int argc, char **argv)
1257 usage(argv); 1426 usage(argv);
1258 sleep_time = atoi(optarg); 1427 sleep_time = atoi(optarg);
1259 break; 1428 break;
1429 case 'N':
1430 if (!record)
1431 die("-N only available with record");
1432 if (output)
1433 die("-N incompatible with -o");
1434 host = optarg;
1435 break;
1260 } 1436 }
1261 } 1437 }
1262 1438
diff --git a/trace-listen.c b/trace-listen.c
new file mode 100644
index 0000000..d1314a5
--- /dev/null
+++ b/trace-listen.c
@@ -0,0 +1,450 @@
1/*
2 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#define _LARGEFILE64_SOURCE
22#define _GNU_SOURCE
23#include <dirent.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <getopt.h>
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <netdb.h>
31#include <unistd.h>
32#include <fcntl.h>
33#include <signal.h>
34#include <errno.h>
35
36#include "trace-local.h"
37
38static char *default_output_dir = ".";
39static char *output_dir;
40static char *default_output_file = "trace";
41static char *output_file;
42
43static int backlog = 5;
44
45#define TEMP_FILE_STR "%s.%s:%s.cpu%d", output_file, host, port, cpu
46static char *get_temp_file(const char *host, const char *port, int cpu)
47{
48 char *file = NULL;
49 int size;
50
51 size = snprintf(file, 0, TEMP_FILE_STR);
52 file = malloc_or_die(size + 1);
53 sprintf(file, TEMP_FILE_STR);
54
55 return file;
56}
57
58static void put_temp_file(char *file)
59{
60 free(file);
61}
62
63#define MAX_PATH 1024
64
65static void delete_temp_file(const char *host, const char *port, int cpu)
66{
67 char file[MAX_PATH];
68
69 snprintf(file, MAX_PATH, TEMP_FILE_STR);
70 unlink(file);
71}
72
73static int read_string(int fd, char *buf, size_t size)
74{
75 size_t i;
76 int n;
77
78 for (i = 0; i < size; i++) {
79 n = read(fd, buf+i, 1);
80 if (!buf[i] || n <= 0)
81 break;
82 }
83
84 return i;
85}
86
87static int done;
88static void finish(int sig)
89{
90 done = 1;
91}
92
93static void process_udp_child(int sfd, const char *host, const char *port,
94 int cpu, int page_size)
95{
96 struct sockaddr_storage peer_addr;
97 socklen_t peer_addr_len;
98 char buf[page_size];
99 char *tempfile;
100 int fd;
101 int n;
102 int once = 0;
103
104 signal(SIGUSR1, finish);
105
106 tempfile = get_temp_file(host, port, cpu);
107 fd = open(tempfile, O_WRONLY | O_TRUNC | O_CREAT, 0644);
108 if (fd < 0)
109 die("creating %s", tempfile);
110
111 do {
112 peer_addr_len = sizeof(peer_addr);
113 /* TODO, make this copyless! */
114 n = read(sfd, buf, page_size);
115#if 0
116 n = recvfrom(sfd, buf, page_size, 0,
117 (struct sockaddr *)&peer_addr, &peer_addr_len);
118#endif
119 if (!n)
120 break;
121 if (n < page_size && !once) {
122 once = 1;
123 warning("read %d bytes, expected %d", n, page_size);
124 }
125 write(fd, buf, n);
126 } while (!done);
127
128 put_temp_file(tempfile);
129 exit(0);
130}
131
132#define START_PORT_SEARCH 1500
133#define MAX_PORT_SEARCH 6000
134
135static int open_udp(const char *node, const char *port, int *pid,
136 int cpu, int pagesize)
137{
138 struct addrinfo hints;
139 struct addrinfo *result, *rp;
140 int sfd, s;
141 char buf[BUFSIZ];
142 int num_port = START_PORT_SEARCH;
143
144 again:
145 snprintf(buf, BUFSIZ, "%d", num_port);
146
147 memset(&hints, 0, sizeof(hints));
148 hints.ai_family = AF_UNSPEC;
149 hints.ai_socktype = SOCK_DGRAM;
150 hints.ai_flags = AI_PASSIVE;
151
152 s = getaddrinfo(NULL, buf, &hints, &result);
153 if (s != 0)
154 die("getaddrinfo: error opening udp socket");
155
156 for (rp = result; rp != NULL; rp = rp->ai_next) {
157 sfd = socket(rp->ai_family, rp->ai_socktype,
158 rp->ai_protocol);
159 if (sfd < 0)
160 continue;
161
162 if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
163 break;
164
165 close(sfd);
166 }
167
168 if (rp == NULL) {
169 freeaddrinfo(result);
170 if (++num_port > MAX_PORT_SEARCH)
171 die("No available ports to bind");
172 goto again;
173 }
174
175 freeaddrinfo(result);
176
177 *pid = fork();
178
179 if (*pid < 0)
180 die("creating udp reader");
181
182 if (!*pid)
183 process_udp_child(sfd, node, port, cpu, pagesize);
184
185 close(sfd);
186
187 return num_port;
188}
189
190static void process_client(const char *node, const char *port, int fd)
191{
192 char **temp_files;
193 char buf[BUFSIZ];
194 int *port_array;
195 int *pid_array;
196 int pagesize;
197 int udp_port;
198 int cpus;
199 int cpu;
200 int pid;
201 int ofd;
202 int n, s, t;
203
204 /* Let the client know what we are */
205 write(fd, "tracecmd", 8);
206
207 /* read back the CPU count */
208 n = read_string(fd, buf, BUFSIZ);
209 if (n == BUFSIZ)
210 /** ERROR **/
211 return;
212
213 cpus = atoi(buf);
214
215 printf("cpus=%d\n", cpus);
216 if (cpus < 0)
217 return;
218
219 /* next read the page size */
220 n = read_string(fd, buf, BUFSIZ);
221 if (n == BUFSIZ)
222 /** ERROR **/
223 return;
224
225 pagesize = atoi(buf);
226
227 printf("pagesize=%d\n", pagesize);
228 if (pagesize <= 0)
229 return;
230
231 /* Create the client file */
232 snprintf(buf, BUFSIZ, "%s.%s:%s.dat", output_file, node, port);
233
234 ofd = open(buf, O_RDWR | O_CREAT | O_TRUNC, 0644);
235 if (ofd < 0)
236 die("Can not create file %s", buf);
237
238 port_array = malloc_or_die(sizeof(int) * cpus);
239 pid_array = malloc_or_die(sizeof(int) * cpus);
240 memset(pid_array, 0, sizeof(int) * cpus);
241
242 /* Now create a UDP port for each CPU */
243 for (cpu = 0; cpu < cpus; cpu++) {
244 udp_port = open_udp(node, port, &pid, cpu, pagesize);
245 if (udp_port < 0)
246 goto out_free;
247 port_array[cpu] = udp_port;
248 pid_array[cpu] = pid;
249 }
250
251 /* send the client a comma deliminated set of port numbers */
252 for (cpu = 0; cpu < cpus; cpu++) {
253 snprintf(buf, BUFSIZ, "%s%d",
254 cpu ? "," : "", port_array[cpu]);
255 write(fd, buf, strlen(buf));
256 }
257 /* end with null terminator */
258 write(fd, "\0", 1);
259
260 /* Now we are ready to start reading data from the client */
261 do {
262 n = read(fd, buf, BUFSIZ);
263 t = n;
264 s = 0;
265 do {
266 s = write(ofd, buf+s, t);
267 if (s < 0)
268 die("writing to file");
269 t -= s;
270 s = n - t;
271 } while (t);
272 } while (n > 0);
273
274 /* wait a little to let our readers finish reading */
275 sleep(1);
276
277 /* stop our readers */
278 for (cpu = 0; cpu < cpus; cpu++) {
279 if (pid_array[cpu] > 0)
280 kill(pid_array[cpu], SIGUSR1);
281 }
282
283 /* wait a little to have the readers clean up */
284 sleep(1);
285
286 /* Now put together the file */
287 temp_files = malloc_or_die(sizeof(*temp_files) * cpus);
288
289 for (cpu = 0; cpu < cpus; cpu++)
290 temp_files[cpu] = get_temp_file(node, port, cpu);
291
292 tracecmd_attach_cpu_data_fd(ofd, cpus, temp_files);
293
294 out_free:
295 for (cpu = 0; cpu < cpus; cpu++) {
296 if (pid_array[cpu] > 0) {
297 kill(pid_array[cpu], SIGKILL);
298 delete_temp_file(node, port, cpu);
299 pid_array[cpu] = 0;
300 }
301 }
302}
303
304static void do_listen(char *port)
305{
306 struct addrinfo hints;
307 struct addrinfo *result, *rp;
308 int sfd, s, cfd;
309 struct sockaddr_storage peer_addr;
310 socklen_t peer_addr_len;
311 ssize_t nread;
312 char buf[BUFSIZ];
313 char host[NI_MAXHOST], service[NI_MAXSERV];
314
315 memset(&hints, 0, sizeof(hints));
316 hints.ai_family = AF_UNSPEC;
317 hints.ai_socktype = SOCK_STREAM;
318 hints.ai_flags = AI_PASSIVE;
319
320 s = getaddrinfo(NULL, port, &hints, &result);
321 if (s != 0)
322 die("getaddrinfo: error opening %s", port);
323
324 for (rp = result; rp != NULL; rp = rp->ai_next) {
325 sfd = socket(rp->ai_family, rp->ai_socktype,
326 rp->ai_protocol);
327 if (sfd < 0)
328 continue;
329
330 if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
331 break;
332
333 close(sfd);
334 }
335
336 if (rp == NULL)
337 die("Could not bind");
338
339 freeaddrinfo(result);
340
341 if (listen(sfd, backlog) < 0)
342 die("listen");
343
344 peer_addr_len = sizeof(peer_addr);
345
346 do {
347 cfd = accept(sfd, (struct sockaddr *)&peer_addr, &peer_addr_len);
348 if (cfd < 0)
349 die("connecting");
350 s = getnameinfo((struct sockaddr *)&peer_addr, peer_addr_len,
351 host, NI_MAXHOST,
352 service, NI_MAXSERV, NI_NUMERICSERV);
353
354 if (s == 0)
355 printf("Connected with %s:%s\n",
356 host, service);
357 else {
358 printf("Error with getnameinfo: %s\n",
359 gai_strerror(s));
360 close(cfd);
361 close(sfd);
362 return;
363 }
364
365 process_client(host, service, cfd);
366
367 do {
368 if (nread > 0)
369 nread = read(cfd, buf, BUFSIZ);
370 if (cfd < 0)
371 die("client");
372 if (nread > 0)
373 write(1, buf, nread);
374 } while (nread);
375
376 close(cfd);
377 } while (0);
378}
379
380static void start_daemon(void)
381{
382}
383
384void trace_listen(int argc, char **argv)
385{
386 char *port = NULL;
387 char *iface;
388 int daemon = 0;
389 int c;
390
391 if (argc < 2)
392 usage(argv);
393
394 if (strcmp(argv[1], "listen") != 0)
395 usage(argv);
396
397 for (;;) {
398 int option_index = 0;
399 static struct option long_options[] = {
400 {"port", required_argument, NULL, 'p'},
401 {"help", no_argument, NULL, '?'},
402 {NULL, 0, NULL, 0}
403 };
404
405 c = getopt_long (argc-1, argv+1, "+hp:o:d:i:D",
406 long_options, &option_index);
407 if (c == -1)
408 break;
409 switch (c) {
410 case 'h':
411 usage(argv);
412 break;
413 case 'p':
414 port = optarg;
415 break;
416 case 'i':
417 iface = optarg;
418 break;
419 case 'd':
420 output_dir = optarg;
421 break;
422 case 'o':
423 output_file = optarg;
424 break;
425 case 'D':
426 daemon = 1;
427 default:
428 usage(argv);
429 }
430 }
431
432 if (!port)
433 usage(argv);
434
435 if ((argc - optind) >= 2)
436 usage(argv);
437
438 if (!output_file)
439 output_file = default_output_file;
440
441 if (!output_dir)
442 output_dir = default_output_dir;
443
444 if (daemon)
445 start_daemon();
446
447 do_listen(port);
448
449 return;
450}
diff --git a/trace-local.h b/trace-local.h
index 0e49fa4..4e44238 100644
--- a/trace-local.h
+++ b/trace-local.h
@@ -37,4 +37,6 @@ void trace_report(int argc, char **argv);
37 37
38void trace_split(int argc, char **argv); 38void trace_split(int argc, char **argv);
39 39
40void trace_listen(int argc, char **argv);
41
40#endif /* __TRACE_LOCAL_H */ 42#endif /* __TRACE_LOCAL_H */