OSDN Git Service

Support more than one clatd at a time.
authorLorenzo Colitti <lorenzo@google.com>
Mon, 20 Oct 2014 08:14:13 +0000 (17:14 +0900)
committerLorenzo Colitti <lorenzo@google.com>
Tue, 28 Oct 2014 13:37:56 +0000 (22:37 +0900)
1. Change from a single PID to a map of interface names to PIDs.
2. Make clatd commands take an interface argument.
3. Give the clatd processes names that depend on their parent
   interface, e.g., clatd-rmnet0.

Bug: 12111730
Change-Id: Ia770952d6511f8598a3356be5911da4ffa01b46a

server/ClatdController.cpp
server/ClatdController.h
server/CommandListener.cpp

index c19e299..b97ea32 100644 (file)
@@ -13,6 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <map>
+#include <string>
+
 #include <unistd.h>
 #include <errno.h>
 #include <sys/types.h>
 #define LOG_TAG "ClatdController"
 #include <cutils/log.h>
 
+#include <resolv_netid.h>
+
 #include "NetdConstants.h"
 #include "ClatdController.h"
 #include "Fwmark.h"
 #include "NetdConstants.h"
 #include "NetworkController.h"
 
+static const char* kClatdPath = "/system/bin/clatd";
+
 ClatdController::ClatdController(NetworkController* controller)
