summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2014-08-25 16:07:12 -0700
committerLorenzo Colitti <lorenzo@google.com>2014-08-25 16:37:18 -0700
commitdce3ddf54083ccd0e3752c4c08013688f79baa7a (patch)
treeff51ef9f8db56e4b676bae8b0f3a83a73811d254
parent545bdca4e73b5aa56b81a735ead316eb6d33c326 (diff)
downloadandroid_external_android-clat-dce3ddf54083ccd0e3752c4c08013688f79baa7a.tar.gz
android_external_android-clat-dce3ddf54083ccd0e3752c4c08013688f79baa7a.tar.bz2
android_external_android-clat-dce3ddf54083ccd0e3752c4c08013688f79baa7a.zip
Call read on any event, not just on POLLIN.
The main clatd event loop calls poll() in a loop, but reads only from FDs that have POLLIN set. This causes it to get into an infinite loop if one of the fds has POLLERR set. Instead, read from all fds that have reported events. The read causes the kernel to return the error to userspace and clear the socket error flag, and poll starts working correctly after that. Bug: 17183471 Bug: 17186694 Change-Id: Ie25853e0d60c077d2478b3e5154946e201f96dca
-rw-r--r--clatd.c23
-rw-r--r--clatd.h2
2 files changed, 14 insertions, 11 deletions
diff --git a/clatd.c b/clatd.c
index 56eb66a..dbf725b 100644
--- a/clatd.c
+++ b/clatd.c
@@ -375,27 +375,28 @@ void read_packet(int active_fd, const struct tun_data *tunnel) {
*/
void event_loop(const struct tun_data *tunnel) {
time_t last_interface_poll;
- struct pollfd wait_fd[2];
+ struct pollfd wait_fd[] = {
+ { tunnel->read_fd6, POLLIN, 0 },
+ { tunnel->fd4, POLLIN, 0 },
+ };
// start the poll timer
last_interface_poll = time(NULL);
- wait_fd[0].fd = tunnel->read_fd6;
- wait_fd[0].events = POLLIN;
- wait_fd[0].revents = 0;
- wait_fd[1].fd = tunnel->fd4;
- wait_fd[1].events = POLLIN;
- wait_fd[1].revents = 0;
-
while(running) {
if(poll(wait_fd, 2, NO_TRAFFIC_INTERFACE_POLL_FREQUENCY*1000) == -1) {
if(errno != EINTR) {
logmsg(ANDROID_LOG_WARN,"event_loop/poll returned an error: %s",strerror(errno));
}
} else {
- int i;
- for(i = 0; i < 2; i++) {
- if((wait_fd[i].revents & POLLIN) != 0) {
+ size_t i;
+ for(i = 0; i < ARRAY_SIZE(wait_fd); i++) {
+ // Call read_packet if the socket has data to be read, but also if an
+ // error is waiting. If we don't call read() after getting POLLERR, a
+ // subsequent poll() will return immediately with POLLERR again,
+ // causing this code to spin in a loop. Calling read() will clear the
+ // socket error flag instead.
+ if(wait_fd[i].revents != 0) {
read_packet(wait_fd[i].fd,tunnel);
}
}
diff --git a/clatd.h b/clatd.h
index 0f4809d..ca7369b 100644
--- a/clatd.h
+++ b/clatd.h
@@ -25,6 +25,8 @@
#define PACKETLEN (MAXMTU+sizeof(struct tun_pi))
#define CLATD_VERSION "1.3"
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
// how frequently (in seconds) to poll for an address change while traffic is passing
#define INTERFACE_POLL_FREQUENCY 30