diff options
author | Yoshihiro YUNOMAE <yoshihiro.yunomae.ez@hitachi.com> | 2014-07-11 00:58:26 +0000 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2016-03-21 17:18:44 -0400 |
commit | 7ea7f9846352f4b607bb1cc7e7b680eca61c12e4 (patch) | |
tree | 041e6d0807a5bf830f1f1b65503488d037c6e38d /trace-listen.c | |
parent | 8bbbaaaf78ecd479d149fc84ab7d50be90c3540d (diff) | |
download | trace-cmd-7ea7f9846352f4b607bb1cc7e7b680eca61c12e4.tar.gz |
trace-cmd/listen: Apply the trace-msg protocol for communication between a server and clients
Apply trace-msg protocol for communication between a server and clients.
Currently, trace-listen(server) and trace-record -N(client) operate as follows:
<server> <client>
listen to socket fd
connect to socket fd
accept the client
send "tracecmd"
+------------> receive "tracecmd"
check "tracecmd"
send cpus
receive cpus <------------+
print "cpus=XXX"
send pagesize
|
receive pagesize <--------+
print "pagesize=XXX"
send option
|
receive option <----------+
understand option
send port_array
+------------> receive port_array
understand port_array
send meta data
receive meta data <-------+
record meta data
(snip)
read block
--- start sending trace data on child processes ---
--- When client finishes sending trace data ---
close(socket fd)
read size = 0
close(socket fd)
All messages are unstructured character strings, so server(client) using the
protocol must parse the unstructured messages. Since it is hard to
add complex contents in the protocol, structured binary message trace-msg
is introduced as the communication protocol.
By applying this patch, server and client operate as follows:
<server> <client>
listen to socket fd
connect to socket fd
accept the client
send "tracecmd"
+------------> receive "tracecmd"
check "tracecmd"
send "V2\0<MAGIC_NUMBER>\00" as the v2 protocol
receive "V2" <------------+
check "V2"
read "<MAGIC_NUMBER>\00"
send "V2"
+---------------> receive "V2"
check "V2"
send cpus,pagesize,option(MSG_TINIT)
receive MSG_TINIT <-------+
print "cpus=XXX"
print "pagesize=XXX"
understand option
send port_array
+--MSG_RINIT-> receive MSG_RINIT
understand port_array
send meta data(MSG_SENDMETA)
receive MSG_SENDMETA <----+
record meta data
(snip)
send a message to finish sending meta data
| (MSG_FINMETA)
receive MSG_FINMETA <-----+
read block
--- start sending trace data on child processes ---
--- When client finishes sending trace data ---
send MSG_CLOSE
receive MSG_CLOSE <-------+
close(socket fd) close(socket fd)
By introducing the v2 protocol, after the client checks "tracecmd", the client
will send "V2\0<MAGIC_NUMBER>\00\0". This complex message is used when the
new client tries to connect to the old server. The new client wants to check
whether the reply message from the server is "V2" or not. However, the old
server does not respond to the client before receiving cpu numbers, page size,
and options. Each message is separated with "\0" in the old server, so the
client send "V2" as cpu numbers, "<MAGIC_NUMBER>" as page size, and "0" as
no options. On the other hands, the old server will understand the messages
as cpus=0, pagesize=<MAGIC_NUMBER>, and options=0, and then the server will
send the message "\0" as port numbers. Then, the message which the client
receives is not "V2" but "\0", so the client will reconnect to the old server
as the v1 protocol.
<How to test>
[1] Backward compatability checks
We need to test backward compatability of this patch for old
trace-cmds(client/server). So, this patch was tested for [2] command checks in
following 3 types:
<client> <server>
new old
old new
new new
[2] Command checks
- server (common)
# trace-cmd listen -p 12345
1) record
- client
# trace-cmd record -e sched -N <server IP>:12345
^C
2) record + multiple buffers
- client
# trace-cmd record -B foo -e sched -N <server IP>:12345
^C
3) extract
- client
# ./trace-cmd start -e sched
# sleep 5
# ./trace-cmd extract -N <server IP>:12345
4) extract + snapshot
- client
# ./trace-cmd start -e sched
# sleep 5
# ./trace-cmd snapshot -s
# ./trace-cmd extract -N <server IP>:12345 -s
Changes in V4: Fix some typos, cleanups and rebase for current trace-cmd-v2.4
Change the argument of tracecmd_msg_recv()
Changes in V3: Change the license of trace-msg.c to LGPL v2.1
Changes in V2: Regacy porotocol support in order to keep backward compatibility
Link: http://lkml.kernel.org/r/20140711005826.25516.77711.stgit@yuno-kbuild.novalocal
Signed-off-by: Yoshihiro YUNOMAE <yoshihiro.yunomae.ez@hitachi.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'trace-listen.c')
-rw-r--r-- | trace-listen.c | 137 |
1 files changed, 84 insertions, 53 deletions
diff --git a/trace-listen.c b/trace-listen.c index 1e38edac..77df7c3d 100644 --- a/trace-listen.c +++ b/trace-listen.c @@ -33,6 +33,7 @@ #include <errno.h> #include "trace-local.h" +#include "trace-msg.h" #define MAX_OPTION_SIZE 4096 @@ -45,10 +46,10 @@ static FILE *logfp; static int debug; -static int use_tcp; - static int backlog = 5; +static int proto_ver; + #define TEMP_FILE_STR "%s.%s:%s.cpu%d", output_file, host, port, cpu static char *get_temp_file(const char *host, const char *port, int cpu) { @@ -114,10 +115,9 @@ static int process_option(char *option) return 0; } -static int done; static void finish(int sig) { - done = 1; + done = true; } #define LOG_BUF_SIZE 1024 @@ -146,7 +146,7 @@ static void __plog(const char *prefix, const char *fmt, va_list ap, fprintf(fp, "%.*s", r, buf); } -static void plog(const char *fmt, ...) +void plog(const char *fmt, ...) { va_list ap; @@ -155,7 +155,7 @@ static void plog(const char *fmt, ...) va_end(ap); } -static void pdie(const char *fmt, ...) +void pdie(const char *fmt, ...) { va_list ap; char *str = ""; @@ -334,58 +334,80 @@ static int communicate_with_client(int fd, int *cpus, int *pagesize) *cpus = atoi(buf); - plog("cpus=%d\n", *cpus); - if (*cpus < 0) - return -EINVAL; + /* Is the client using the new protocol? */ + if (!*cpus) { + if (memcmp(buf, "V2", 2) != 0) { + plog("Cannot handle the protocol %s", buf); + return -EINVAL; + } - /* next read the page size */ - n = read_string(fd, buf, BUFSIZ); - if (n == BUFSIZ) - /** ERROR **/ - return -EINVAL; + /* read the rest of dummy data, but not use */ + read(fd, buf, sizeof(V2_MAGIC)+1); - *pagesize = atoi(buf); + proto_ver = V2_PROTOCOL; - plog("pagesize=%d\n", *pagesize); - if (*pagesize <= 0) - return -EINVAL; + /* Let the client know we use v2 protocol */ + write(fd, "V2", 2); - /* Now the number of options */ - n = read_string(fd, buf, BUFSIZ); - if (n == BUFSIZ) - /** ERROR **/ - return -EINVAL; + /* read the CPU count, the page size, and options */ + if (tracecmd_msg_initial_setting(fd, cpus, pagesize) < 0) + return -EINVAL; + } else { + /* The client is using the v1 protocol */ - options = atoi(buf); + plog("cpus=%d\n", *cpus); + if (*cpus < 0) + return -EINVAL; - for (i = 0; i < options; i++) { - /* next is the size of the options */ + /* next read the page size */ n = read_string(fd, buf, BUFSIZ); if (n == BUFSIZ) /** ERROR **/ return -EINVAL; - size = atoi(buf); - /* prevent a client from killing us */ - if (size > MAX_OPTION_SIZE) + + *pagesize = atoi(buf); + + plog("pagesize=%d\n", *pagesize); + if (*pagesize <= 0) return -EINVAL; - option = malloc(size); - if (!option) - return -ENOMEM; - do { - t = size; - s = 0; - s = read(fd, option+s, t); - if (s <= 0) - return -EIO; - t -= s; - s = size - t; - } while (t); - s = process_option(option); - free(option); - /* do we understand this option? */ - if (!s) + /* Now the number of options */ + n = read_string(fd, buf, BUFSIZ); + if (n == BUFSIZ) + /** ERROR **/ return -EINVAL; + + options = atoi(buf); + + for (i = 0; i < options; i++) { + /* next is the size of the options */ + n = read_string(fd, buf, BUFSIZ); + if (n == BUFSIZ) + /** ERROR **/ + return -EINVAL; + size = atoi(buf); + /* prevent a client from killing us */ + if (size > MAX_OPTION_SIZE) + return -EINVAL; + option = malloc(size); + if (!option) + return -ENOMEM; + do { + t = size; + s = 0; + s = read(fd, option+s, t); + if (s <= 0) + return -EIO; + t -= s; + s = size - t; + } while (t); + + s = process_option(option); + free(option); + /* do we understand this option? */ + if (!s) + return -EINVAL; + } } if (use_tcp) @@ -462,14 +484,20 @@ static int *create_all_readers(int cpus, const char *node, const char *port, start_port = udp_port + 1; } - /* send the client a comma deliminated set of port numbers */ - for (cpu = 0; cpu < cpus; cpu++) { - snprintf(buf, BUFSIZ, "%s%d", - cpu ? "," : "", port_array[cpu]); - write(fd, buf, strlen(buf)); + if (proto_ver == V2_PROTOCOL) { + /* send set of port numbers to the client */ + if (tracecmd_msg_send_port_array(fd, cpus, port_array) < 0) + goto out_free; + } else { + /* send the client a comma deliminated set of port numbers */ + for (cpu = 0; cpu < cpus; cpu++) { + snprintf(buf, BUFSIZ, "%s%d", + cpu ? "," : "", port_array[cpu]); + write(fd, buf, strlen(buf)); + } + /* end with null terminator */ + write(fd, "\0", 1); } - /* end with null terminator */ - write(fd, "\0", 1); return pid_array; @@ -563,7 +591,10 @@ static int process_client(const char *node, const char *port, int fd) return -ENOMEM; /* Now we are ready to start reading data from the client */ - collect_metadata_from_client(fd, ofd); + if (proto_ver == V2_PROTOCOL) + tracecmd_msg_collect_metadata(fd, ofd); + else + collect_metadata_from_client(fd, ofd); /* wait a little to let our readers finish reading */ sleep(1); |