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);
+}
+