diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | trace-cmd.c | 196 | ||||
-rw-r--r-- | trace-listen.c | 450 | ||||
-rw-r--r-- | trace-local.h | 2 |
4 files changed, 639 insertions, 11 deletions
@@ -140,7 +140,7 @@ endef | |||
140 | $(Q)$(call check_gui) | 140 | $(Q)$(call check_gui) |
141 | 141 | ||
142 | 142 | ||
143 | TRACE_CMD_OBJS = trace-cmd.o trace-read.o trace-split.o | 143 | TRACE_CMD_OBJS = trace-cmd.o trace-read.o trace-split.o trace-listen.o |
144 | TRACE_VIEW_OBJS = trace-view.o trace-view-store.o trace-filter.o trace-compat.o \ | 144 | TRACE_VIEW_OBJS = trace-view.o trace-view-store.o trace-filter.o trace-compat.o \ |
145 | trace-hash.o | 145 | trace-hash.o |
146 | TRACE_GRAPH_OBJS = trace-graph.o trace-compat.o trace-hash.o trace-filter.o \ | 146 | TRACE_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 | ||
51 | unsigned int page_size; | 53 | static unsigned int page_size; |
52 | 54 | ||
53 | static const char *output_file = "trace.dat"; | 55 | static const char *output_file = "trace.dat"; |
54 | 56 | ||
@@ -57,6 +59,10 @@ static int sleep_time = 1000; | |||
57 | static int cpu_count; | 59 | static int cpu_count; |
58 | static int *pids; | 60 | static int *pids; |
59 | 61 | ||
62 | static char *host; | ||
63 | static int *client_ports; | ||
64 | static int sfd; | ||
65 | |||
60 | static int filter_task; | 66 | static int filter_task; |
61 | static int filter_pid = -1; | 67 | static 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 | ||
904 | static 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 | |||
898 | static int create_recorder(int cpu) | 939 | static 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 | ||
975 | static 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 | |||
1074 | static void finish_network(void) | ||
1075 | { | ||
1076 | close(sfd); | ||
1077 | free(host); | ||
1078 | } | ||
1079 | |||
930 | static void start_threads(void) | 1080 | static 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 | |||
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 int backlog = 5; | ||
44 | |||
45 | #define TEMP_FILE_STR "%s.%s:%s.cpu%d", output_file, host, port, cpu | ||
46 | static 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 | |||
58 | static void put_temp_file(char *file) | ||
59 | { | ||
60 | free(file); | ||
61 | } | ||
62 | |||
63 | #define MAX_PATH 1024 | ||
64 | |||
65 | static 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 | |||
73 | static 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 | |||
87 | static int done; | ||
88 | static void finish(int sig) | ||
89 | { | ||
90 | done = 1; | ||
91 | } | ||
92 | |||
93 | static 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 | |||
135 | static 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 | |||
190 | static 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 | |||
304 | static 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 | |||
380 | static void start_daemon(void) | ||
381 | { | ||
382 | } | ||
383 | |||
384 | void 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 | ||
38 | void trace_split(int argc, char **argv); | 38 | void trace_split(int argc, char **argv); |
39 | 39 | ||
40 | void trace_listen(int argc, char **argv); | ||
41 | |||
40 | #endif /* __TRACE_LOCAL_H */ | 42 | #endif /* __TRACE_LOCAL_H */ |