libsysutils: Add multiple client support and fix some bugs
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
index 0b15c12..cbb1edf 100644
--- a/libsysutils/Android.mk
+++ b/libsysutils/Android.mk
@@ -3,12 +3,12 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- src/FrameworkManager.cpp \
src/SocketListener.cpp \
src/FrameworkListener.cpp \
src/NetlinkListener.cpp \
src/NetlinkEvent.cpp \
src/FrameworkCommand.cpp \
+ src/SocketClient.cpp \
LOCAL_MODULE:= libsysutils
diff --git a/libsysutils/src/FrameworkClient.cpp b/libsysutils/src/FrameworkClient.cpp
new file mode 100644
index 0000000..237bb60
--- /dev/null
+++ b/libsysutils/src/FrameworkClient.cpp
@@ -0,0 +1,41 @@
+#include <alloca.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#define LOG_TAG "FrameworkClient"
+#include <cutils/log.h>
+
+#include <sysutils/FrameworkClient.h>
+
+FrameworkClient::FrameworkClient(int socket) {
+ mSocket = socket;
+ pthread_mutex_init(&mWriteMutex, NULL);
+}
+
+int FrameworkClient::sendMsg(char *msg) {
+ LOGD("FrameworkClient::sendMsg(%s)", msg);
+ if (mSocket < 0) {
+ errno = EHOSTUNREACH;
+ return -1;
+ }
+
+ pthread_mutex_lock(&mWriteMutex);
+ if (write(mSocket, msg, strlen(msg) +1) < 0) {
+ LOGW("Unable to send msg '%s' (%s)", msg, strerror(errno));
+ }
+ pthread_mutex_unlock(&mWriteMutex);
+ return 0;
+}
+
+int FrameworkClient::sendMsg(char *msg, char *data) {
+ char *buffer = (char *) alloca(strlen(msg) + strlen(data) + 1);
+ if (!buffer) {
+ errno = -ENOMEM;
+ return -1;
+ }
+ strcpy(buffer, msg);
+ strcat(buffer, data);
+ return sendMsg(buffer);
+}
+
diff --git a/libsysutils/src/FrameworkCommand.cpp b/libsysutils/src/FrameworkCommand.cpp
index 0444de5..94e7426 100644
--- a/libsysutils/src/FrameworkCommand.cpp
+++ b/libsysutils/src/FrameworkCommand.cpp
@@ -25,7 +25,7 @@
mCommand = cmd;
}
-int FrameworkCommand::runCommand(char *data) {
+int FrameworkCommand::runCommand(SocketClient *c, char *data) {
LOGW("Command %s has no run handler!", getCommand());
errno = ENOSYS;
return -1;
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index b920215..9210ca5 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -22,17 +22,18 @@
#include <sysutils/FrameworkListener.h>
#include <sysutils/FrameworkCommand.h>
+#include <sysutils/SocketClient.h>
FrameworkListener::FrameworkListener(const char *socketName) :
SocketListener(socketName, true) {
mCommands = new FrameworkCommandCollection();
}
-bool FrameworkListener::onDataAvailable(int socket) {
+bool FrameworkListener::onDataAvailable(SocketClient *c) {
char buffer[101];
int len;
- if ((len = read(socket, buffer, sizeof(buffer) -1)) < 0) {
+ if ((len = read(c->getSocket(), buffer, sizeof(buffer) -1)) < 0) {
LOGE("read() failed (%s)", strerror(errno));
return errno;
} else if (!len) {
@@ -47,7 +48,7 @@
for (i = 0; i < len; i++) {
if (buffer[i] == '\0') {
- dispatchCommand(buffer + start);
+ dispatchCommand(c, buffer + start);
start = i + 1;
}
}
@@ -58,14 +59,22 @@
mCommands->push_back(cmd);
}
-void FrameworkListener::dispatchCommand(char *cmd) {
+void FrameworkListener::dispatchCommand(SocketClient *cli, char *cmd) {
+
+ char *cm, *last;
+
+ if (!(cm = strtok_r(cmd, ":", &last))) {
+ cli->sendMsg("BAD_MSG");
+ return;
+ }
+
FrameworkCommandCollection::iterator i;
for (i = mCommands->begin(); i != mCommands->end(); ++i) {
FrameworkCommand *c = *i;
- if (!strncmp(cmd, c->getCommand(), strlen(c->getCommand()))) {
- if (c->runCommand(cmd)) {
+ if (!strcmp(cm, c->getCommand())) {
+ if (c->runCommand(cli, cmd)) {
LOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
}
return;
@@ -73,5 +82,6 @@
}
LOGE("No cmd handlers defined for '%s'", cmd);
+ cli->sendMsg("UNKNOWN_CMD");
+ return;
}
-
diff --git a/libsysutils/src/FrameworkManager.cpp b/libsysutils/src/FrameworkManager.cpp
deleted file mode 100644
index 5dceb9f..0000000
--- a/libsysutils/src/FrameworkManager.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/un.h>
-
-#include <cutils/config_utils.h>
-#include <cutils/cpu_info.h>
-#include <cutils/properties.h>
-#include <cutils/sockets.h>
-
-#define LOG_TAG "FrameworkManager"
-#include <cutils/log.h>
-
-#include <sysutils/FrameworkManager.h>
-#include <sysutils/FrameworkListener.h>
-
-FrameworkManager::FrameworkManager(FrameworkListener *Listener) {
- mDoorbell = -1;
- mFwSock = -1;
- mListener = Listener;
-
- pthread_mutex_init(&mWriteMutex, NULL);
-}
-
-int FrameworkManager::run() {
-
- if (mListener->run()) {
- LOGE("Error running listener (%s)", strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-/* ========
- * Privates
- * ========
- */
-
-int FrameworkManager::sendMsg(char *msg) {
- LOGD("FrameworkManager::sendMsg(%s)", msg);
- if (mFwSock < 0) {
- errno = EHOSTUNREACH;
- return -1;
- }
-
- pthread_mutex_lock(&mWriteMutex);
- if (write(mFwSock, msg, strlen(msg) +1) < 0) {
- LOGW("Unable to send msg '%s' (%s)", msg, strerror(errno));
- }
- pthread_mutex_unlock(&mWriteMutex);
- return 0;
-}
-
-int FrameworkManager::sendMsg(char *msg, char *data) {
- char *buffer = (char *) alloca(strlen(msg) + strlen(data) + 1);
- if (!buffer) {
- errno = -ENOMEM;
- return -1;
- }
- strcpy(buffer, msg);
- strcat(buffer, data);
- return sendMsg(buffer);
-}
diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp
index 96a616d..3ec9d9d 100644
--- a/libsysutils/src/NetlinkListener.cpp
+++ b/libsysutils/src/NetlinkListener.cpp
@@ -29,8 +29,9 @@
SocketListener(socket, false) {
}
-bool NetlinkListener::onDataAvailable(int socket)
+bool NetlinkListener::onDataAvailable(SocketClient *cli)
{
+ int socket = cli->getSocket();
LOGD("NetlinkListener::onDataAvailable()");
int count;
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
new file mode 100644
index 0000000..6db62b3
--- /dev/null
+++ b/libsysutils/src/SocketClient.cpp
@@ -0,0 +1,41 @@
+#include <alloca.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#define LOG_TAG "SocketClient"
+#include <cutils/log.h>
+
+#include <sysutils/SocketClient.h>
+
+SocketClient::SocketClient(int socket) {
+ mSocket = socket;
+ pthread_mutex_init(&mWriteMutex, NULL);
+}
+
+int SocketClient::sendMsg(char *msg) {
+ LOGD("SocketClient::sendMsg(%s)", msg);
+ if (mSocket < 0) {
+ errno = EHOSTUNREACH;
+ return -1;
+ }
+
+ pthread_mutex_lock(&mWriteMutex);
+ if (write(mSocket, msg, strlen(msg) +1) < 0) {
+ LOGW("Unable to send msg '%s' (%s)", msg, strerror(errno));
+ }
+ pthread_mutex_unlock(&mWriteMutex);
+ return 0;
+}
+
+int SocketClient::sendMsg(char *msg, char *data) {
+ char *buffer = (char *) alloca(strlen(msg) + strlen(data) + 1);
+ if (!buffer) {
+ errno = -ENOMEM;
+ return -1;
+ }
+ strcpy(buffer, msg);
+ strcat(buffer, data);
+ return sendMsg(buffer);
+}
+
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index f92e30d..cb69bfd 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -24,26 +24,28 @@
#define LOG_TAG "SocketListener"
#include <cutils/log.h>
-
#include <cutils/sockets.h>
#include <sysutils/SocketListener.h>
+#include <sysutils/SocketClient.h>
-SocketListener::SocketListener(const char *socketName, bool acceptClients) {
- mAcceptClients = acceptClients;
- mCsock = -1;
+SocketListener::SocketListener(const char *socketName, bool listen) {
+ mListen = listen;
mSocketName = socketName;
mSock = -1;
+ pthread_mutex_init(&mClientsLock, NULL);
+ mClients = new SocketClientCollection();
}
-SocketListener::SocketListener(int socketFd, bool acceptClients) {
- mAcceptClients = acceptClients;
- mCsock = -1;
+SocketListener::SocketListener(int socketFd, bool listen) {
+ mListen = listen;
mSocketName = NULL;
mSock = socketFd;
+ pthread_mutex_init(&mClientsLock, NULL);
+ mClients = new SocketClientCollection();
}
-int SocketListener::run() {
+int SocketListener::startListener() {
if (!mSocketName && mSock == -1) {
errno = EINVAL;
@@ -56,72 +58,155 @@
}
}
- if (mAcceptClients) {
- if (listen(mSock, 4) < 0) {
- LOGE("Unable to listen on socket (%s)", strerror(errno));
- return -1;
- }
+ if (mListen && listen(mSock, 4) < 0) {
+ LOGE("Unable to listen on socket (%s)", strerror(errno));
+ return -1;
+ } else if (!mListen) {
+ mClients->push_back(new SocketClient(mSock));
+ LOGD("Created phantom client");
}
+ if (pipe(mCtrlPipe))
+ return -1;
+
+ if (pthread_create(&mThread, NULL, SocketListener::threadStart, this))
+ return -1;
+
+ return 0;
+}
+
+int SocketListener::stopListener() {
+ char c = 0;
+
+ if (write(mCtrlPipe[1], &c, 1) != 1) {
+ LOGE("Error writing to control pipe (%s)", strerror(errno));
+ return -1;
+ }
+
+ LOGD("Signaled listener thread - waiting for it to die");
+ void *ret;
+ if (pthread_join(mThread, &ret)) {
+ LOGE("Error joining to listener thread (%s)", strerror(errno));
+ return -1;
+ }
+ LOGD("Listener stopped");
+ return 0;
+}
+
+void *SocketListener::threadStart(void *obj) {
+ SocketListener *me = reinterpret_cast<SocketListener *>(obj);
+
+ me->runListener();
+ LOGD("Listener thread shutting down");
+ pthread_exit(NULL);
+ return NULL;
+}
+
+void SocketListener::runListener() {
+
while(1) {
+ SocketClientCollection::iterator it;
fd_set read_fds;
struct timeval to;
- int max = 0;
int rc = 0;
to.tv_sec = 60 * 60;
to.tv_usec = 0;
+ int max = 0;
+
FD_ZERO(&read_fds);
- if ((mAcceptClients == false) ||
- (mAcceptClients == true && mCsock == -1)) {
- FD_SET(mSock, &read_fds);
+ if (mListen) {
max = mSock;
- } else if (mCsock != -1) {
- FD_SET(mCsock, &read_fds);
- max = mCsock;
+ FD_SET(mSock, &read_fds);
}
+ FD_SET(mCtrlPipe[0], &read_fds);
+ if (mCtrlPipe[0] > max)
+ max = mCtrlPipe[0];
+
+ pthread_mutex_lock(&mClientsLock);
+ for (it = mClients->begin(); it != mClients->end(); ++it) {
+ FD_SET((*it)->getSocket(), &read_fds);
+ if ((*it)->getSocket() > max)
+ max = (*it)->getSocket();
+ }
+ pthread_mutex_unlock(&mClientsLock);
+
if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) {
LOGE("select failed (%s)", strerror(errno));
- return -errno;
- } else if (!rc)
+ sleep(1);
continue;
- else if (FD_ISSET(mSock, &read_fds)) {
- /*
- * If we're accepting client connections then
- * accept and gobble the event. Otherwise
- * pass it on to the handlers.
- */
- if (mAcceptClients) {
- struct sockaddr addr;
- socklen_t alen = sizeof(addr);
+ } else if (!rc) {
+ LOGD("select timeout");
+ continue;
+ }
- if ((mCsock = accept(mSock, &addr, &alen)) < 0) {
- LOGE("accept failed (%s)", strerror(errno));
- return -errno;
+ if (FD_ISSET(mCtrlPipe[0], &read_fds)) {
+ LOGD("Control message received");
+ break;
+ }
+ if (mListen && FD_ISSET(mSock, &read_fds)) {
+ struct sockaddr addr;
+ socklen_t alen = sizeof(addr);
+ int c;
+
+ if ((c = accept(mSock, &addr, &alen)) < 0) {
+ LOGE("accept failed (%s)", strerror(errno));
+ sleep(1);
+ continue;
+ }
+ LOGD("SocketListener client connection accepted");
+ pthread_mutex_lock(&mClientsLock);
+ mClients->push_back(new SocketClient(c));
+ pthread_mutex_unlock(&mClientsLock);
+ }
+
+ do {
+ pthread_mutex_lock(&mClientsLock);
+ for (it = mClients->begin(); it != mClients->end(); ++it) {
+ int fd = (*it)->getSocket();
+ if (FD_ISSET(fd, &read_fds)) {
+ pthread_mutex_unlock(&mClientsLock);
+ if (!onDataAvailable(*it)) {
+ LOGD("SocketListener closing client socket");
+ close(fd);
+ pthread_mutex_lock(&mClientsLock);
+ delete *it;
+ it = mClients->erase(it);
+ pthread_mutex_unlock(&mClientsLock);
+ }
+ FD_CLR(fd, &read_fds);
+ continue;
}
- LOGD("SocketListener client connection accepted");
- } else if (!onDataAvailable(mSock)) {
- LOGW("SocketListener closing listening socket (Will shut down)");
- close(mSock);
- return -ESHUTDOWN;
}
- } else if ((FD_ISSET(mCsock, &read_fds)) &&
- !onDataAvailable(mCsock)) {
- /*
- * Once mCsock == -1, we'll start
- * accepting connections on mSock again.
- */
- LOGD("SocketListener closing client socket");
- close(mCsock);
- mCsock = -1;
- }
+ pthread_mutex_unlock(&mClientsLock);
+ } while (0);
}
- return 0;
}
-bool SocketListener::onDataAvailable(int socket) {
- return false;
+void SocketListener::sendBroadcast(char *msg) {
+ pthread_mutex_lock(&mClientsLock);
+ SocketClientCollection::iterator i;
+
+ for (i = mClients->begin(); i != mClients->end(); ++i) {
+ if ((*i)->sendMsg(msg)) {
+ LOGW("Error sending broadcast (%s)", strerror(errno));
+ }
+ }
+ pthread_mutex_unlock(&mClientsLock);
}
+
+void SocketListener::sendBroadcast(char *msg, char *data) {
+ pthread_mutex_lock(&mClientsLock);
+ SocketClientCollection::iterator i;
+
+ for (i = mClients->begin(); i != mClients->end(); ++i) {
+ if ((*i)->sendMsg(msg, data)) {
+ LOGW("Error sending broadcast (%s)", strerror(errno));
+ }
+ }
+ pthread_mutex_unlock(&mClientsLock);
+}
+