-        : mNetCtrl(controller), mClatdPid(0) {
+        : mNetCtrl(controller) {
 }
 
 ClatdController::~ClatdController() {
 }
 
-int ClatdController::startClatd(char *interface) {
-    pid_t pid;
+// Returns the PID of the clatd running on interface |interface|, or 0 if clatd is not running on
+// |interface|.
+pid_t ClatdController::getClatdPid(char* interface) {
+    auto it = mClatdPids.find(interface);
+    return (it == mClatdPids.end() ? 0 : it->second);
+}
+
+int ClatdController::startClatd(char* interface) {
+    pid_t pid = getClatdPid(interface);
 
-    if(mClatdPid != 0) {
-        ALOGE("clatd already running");
+    if (pid != 0) {
+        ALOGE("clatd pid=%d already started on %s", pid, interface);
         errno = EBUSY;
         return -1;
     }
 
-    if (!isIfaceName(interface)) {
-        errno = ENOENT;
-        return -1;
-    }
+    ALOGD("starting clatd on %s", interface);
 
-    ALOGD("starting clatd");
+    std::string progname("clatd-");
+    progname += interface;
 
     if ((pid = fork()) < 0) {
         ALOGE("fork failed (%s)", strerror(errno));
@@ -58,11 +70,16 @@ int ClatdController::startClatd(char *interface) {
     if (!pid) {
         // Pass in the interface, a netid to use for DNS lookups, and a fwmark for outgoing packets.
         unsigned netId = mNetCtrl->getNetworkForInterface(interface);
+        if (netId == NETID_UNSET) {
+            ALOGE("interface %s not assigned to any netId", interface);
+            errno = ENODEV;
+            return -1;
+        }
+
         char netIdString[UINT32_STRLEN];
         snprintf(netIdString, sizeof(netIdString), "%u", netId);
 
         Fwmark fwmark;
-
         fwmark.netId = netId;
         fwmark.explicitlySelected = true;
         fwmark.protectedFromVpn = true;
@@ -72,7 +89,7 @@ int ClatdController::startClatd(char *interface) {
         snprintf(fwmarkString, sizeof(fwmarkString), "0x%x", fwmark.intValue);
 
         char *args[] = {
-            (char *) "/system/bin/clatd",
+            (char *) progname.c_str(),
             (char *) "-i",
             interface,
             (char *) "-n",
@@ -82,44 +99,48 @@ int ClatdController::startClatd(char *interface) {
             NULL
         };
 
-        if (execv(args[0], args)) {
+        if (execv(kClatdPath, args)) {
             ALOGE("execv failed (%s)", strerror(errno));
+            return -1;
         }
         ALOGE("Should never get here!");
         _exit(0);
     } else {
-        mClatdPid = pid;
-        ALOGD("clatd started");
+        mClatdPids[interface] = pid;
+        ALOGD("clatd started on %s", interface);
     }
 
     return 0;
 }
 
-int ClatdController::stopClatd() {
-    if (mClatdPid == 0) {
+int ClatdController::stopClatd(char* interface) {
+    pid_t pid = getClatdPid(interface);
+
+    if (pid == 0) {
         ALOGE("clatd already stopped");
         return -1;
     }
 
-    ALOGD("Stopping clatd");
+    ALOGD("Stopping clatd pid=%d on %s", pid, interface);
 
-    kill(mClatdPid, SIGTERM);
-    waitpid(mClatdPid, NULL, 0);
-    mClatdPid = 0;
+    kill(pid, SIGTERM);
+    waitpid(pid, NULL, 0);
+    mClatdPids.erase(interface);
 
-    ALOGD("clatd stopped");
+    ALOGD("clatd on %s stopped", interface);
 
     return 0;
 }
 
-bool ClatdController::isClatdStarted() {
+bool ClatdController::isClatdStarted(char* interface) {
     pid_t waitpid_status;
-    if(mClatdPid == 0) {
+    pid_t pid = getClatdPid(interface);
+    if (pid == 0) {
         return false;
     }
-    waitpid_status = waitpid(mClatdPid, NULL, WNOHANG);
-    if(waitpid_status != 0) {
-        mClatdPid = 0; // child exited, don't call waitpid on it again
+    waitpid_status = waitpid(pid, NULL, WNOHANG);
+    if (waitpid_status != 0) {
+        mClatdPids.erase(interface);  // child exited, don't call waitpid on it again
     }
     return waitpid_status == 0; // 0 while child is running
 }
index 5bf48d9..1985836 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef _CLATD_CONTROLLER_H
 #define _CLATD_CONTROLLER_H
 
+#include <map>
+
 class NetworkController;
 
 class ClatdController {
@@ -25,12 +27,13 @@ public:
     virtual ~ClatdController();
 
     int startClatd(char *interface);
-    int stopClatd();
-    bool isClatdStarted();
+    int stopClatd(char* interface);
+    bool isClatdStarted(char* interface);
 
 private:
     NetworkController* const mNetCtrl;
-    pid_t mClatdPid;
+    std::map<std::string, pid_t> mClatdPids;
+    pid_t getClatdPid(char* interface);
 };
 
 #endif
index e2d2308..d8c42ca 100644 (file)
@@ -1318,26 +1318,21 @@ CommandListener::ClatdCmd::ClatdCmd() : NetdCommand("clatd") {
 int CommandListener::ClatdCmd::runCommand(SocketClient *cli, int argc,
                                                             char **argv) {
     int rc = 0;
-    if (argc < 2) {
+    if (argc < 3) {
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
         return 0;
     }
 
-    if(!strcmp(argv[1], "stop")) {
-        rc = sClatdCtrl->stopClatd();
+    if (!strcmp(argv[1], "stop")) {
+        rc = sClatdCtrl->stopClatd(argv[2]);
     } else if (!strcmp(argv[1], "status")) {
         char *tmp = NULL;
-
-        asprintf(&tmp, "Clatd status: %s", (sClatdCtrl->isClatdStarted() ?
-                                                        "started" : "stopped"));
+        asprintf(&tmp, "Clatd status: %s", (sClatdCtrl->isClatdStarted(argv[2]) ?
+                                            "started" : "stopped"));
         cli->sendMsg(ResponseCode::ClatdStatusResult, tmp, false);
         free(tmp);
         return 0;
-    } else if(!strcmp(argv[1], "start")) {
-        if (argc < 3) {
-            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
-            return 0;
-        }
+    } else if (!strcmp(argv[1], "start")) {
         rc = sClatdCtrl->startClatd(argv[2]);
     } else {
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown clatd cmd", false);