1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // When run with 2 or more arguments the file_poller tool will open a port on
6 // the device, print it on its standard output and then start collect file
7 // contents. The first argument is the polling rate in Hz, and the following
8 // arguments are file to poll.
9 // When run with the port of an already running file_poller, the tool will
10 // contact the first instance, retrieve the sample and print those on its
11 // standard output. This will also terminate the first instance.
15 #include <netinet/in.h>
18 #include <sys/socket.h>
21 #include <sys/types.h>
24 #include "base/logging.h"
26 // Context containing the files to poll and the polling rate.
33 // Write from the buffer to the given file descriptor.
34 void safe_write(int fd
, const char* buffer
, int size
) {
35 const char* index
= buffer
;
36 size_t to_write
= size
;
37 while (to_write
> 0) {
38 int written
= write(fd
, index
, to_write
);
46 // Transfer the content of a file descriptor to another.
47 void transfer_to_fd(int fd_in
, int fd_out
) {
50 while ((n
= read(fd_in
, buffer
, sizeof(buffer
))) > 0)
51 safe_write(fd_out
, buffer
, n
);
54 // Transfer the content of a file descriptor to a buffer.
55 int transfer_to_buffer(int fd_in
, char* bufffer
, size_t size
) {
56 char* index
= bufffer
;
57 size_t to_read
= size
;
59 while (to_read
> 0 && ((n
= read(fd_in
, index
, to_read
)) > 0)) {
65 return size
- to_read
;
68 // Try to open the file at the given path for reading. Exit in case of failure.
69 int checked_open(const char* path
) {
70 int fd
= open(path
, O_RDONLY
);
76 void transfer_measurement(int fd_in
, int fd_out
, bool last
) {
78 if (lseek(fd_in
, 0, SEEK_SET
) < 0)
80 int n
= transfer_to_buffer(fd_in
, buffer
, sizeof(buffer
));
81 safe_write(fd_out
, buffer
, n
- 1);
82 safe_write(fd_out
, last
? "\n" : " ", 1);
85 // Acquire a sample and save it to the given file descriptor.
86 void acquire_sample(int fd
, const Context
& context
) {
88 gettimeofday(&tv
, NULL
);
90 int n
= snprintf(buffer
, sizeof(buffer
), "%d.%06d ", tv
.tv_sec
, tv
.tv_usec
);
91 safe_write(fd
, buffer
, n
);
93 for (int i
= 0; i
< context
.nb_files
; ++i
)
94 transfer_measurement(context
.file_fds
[i
], fd
, i
== (context
.nb_files
- 1));
97 void poll_content(const Context
& context
) {
98 // Create and bind the socket so that the port can be written to stdout.
99 int sockfd
= socket(AF_INET
, SOCK_STREAM
, 0);
100 struct sockaddr_in socket_info
;
101 socket_info
.sin_family
= AF_INET
;
102 socket_info
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
103 socket_info
.sin_port
= htons(0);
104 if (bind(sockfd
, (struct sockaddr
*)&socket_info
, sizeof(socket_info
)) < 0)
106 socklen_t size
= sizeof(socket_info
);
107 getsockname(sockfd
, (struct sockaddr
*)&socket_info
, &size
);
108 printf("%d\n", ntohs(socket_info
.sin_port
));
109 // Using a pipe to ensure child is diconnected from the terminal before
118 // Not expecting any data to be received.
119 read(pipes
[0], NULL
, 1);
120 signal(SIGCHLD
, SIG_IGN
);
124 // Detach from terminal.
127 close(STDOUT_FILENO
);
128 close(STDERR_FILENO
);
131 // Start listening for incoming connection.
132 if (listen(sockfd
, 1) < 0)
135 // Signal the parent that it can now safely exit.
138 // Prepare file to store the samples.
140 char filename
[] = "/data/local/tmp/fileXXXXXX";
141 fd
= mkstemp(filename
);
144 // Collect samples until a client connect on the socket.
146 struct timeval timeout
;
148 acquire_sample(fd
, context
);
150 timeout
.tv_usec
= 1000000 / context
.poll_rate
;
152 FD_SET(sockfd
, &rfds
);
153 } while (select(sockfd
+ 1, &rfds
, NULL
, NULL
, &timeout
) == 0);
155 // Collect a final sample.
156 acquire_sample(fd
, context
);
158 // Send the result back.
159 struct sockaddr_in remote_socket_info
;
160 int rfd
= accept(sockfd
, (struct sockaddr
*)&remote_socket_info
, &size
);
163 if (lseek(fd
, 0, SEEK_SET
) < 0)
165 transfer_to_fd(fd
, rfd
);
168 void content_collection(int port
) {
169 int sockfd
= socket(AF_INET
, SOCK_STREAM
, 0);
170 // Connect to localhost.
171 struct sockaddr_in socket_info
;
172 socket_info
.sin_family
= AF_INET
;
173 socket_info
.sin_addr
.s_addr
= htonl(0x7f000001);
174 socket_info
.sin_port
= htons(port
);
175 if (connect(sockfd
, (struct sockaddr
*)&socket_info
, sizeof(socket_info
)) <
179 transfer_to_fd(sockfd
, STDOUT_FILENO
);
182 int main(int argc
, char** argv
) {
187 " %s rate FILE...\n",
193 // Argument is the port to connect to.
194 content_collection(atoi(argv
[1]));
196 // First argument is the poll frequency, in Hz, following arguments are the
199 context
.poll_rate
= atoi(argv
[1]);
200 context
.nb_files
= argc
- 2;
201 context
.file_fds
= new int[context
.nb_files
];
202 for (int i
= 2; i
< argc
; ++i
)
203 context
.file_fds
[i
- 2] = checked_open(argv
[i
]);
204 poll_content(context
);