Support more than one clatd at a time.
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
diff --git a/server/ClatdController.cpp b/server/ClatdController.cpp
index c19e299..b97ea32 100644
--- a/server/ClatdController.cpp
+++ b/server/ClatdController.cpp
@@ -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>
@@ -21,34 +24,43 @@
#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);
+}
- if(mClatdPid != 0) {
- ALOGE("clatd already running");
+int ClatdController::startClatd(char* interface) {
+ pid_t pid = getClatdPid(interface);
+
+ 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 @@
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 @@
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 @@
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
}
diff --git a/server/ClatdController.h b/server/ClatdController.h
index 5bf48d9..1985836 100644
--- a/server/ClatdController.h
+++ b/server/ClatdController.h
@@ -17,6 +17,8 @@
#ifndef _CLATD_CONTROLLER_H
#define _CLATD_CONTROLLER_H
+#include <map>
+
class NetworkController;
class ClatdController {
@@ -25,12 +27,13 @@
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
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index e2d2308..d8c42ca 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -1318,26 +1318,21 @@
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);