resolved conflicts for merge of e36a3a2f to jb-dev-plus-aosp
Change-Id: I566b0e96327f318313c17a11d35539554b075f59
diff --git a/Android.mk b/Android.mk
index c20898b..655038d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -6,8 +6,11 @@
BandwidthController.cpp \
CommandListener.cpp \
DnsProxyListener.cpp \
+ MDnsSdListener.cpp \
+ IdletimerController.cpp \
NatController.cpp \
NetdCommand.cpp \
+ NetdConstants.cpp \
NetlinkHandler.cpp \
NetlinkManager.cpp \
PanController.cpp \
@@ -27,15 +30,17 @@
LOCAL_C_INCLUDES := $(KERNEL_HEADERS) \
$(LOCAL_PATH)/../bluetooth/bluedroid/include \
$(LOCAL_PATH)/../bluetooth/bluez-clean-headers \
+ external/mdnsresponder/mDNSShared \
external/openssl/include \
external/stlport/stlport \
bionic \
+ bionic/libc/private \
$(call include-path-for, libhardware_legacy)/hardware_legacy
-LOCAL_CFLAGS :=
+LOCAL_CFLAGS := -Werror=format
LOCAL_SHARED_LIBRARIES := libstlport libsysutils libcutils libnetutils \
- libcrypto libhardware_legacy
+ libcrypto libhardware_legacy libmdnssd
ifneq ($(BOARD_HOSTAPD_DRIVER),)
LOCAL_CFLAGS += -DHAVE_HOSTAPD
diff --git a/BandwidthController.cpp b/BandwidthController.cpp
index 4c15394..31cdcab 100644
--- a/BandwidthController.cpp
+++ b/BandwidthController.cpp
@@ -41,18 +41,16 @@
#include <cutils/log.h>
#include <cutils/properties.h>
-extern "C" int logwrap(int argc, const char **argv, int background);
+extern "C" int logwrap(int argc, const char **argv);
extern "C" int system_nosh(const char *command);
+#include "NetdConstants.h"
#include "BandwidthController.h"
-#include "oem_iptables_hook.h"
/* Alphabetical */
-const char BandwidthController::ALERT_IPT_TEMPLATE[] = "%s %s %s -m quota2 ! --quota %lld --name %s";
+#define ALERT_IPT_TEMPLATE "%s %s %s -m quota2 ! --quota %lld --name %s"
const int BandwidthController::ALERT_RULE_POS_IN_COSTLY_CHAIN = 4;
const char BandwidthController::ALERT_GLOBAL_NAME[] = "globalAlert";
-const char BandwidthController::IP6TABLES_PATH[] = "/system/bin/ip6tables";
-const char BandwidthController::IPTABLES_PATH[] = "/system/bin/iptables";
const int BandwidthController::MAX_CMD_ARGS = 32;
const int BandwidthController::MAX_CMD_LEN = 1024;
const int BandwidthController::MAX_IFACENAME_LEN = 64;
@@ -64,33 +62,32 @@
* Some comments about the rules:
* * Ordering
* - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
- * E.g. "-I INPUT -i rmnet0 --goto costly"
+ * E.g. "-I bw_INPUT -i rmnet0 --jump costly"
* - quota'd rules in the costly chain should be before penalty_box lookups.
+ * - the qtaguid counting is done at the end of the bw_INPUT/bw_OUTPUT user chains.
*
* * global quota vs per interface quota
* - global quota for all costly interfaces uses a single costly chain:
* . initial rules
* iptables -N costly_shared
- * iptables -I INPUT -i iface0 --goto costly_shared
- * iptables -I OUTPUT -o iface0 --goto costly_shared
+ * iptables -I bw_INPUT -i iface0 --jump costly_shared
+ * iptables -I bw_OUTPUT -o iface0 --jump costly_shared
* iptables -I costly_shared -m quota \! --quota 500000 \
* --jump REJECT --reject-with icmp-net-prohibited
* iptables -A costly_shared --jump penalty_box
- * iptables -A costly_shared -m owner --socket-exists
*
* . adding a new iface to this, E.g.:
- * iptables -I INPUT -i iface1 --goto costly_shared
- * iptables -I OUTPUT -o iface1 --goto costly_shared
+ * iptables -I bw_INPUT -i iface1 --jump costly_shared
+ * iptables -I bw_OUTPUT -o iface1 --jump costly_shared
*
* - quota per interface. This is achieve by having "costly" chains per quota.
* E.g. adding a new costly interface iface0 with its own quota:
* iptables -N costly_iface0
- * iptables -I INPUT -i iface0 --goto costly_iface0
- * iptables -I OUTPUT -o iface0 --goto costly_iface0
+ * iptables -I bw_INPUT -i iface0 --jump costly_iface0
+ * iptables -I bw_OUTPUT -o iface0 --jump costly_iface0
* iptables -A costly_iface0 -m quota \! --quota 500000 \
* --jump REJECT --reject-with icmp-net-prohibited
* iptables -A costly_iface0 --jump penalty_box
- * iptables -A costly_iface0 -m owner --socket-exists
*
* * penalty_box handling:
* - only one penalty_box for all interfaces
@@ -98,58 +95,89 @@
* iptables -A penalty_box -m owner --uid-owner app_3 \
* --jump REJECT --reject-with icmp-net-prohibited
*/
-const char *BandwidthController::IPT_CLEANUP_COMMANDS[] = {
- /* Cleanup rules. */
- "-F",
- "-t raw -F",
- /* TODO: If at some point we need more user chains than here, then we will need
- * a different cleanup approach.
+const char *BandwidthController::IPT_FLUSH_COMMANDS[] = {
+ /*
+ * Cleanup rules.
+ * Should normally include costly_<iface>, but we rely on the way they are setup
+ * to allow coexistance.
*/
- "-X", /* Should normally only be costly_shared, penalty_box, and costly_<iface> */
+ "-F bw_INPUT",
+ "-F bw_OUTPUT",
+ "-F bw_FORWARD",
+ "-F penalty_box",
+ "-F costly_shared",
+
+ "-t raw -F bw_raw_PREROUTING",
+ "-t mangle -F bw_mangle_POSTROUTING",
+};
+
+/* The cleanup commands assume flushing has been done. */
+const char *BandwidthController::IPT_CLEANUP_COMMANDS[] = {
+ /* Delete hooks to custom chains. */
+ "-D INPUT -j bw_INPUT",
+ "-D OUTPUT -j bw_OUTPUT",
+ "-D FORWARD -j bw_FORWARD",
+
+ "-t raw -D bw_raw_PREROUTING",
+ "-t mangle -D bw_mangle_POSTROUTING",
+
+ "-X bw_INPUT",
+ "-X bw_OUTPUT",
+ "-X bw_FORWARD",
+ "-X penalty_box",
+ "-X costly_shared",
+
+ "-t raw -X bw_raw_PREROUTING",
+ "-t mangle -X bw_mangle_POSTROUTING",
};
const char *BandwidthController::IPT_SETUP_COMMANDS[] = {
/* Created needed chains. */
+ "-N bw_INPUT",
+ "-A INPUT -j bw_INPUT",
+
+ "-N bw_OUTPUT",
+ "-A OUTPUT -j bw_OUTPUT",
+
+ "-N bw_FORWARD",
+ "-I FORWARD -j bw_FORWARD",
+
"-N costly_shared",
"-N penalty_box",
+
+ "-t raw -N bw_raw_PREROUTING",
+ "-t raw -A PREROUTING -j bw_raw_PREROUTING",
+ "-t mangle -N bw_mangle_POSTROUTING",
+ "-t mangle -A POSTROUTING -j bw_mangle_POSTROUTING",
};
const char *BandwidthController::IPT_BASIC_ACCOUNTING_COMMANDS[] = {
- "-F INPUT",
- "-A INPUT -i lo --jump ACCEPT",
- "-A INPUT -m owner --socket-exists", /* This is a tracking rule. */
+ "-A bw_INPUT -i lo --jump RETURN",
+ "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
- "-F OUTPUT",
- "-A OUTPUT -o lo --jump ACCEPT",
- "-A OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
+ "-A bw_OUTPUT -o lo --jump RETURN",
+ "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
- "-F costly_shared",
"-A costly_shared --jump penalty_box",
- "-A costly_shared -m owner --socket-exists", /* This is a tracking rule. */
- /* TODO(jpa): Figure out why iptables doesn't correctly return from this
- * chain. For now, hack the chain exit with an ACCEPT.
- */
- "-A costly_shared --jump ACCEPT",
+
+ "-t raw -A bw_raw_PREROUTING ! -i lo+ -m owner --socket-exists", /* This is a tracking rule. */
+ "-t mangle -A bw_mangle_POSTROUTING ! -o lo+ -m owner --socket-exists", /* This is a tracking rule. */
};
BandwidthController::BandwidthController(void) {
char value[PROPERTY_VALUE_MAX];
- property_get("persist.bandwidth.enable", value, "0");
- if (!strcmp(value, "1")) {
- enableBandwidthControl();
- }
-
property_get("persist.bandwidth.uselogwrap", value, "0");
useLogwrapCall = !strcmp(value, "1");
}
-int BandwidthController::runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling) {
+int BandwidthController::runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling,
+ IptFailureLog failureHandling) {
int res = 0;
- LOGV("runIpxtablesCmd(cmd=%s)", cmd);
- res |= runIptablesCmd(cmd, rejectHandling, IptIpV4);
- res |= runIptablesCmd(cmd, rejectHandling, IptIpV6);
+ ALOGV("runIpxtablesCmd(cmd=%s)", cmd);
+ res |= runIptablesCmd(cmd, rejectHandling, IptIpV4, failureHandling);
+ res |= runIptablesCmd(cmd, rejectHandling, IptIpV6, failureHandling);
return res;
}
@@ -161,7 +189,7 @@
}
int BandwidthController::runIptablesCmd(const char *cmd, IptRejectOp rejectHandling,
- IptIpVer iptVer) {
+ IptIpVer iptVer, IptFailureLog failureHandling) {
char buffer[MAX_CMD_LEN];
const char *argv[MAX_CMD_ARGS];
int argc = 0;
@@ -190,7 +218,7 @@
res = system_nosh(fullCmd.c_str());
} else {
if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
- LOGE("iptables command too long");
+ ALOGE("iptables command too long");
return -1;
}
@@ -198,22 +226,45 @@
while ((tmp = strsep(&next, " "))) {
argv[argc++] = tmp;
if (argc >= MAX_CMD_ARGS) {
- LOGE("iptables argument overflow");
+ ALOGE("iptables argument overflow");
return -1;
}
}
argv[argc] = NULL;
- res = logwrap(argc, argv, 0);
+ res = logwrap(argc, argv);
}
- if (res) {
- LOGE("runIptablesCmd(): failed %s res=%d", fullCmd.c_str(), res);
+ if (res && failureHandling == IptFailShow) {
+ ALOGE("runIptablesCmd(): failed %s res=%d", fullCmd.c_str(), res);
}
return res;
}
-int BandwidthController::enableBandwidthControl(void) {
+int BandwidthController::setupIptablesHooks(void) {
+
+ /* Some of the initialCommands are allowed to fail */
+ runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
+ IPT_FLUSH_COMMANDS, RunCmdFailureOk);
+
+ runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
+ IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
+
+ runCommands(sizeof(IPT_SETUP_COMMANDS) / sizeof(char*),
+ IPT_SETUP_COMMANDS, RunCmdFailureBad);
+
+ return 0;
+
+}
+
+int BandwidthController::enableBandwidthControl(bool force) {
int res;
+ char value[PROPERTY_VALUE_MAX];
+
+ if (!force) {
+ property_get("persist.bandwidth.enable", value, "1");
+ if (!strcmp(value, "0"))
+ return 0;
+ }
/* Let's pretend we started from scratch ... */
sharedQuotaIfaces.clear();
@@ -223,39 +274,36 @@
globalAlertTetherCount = 0;
sharedQuotaBytes = sharedAlertBytes = 0;
+ res = runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
+ IPT_FLUSH_COMMANDS, RunCmdFailureOk);
- /* Some of the initialCommands are allowed to fail */
- runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
- IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
- runCommands(sizeof(IPT_SETUP_COMMANDS) / sizeof(char*),
- IPT_SETUP_COMMANDS, RunCmdFailureOk);
- res = runCommands(sizeof(IPT_BASIC_ACCOUNTING_COMMANDS) / sizeof(char*),
+ res |= runCommands(sizeof(IPT_BASIC_ACCOUNTING_COMMANDS) / sizeof(char*),
IPT_BASIC_ACCOUNTING_COMMANDS, RunCmdFailureBad);
- setupOemIptablesHook();
-
return res;
}
int BandwidthController::disableBandwidthControl(void) {
- /* The IPT_CLEANUP_COMMANDS are allowed to fail. */
- runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
- IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
- setupOemIptablesHook();
+ runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
+ IPT_FLUSH_COMMANDS, RunCmdFailureOk);
return 0;
}
int BandwidthController::runCommands(int numCommands, const char *commands[],
RunCmdErrHandling cmdErrHandling) {
int res = 0;
- LOGV("runCommands(): %d commands", numCommands);
+ IptFailureLog failureLogging = IptFailShow;
+ if (cmdErrHandling == RunCmdFailureOk) {
+ failureLogging = IptFailHide;
+ }
+ ALOGV("runCommands(): %d commands", numCommands);
for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
- res = runIpxtablesCmd(commands[cmdNum], IptRejectNoAdd);
- if (res && cmdErrHandling != RunCmdFailureBad)
+ res = runIpxtablesCmd(commands[cmdNum], IptRejectNoAdd, failureLogging);
+ if (res && cmdErrHandling != RunCmdFailureOk)
return res;
}
- return cmdErrHandling == RunCmdFailureBad ? res : 0;
+ return 0;
}
std::string BandwidthController::makeIptablesNaughtyCmd(IptOp op, int uid) {
@@ -296,6 +344,7 @@
IptOp op;
int appUids[numUids];
std::string naughtyCmd;
+ std::list<int /*uid*/>::iterator it;
switch (appOp) {
case NaughtyAppOpAdd:
@@ -306,20 +355,44 @@
op = IptOpDelete;
failLogTemplate = "Failed to delete app uid %d from penalty box.";
break;
+ default:
+ ALOGE("Unexpected app Op %d", appOp);
+ return -1;
}
for (uidNum = 0; uidNum < numUids; uidNum++) {
appUids[uidNum] = atol(appStrUids[uidNum]);
if (appUids[uidNum] == 0) {
- LOGE(failLogTemplate, appUids[uidNum]);
+ ALOGE(failLogTemplate, appUids[uidNum]);
goto fail_parse;
}
}
for (uidNum = 0; uidNum < numUids; uidNum++) {
- naughtyCmd = makeIptablesNaughtyCmd(op, appUids[uidNum]);
+ int uid = appUids[uidNum];
+ for (it = naughtyAppUids.begin(); it != naughtyAppUids.end(); it++) {
+ if (*it == uid)
+ break;
+ }
+ bool found = (it != naughtyAppUids.end());
+
+ if (appOp == NaughtyAppOpRemove) {
+ if (!found) {
+ ALOGE("No such appUid %d to remove", uid);
+ return -1;
+ }
+ naughtyAppUids.erase(it);
+ } else {
+ if (found) {
+ ALOGE("appUid %d exists already", uid);
+ return -1;
+ }
+ naughtyAppUids.push_front(uid);
+ }
+
+ naughtyCmd = makeIptablesNaughtyCmd(op, uid);
if (runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd)) {
- LOGE(failLogTemplate, appUids[uidNum]);
+ ALOGE(failLogTemplate, uid);
goto fail_with_uidNum;
}
}
@@ -338,7 +411,7 @@
char *buff;
const char *opFlag;
- LOGV("makeIptablesQuotaCmd(%d, %lld)", op, quota);
+ ALOGV("makeIptablesQuotaCmd(%d, %lld)", op, quota);
switch (op) {
case IptOpInsert:
@@ -363,7 +436,7 @@
int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
char cmd[MAX_CMD_LEN];
- int res = 0;
+ int res = 0, res1, res2;
int ruleInsertPos = 1;
std::string costString;
const char *costCString;
@@ -374,30 +447,43 @@
costString = "costly_";
costString += ifn;
costCString = costString.c_str();
- snprintf(cmd, sizeof(cmd), "-N %s", costCString);
- res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
- snprintf(cmd, sizeof(cmd), "-A %s -j penalty_box", costCString);
- res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
- snprintf(cmd, sizeof(cmd), "-A %s -m owner --socket-exists", costCString);
- res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
- /* TODO(jpa): Figure out why iptables doesn't correctly return from this
- * chain. For now, hack the chain exit with an ACCEPT.
+ /*
+ * Flush the costly_<iface> is allowed to fail in case it didn't exist.
+ * Creating a new one is allowed to fail in case it existed.
+ * This helps with netd restarts.
*/
- snprintf(cmd, sizeof(cmd), "-A %s --jump ACCEPT", costCString);
+ snprintf(cmd, sizeof(cmd), "-F %s", costCString);
+ res1 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
+ snprintf(cmd, sizeof(cmd), "-N %s", costCString);
+ res2 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
+ res = (res1 && res2) || (!res1 && !res2);
+
+ snprintf(cmd, sizeof(cmd), "-A %s -j penalty_box", costCString);
res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
break;
case QuotaShared:
costCString = "costly_shared";
break;
+ default:
+ ALOGE("Unexpected quotatype %d", quotaType);
+ return -1;
}
if (globalAlertBytes) {
/* The alert rule comes 1st */
ruleInsertPos = 2;
}
- snprintf(cmd, sizeof(cmd), "-I INPUT %d -i %s --goto %s", ruleInsertPos, ifn, costCString);
+
+ snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
+ runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
+
+ snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn, costCString);
res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
- snprintf(cmd, sizeof(cmd), "-I OUTPUT %d -o %s --goto %s", ruleInsertPos, ifn, costCString);
+
+ snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
+ runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
+
+ snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn, costCString);
res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
return res;
}
@@ -417,11 +503,14 @@
case QuotaShared:
costCString = "costly_shared";
break;
+ default:
+ ALOGE("Unexpected quotatype %d", quotaType);
+ return -1;
}
- snprintf(cmd, sizeof(cmd), "-D INPUT -i %s --goto %s", ifn, costCString);
+ snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
- snprintf(cmd, sizeof(cmd), "-D OUTPUT -o %s --goto %s", ifn, costCString);
+ snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
/* The "-N costly_shared" is created upfront, no need to handle it here. */
@@ -446,11 +535,11 @@
if (!maxBytes) {
/* Don't talk about -1, deprecate it. */
- LOGE("Invalid bytes value. 1..max_int64.");
+ ALOGE("Invalid bytes value. 1..max_int64.");
return -1;
}
if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
- LOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
+ ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
return -1;
}
ifaceName = ifn;
@@ -471,7 +560,7 @@
quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
if (res) {
- LOGE("Failed set quota rule");
+ ALOGE("Failed set quota rule");
goto fail;
}
sharedQuotaBytes = maxBytes;
@@ -483,7 +572,7 @@
if (maxBytes != sharedQuotaBytes) {
res |= updateQuota(costName, maxBytes);
if (res) {
- LOGE("Failed update quota for %s", costName);
+ ALOGE("Failed update quota for %s", costName);
goto fail;
}
sharedQuotaBytes = maxBytes;
@@ -510,7 +599,7 @@
const char *costName = "shared";
if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
- LOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
+ ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
return -1;
}
ifaceName = ifn;
@@ -520,7 +609,7 @@
break;
}
if (it == sharedQuotaIfaces.end()) {
- LOGE("No such iface %s to delete", ifn);
+ ALOGE("No such iface %s to delete", ifn);
return -1;
}
@@ -550,7 +639,7 @@
if (!maxBytes) {
/* Don't talk about -1, deprecate it. */
- LOGE("Invalid bytes value. 1..max_int64.");
+ ALOGE("Invalid bytes value. 1..max_int64.");
return -1;
}
if (maxBytes == -1) {
@@ -558,7 +647,7 @@
}
if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
- LOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
+ ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
return -1;
}
ifaceName = ifn;
@@ -575,7 +664,7 @@
quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
if (res) {
- LOGE("Failed set quota rule");
+ ALOGE("Failed set quota rule");
goto fail;
}
@@ -584,7 +673,7 @@
} else {
res |= updateQuota(costName, maxBytes);
if (res) {
- LOGE("Failed update quota for %s", iface);
+ ALOGE("Failed update quota for %s", iface);
goto fail;
}
it->quota = maxBytes;
@@ -615,11 +704,11 @@
fp = fopen(fname, "r");
free(fname);
if (!fp) {
- LOGE("Reading quota %s failed (%s)", costName, strerror(errno));
+ ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
return -1;
}
scanRes = fscanf(fp, "%lld", bytes);
- LOGV("Read quota res=%d bytes=%lld", scanRes, *bytes);
+ ALOGV("Read quota res=%d bytes=%lld", scanRes, *bytes);
fclose(fp);
return scanRes == 1 ? 0 : -1;
}
@@ -633,7 +722,7 @@
std::list<QuotaInfo>::iterator it;
if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
- LOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
+ ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
return -1;
}
ifaceName = ifn;
@@ -645,7 +734,7 @@
}
if (it == quotaIfaces.end()) {
- LOGE("No such iface %s to delete", ifn);
+ ALOGE("No such iface %s to delete", ifn);
return -1;
}
@@ -665,7 +754,7 @@
fp = fopen(fname, "w");
free(fname);
if (!fp) {
- LOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
+ ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
return -1;
}
fprintf(fp, "%lld\n", bytes);
@@ -693,13 +782,13 @@
}
ifaceLimiting = "! -i lo+";
- asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "INPUT",
- bytes, alertName, alertName);
+ asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_INPUT",
+ bytes, alertName);
res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
free(alertQuotaCmd);
ifaceLimiting = "! -o lo+";
- asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "OUTPUT",
- bytes, alertName, alertName);
+ asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_OUTPUT",
+ bytes, alertName);
res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
free(alertQuotaCmd);
return res;
@@ -725,8 +814,8 @@
}
ifaceLimiting = "! -i lo+";
- asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "FORWARD",
- bytes, alertName, alertName);
+ asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_FORWARD",
+ bytes, alertName);
res = runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
free(alertQuotaCmd);
return res;
@@ -737,7 +826,7 @@
int res = 0;
if (!bytes) {
- LOGE("Invalid bytes value. 1..max_int64.");
+ ALOGE("Invalid bytes value. 1..max_int64.");
return -1;
}
if (globalAlertBytes) {
@@ -745,7 +834,7 @@
} else {
res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
if (globalAlertTetherCount) {
- LOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
+ ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
}
}
@@ -758,7 +847,7 @@
int res = 0;
globalAlertTetherCount++;
- LOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
+ ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
/*
* If there is no globalAlert active we are done.
@@ -780,7 +869,7 @@
int res = 0;
if (!globalAlertBytes) {
- LOGE("No prior alert set");
+ ALOGE("No prior alert set");
return -1;
}
res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
@@ -796,7 +885,7 @@
const char *alertName = ALERT_GLOBAL_NAME;
if (!globalAlertTetherCount) {
- LOGE("No prior alert set");
+ ALOGE("No prior alert set");
return -1;
}
@@ -817,11 +906,11 @@
int BandwidthController::setSharedAlert(int64_t bytes) {
if (!sharedQuotaBytes) {
- LOGE("Need to have a prior shared quota set to set an alert");
+ ALOGE("Need to have a prior shared quota set to set an alert");
return -1;
}
if (!bytes) {
- LOGE("Invalid bytes value. 1..max_int64.");
+ ALOGE("Invalid bytes value. 1..max_int64.");
return -1;
}
return setCostlyAlert("shared", bytes, &sharedAlertBytes);
@@ -835,7 +924,7 @@
std::list<QuotaInfo>::iterator it;
if (!bytes) {
- LOGE("Invalid bytes value. 1..max_int64.");
+ ALOGE("Invalid bytes value. 1..max_int64.");
return -1;
}
for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
@@ -844,7 +933,7 @@
}
if (it == quotaIfaces.end()) {
- LOGE("Need to have a prior interface quota set to set an alert");
+ ALOGE("Need to have a prior interface quota set to set an alert");
return -1;
}
@@ -860,7 +949,7 @@
}
if (it == quotaIfaces.end()) {
- LOGE("No prior alert set for interface %s", iface);
+ ALOGE("No prior alert set for interface %s", iface);
return -1;
}
@@ -874,7 +963,7 @@
char *alertName;
if (!bytes) {
- LOGE("Invalid bytes value. 1..max_int64.");
+ ALOGE("Invalid bytes value. 1..max_int64.");
return -1;
}
asprintf(&alertName, "%sAlert", costName);
@@ -882,8 +971,7 @@
res = updateQuota(alertName, *alertBytes);
} else {
asprintf(&chainNameAndPos, "costly_%s %d", costName, ALERT_RULE_POS_IN_COSTLY_CHAIN);
- asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-I", chainNameAndPos, bytes, alertName,
- alertName);
+ asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-I", chainNameAndPos, bytes, alertName);
res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
free(alertQuotaCmd);
free(chainNameAndPos);
@@ -901,12 +989,12 @@
asprintf(&alertName, "%sAlert", costName);
if (!*alertBytes) {
- LOGE("No prior alert set for %s alert", costName);
+ ALOGE("No prior alert set for %s alert", costName);
return -1;
}
asprintf(&chainName, "costly_%s", costName);
- asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-D", chainName, *alertBytes, alertName, alertName);
+ asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-D", chainName, *alertBytes, alertName);
res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
free(alertQuotaCmd);
free(chainName);
@@ -918,14 +1006,15 @@
/*
* Parse the ptks and bytes out of:
- * Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
+ * Chain FORWARD (policy RETURN 0 packets, 0 bytes)
* pkts bytes target prot opt in out source destination
- * 0 0 ACCEPT all -- rmnet0 wlan0 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
+ * 0 0 RETURN all -- rmnet0 wlan0 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
* 0 0 DROP all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0 state INVALID
- * 0 0 ACCEPT all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
+ * 0 0 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
*
*/
-int BandwidthController::parseForwardChainStats(TetherStats &stats, FILE *fp) {
+int BandwidthController::parseForwardChainStats(TetherStats &stats, FILE *fp,
+ std::string &extraProcessingInfo) {
int res;
char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
char iface0[MAX_IPT_OUTPUT_LINE_LEN];
@@ -938,19 +1027,21 @@
while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
/* Clean up, so a failed parse can still print info */
iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
- res = sscanf(buffPtr, "%lld %lld ACCEPT all -- %s %s 0.%s",
+ res = sscanf(buffPtr, "%lld %lld RETURN all -- %s %s 0.%s",
&packets, &bytes, iface0, iface1, rest);
- LOGV("parse res=%d iface0=<%s> iface1=<%s> pkts=%lld bytes=%lld rest=<%s> orig line=<%s>", res,
+ ALOGV("parse res=%d iface0=<%s> iface1=<%s> pkts=%lld bytes=%lld rest=<%s> orig line=<%s>", res,
iface0, iface1, packets, bytes, rest, buffPtr);
+ extraProcessingInfo += buffPtr;
+
if (res != 5) {
continue;
}
if ((stats.ifaceIn == iface0) && (stats.ifaceOut == iface1)) {
- LOGV("iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
+ ALOGV("iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
stats.rxPackets = packets;
stats.rxBytes = bytes;
} else if ((stats.ifaceOut == iface0) && (stats.ifaceIn == iface1)) {
- LOGV("iface_in=%s iface_out=%s tx_bytes=%lld tx_packets=%lld ", iface1, iface0, bytes, packets);
+ ALOGV("iface_in=%s iface_out=%s tx_bytes=%lld tx_packets=%lld ", iface1, iface0, bytes, packets);
stats.txPackets = packets;
stats.txBytes = bytes;
}
@@ -967,14 +1058,14 @@
return msg;
}
-int BandwidthController::getTetherStats(TetherStats &stats) {
+int BandwidthController::getTetherStats(TetherStats &stats, std::string &extraProcessingInfo) {
int res;
std::string fullCmd;
FILE *iptOutput;
const char *cmd;
if (stats.rxBytes != -1 || stats.txBytes != -1) {
- LOGE("Unexpected input stats. Byte counts should be -1.");
+ ALOGE("Unexpected input stats. Byte counts should be -1.");
return -1;
}
@@ -986,13 +1077,14 @@
* the wanted info.
*/
fullCmd = IPTABLES_PATH;
- fullCmd += " -nvx -L FORWARD";
+ fullCmd += " -nvx -L natctrl_FORWARD";
iptOutput = popen(fullCmd.c_str(), "r");
if (!iptOutput) {
- LOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
+ ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
+ extraProcessingInfo += "Failed to run iptables.";
return -1;
}
- res = parseForwardChainStats(stats, iptOutput);
+ res = parseForwardChainStats(stats, iptOutput, extraProcessingInfo);
pclose(iptOutput);
/* Currently NatController doesn't do ipv6 tethering, so we are done. */
diff --git a/BandwidthController.h b/BandwidthController.h
index 861c63e..10e6ca2 100644
--- a/BandwidthController.h
+++ b/BandwidthController.h
@@ -46,7 +46,10 @@
};
BandwidthController();
- int enableBandwidthControl(void);
+
+ int setupIptablesHooks(void);
+
+ int enableBandwidthControl(bool force);
int disableBandwidthControl(void);
int setInterfaceSharedQuota(const char *iface, int64_t bytes);
@@ -75,7 +78,7 @@
* stats should have ifaceIn and ifaceOut initialized.
* Byte counts should be left to the default (-1).
*/
- int getTetherStats(TetherStats &stats);
+ int getTetherStats(TetherStats &stats, std::string &extraProcessingInfo);
protected:
class QuotaInfo {
@@ -93,7 +96,11 @@
enum NaughtyAppOp { NaughtyAppOpAdd, NaughtyAppOpRemove };
enum QuotaType { QuotaUnique, QuotaShared };
enum RunCmdErrHandling { RunCmdFailureBad, RunCmdFailureOk };
-
+#if LOG_NDEBUG
+ enum IptFailureLog { IptFailShow, IptFailHide };
+#else
+ enum IptFailureLog { IptFailShow, IptFailHide = IptFailShow };
+#endif
int maninpulateNaughtyApps(int numUids, char *appStrUids[], NaughtyAppOp appOp);
int prepCostlyIface(const char *ifn, QuotaType quotaType);
@@ -108,8 +115,11 @@
/* Runs for both ipv4 and ipv6 iptables */
int runCommands(int numCommands, const char *commands[], RunCmdErrHandling cmdErrHandling);
/* Runs for both ipv4 and ipv6 iptables, appends -j REJECT --reject-with ... */
- static int runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling);
- static int runIptablesCmd(const char *cmd, IptRejectOp rejectHandling, IptIpVer iptIpVer);
+ static int runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling,
+ IptFailureLog failureHandling = IptFailShow);
+ static int runIptablesCmd(const char *cmd, IptRejectOp rejectHandling, IptIpVer iptIpVer,
+ IptFailureLog failureHandling = IptFailShow);
+
// Provides strncpy() + check overflow.
static int StrncpyAndCheck(char *buffer, const char *src, size_t buffSize);
@@ -122,8 +132,10 @@
/*
* stats should have ifaceIn and ifaceOut initialized.
* fp should be a file to the FORWARD rules of iptables.
+ * extraProcessingInfo: contains raw parsed data, and error info.
*/
- static int parseForwardChainStats(TetherStats &stats, FILE *fp);
+ static int parseForwardChainStats(TetherStats &stats, FILE *fp,
+ std::string &extraProcessingInfo);
/*------------------*/
@@ -145,16 +157,14 @@
std::list<int /*appUid*/> naughtyAppUids;
private:
+ static const char *IPT_FLUSH_COMMANDS[];
static const char *IPT_CLEANUP_COMMANDS[];
static const char *IPT_SETUP_COMMANDS[];
static const char *IPT_BASIC_ACCOUNTING_COMMANDS[];
/* Alphabetical */
- static const char ALERT_IPT_TEMPLATE[];
static const int ALERT_RULE_POS_IN_COSTLY_CHAIN;
static const char ALERT_GLOBAL_NAME[];
- static const char IP6TABLES_PATH[];
- static const char IPTABLES_PATH[];
static const int MAX_CMD_ARGS;
static const int MAX_CMD_LEN;
static const int MAX_IFACENAME_LEN;
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 0fed54b..97e2fa2 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -37,7 +37,9 @@
#include "ResponseCode.h"
#include "ThrottleController.h"
#include "BandwidthController.h"
+#include "IdletimerController.h"
#include "SecondaryTableController.h"
+#include "oem_iptables_hook.h"
TetherController *CommandListener::sTetherCtrl = NULL;
@@ -46,11 +48,12 @@
PanController *CommandListener::sPanCtrl = NULL;
SoftapController *CommandListener::sSoftapCtrl = NULL;
BandwidthController * CommandListener::sBandwidthCtrl = NULL;
+IdletimerController * CommandListener::sIdletimerCtrl = NULL;
ResolverController *CommandListener::sResolverCtrl = NULL;
SecondaryTableController *CommandListener::sSecondaryTableCtrl = NULL;
CommandListener::CommandListener() :
- FrameworkListener("netd") {
+ FrameworkListener("netd", true) {
registerCmd(new InterfaceCmd());
registerCmd(new IpFwdCmd());
registerCmd(new TetherCmd());
@@ -60,6 +63,7 @@
registerCmd(new PanCmd());
registerCmd(new SoftapCmd());
registerCmd(new BandwidthControlCmd());
+ registerCmd(new IdletimerControlCmd());
registerCmd(new ResolverCmd());
if (!sSecondaryTableCtrl)
@@ -76,8 +80,34 @@
sSoftapCtrl = new SoftapController();
if (!sBandwidthCtrl)
sBandwidthCtrl = new BandwidthController();
+ if (!sIdletimerCtrl)
+ sIdletimerCtrl = new IdletimerController();
if (!sResolverCtrl)
sResolverCtrl = new ResolverController();
+
+ /*
+ * This is the only time controllers are allowed to touch
+ * top-level chains in iptables.
+ * Each controller should setup custom chains and hook them into
+ * the top-level ones.
+ * THE ORDER IS IMPORTANT. TRIPPLE CHECK EACH setup function.
+ */
+ /* Does DROP in nat: PREROUTING, FORWARD, OUTPUT */
+ setupOemIptablesHook();
+ /* Does DROPs in FORWARD by default */
+ sNatCtrl->setupIptablesHooks();
+ /*
+ * Does REJECT in INPUT, OUTPUT. Does counting also.
+ * No DROP/REJECT allowed later in netfilter-flow hook order.
+ */
+ sBandwidthCtrl->setupIptablesHooks();
+ /*
+ * Counts in nat: PREROUTING, POSTROUTING.
+ * No DROP/REJECT allowed later in netfilter-flow hook order.
+ */
+ sIdletimerCtrl->setupIptablesHooks();
+
+ sBandwidthCtrl->enableBandwidthControl(false);
}
CommandListener::InterfaceCmd::InterfaceCmd() :
@@ -87,12 +117,12 @@
int CommandListener::writeFile(const char *path, const char *value, int size) {
int fd = open(path, O_WRONLY);
if (fd < 0) {
- LOGE("Failed to open %s: %s", path, strerror(errno));
+ ALOGE("Failed to open %s: %s", path, strerror(errno));
return -1;
}
if (write(fd, value, size) != size) {
- LOGE("Failed to write %s: %s", path, strerror(errno));
+ ALOGE("Failed to write %s: %s", path, strerror(errno));
close(fd);
return -1;
}
@@ -274,7 +304,7 @@
}
if (ifc_get_hwaddr(argv[2], (void *) hwaddr)) {
- LOGW("Failed to retrieve HW addr for %s (%s)", argv[2], strerror(errno));
+ ALOGW("Failed to retrieve HW addr for %s (%s)", argv[2], strerror(errno));
}
char *addr_s = strdup(inet_ntoa(addr));
@@ -289,7 +319,7 @@
char *flag_s;
- asprintf(&flag_s, "[%s%s%s%s%s%s]", updown, brdcst, loopbk, ppp, running, multi);
+ asprintf(&flag_s, "%s%s%s%s%s%s", updown, brdcst, loopbk, ppp, running, multi);
char *msg = NULL;
asprintf(&msg, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %d %s",
@@ -305,12 +335,12 @@
ifc_close();
return 0;
} else if (!strcmp(argv[1], "setcfg")) {
- // arglist: iface addr prefixLength [flags]
+ // arglist: iface addr prefixLength flags
if (argc < 5) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
return 0;
}
- LOGD("Setting iface cfg");
+ ALOGD("Setting iface cfg");
struct in_addr addr;
unsigned flags = 0;
@@ -335,43 +365,34 @@
}
/* Process flags */
- /* read from "[XX" arg to "YY]" arg */
- bool bStarted = false;
for (int i = 5; i < argc; i++) {
char *flag = argv[i];
- if (!bStarted) {
- if (*flag == '[') {
- flag++;
- bStarted = true;
- } else {
- continue;
- }
- }
- int len = strlen(flag);
- if (flag[len-1] == ']') {
- i = argc; // stop after this loop
- flag[len-1] = 0;
- }
if (!strcmp(flag, "up")) {
- LOGD("Trying to bring up %s", argv[2]);
+ ALOGD("Trying to bring up %s", argv[2]);
if (ifc_up(argv[2])) {
- LOGE("Error upping interface");
+ ALOGE("Error upping interface");
cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true);
ifc_close();
return 0;
}
} else if (!strcmp(flag, "down")) {
- LOGD("Trying to bring down %s", argv[2]);
+ ALOGD("Trying to bring down %s", argv[2]);
if (ifc_down(argv[2])) {
- LOGE("Error downing interface");
+ ALOGE("Error downing interface");
cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true);
ifc_close();
return 0;
}
} else if (!strcmp(flag, "broadcast")) {
- LOGD("broadcast flag ignored");
+ // currently ignored
} else if (!strcmp(flag, "multicast")) {
- LOGD("multicast flag ignored");
+ // currently ignored
+ } else if (!strcmp(flag, "running")) {
+ // currently ignored
+ } else if (!strcmp(flag, "loopback")) {
+ // currently ignored
+ } else if (!strcmp(flag, "point-to-point")) {
+ // currently ignored
} else {
cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false);
ifc_close();
@@ -384,7 +405,7 @@
return 0;
} else if (!strcmp(argv[1], "clearaddrs")) {
// arglist: iface
- LOGD("Clearing all IP addresses on %s", argv[2]);
+ ALOGD("Clearing all IP addresses on %s", argv[2]);
ifc_clear_addresses(argv[2]);
@@ -847,7 +868,7 @@
int CommandListener::readInterfaceCounters(const char *iface, unsigned long *rx, unsigned long *tx) {
FILE *fp = fopen("/proc/net/dev", "r");
if (!fp) {
- LOGE("Failed to open /proc/net/dev (%s)", strerror(errno));
+ ALOGE("Failed to open /proc/net/dev (%s)", strerror(errno));
return -1;
}
@@ -914,10 +935,10 @@
return 0;
}
- LOGV("bwctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
+ ALOGV("bwctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
if (!strcmp(argv[1], "enable")) {
- int rc = sBandwidthCtrl->enableBandwidthControl();
+ int rc = sBandwidthCtrl->enableBandwidthControl(true);
sendGenericOkFail(cli, rc);
return 0;
@@ -1154,6 +1175,7 @@
}
if (!strcmp(argv[1], "gettetherstats") || !strcmp(argv[1], "gts")) {
BandwidthController::TetherStats tetherStats;
+ std::string extraProcessingInfo = "";
if (argc != 4) {
sendGenericSyntaxError(cli, "gettetherstats <interface0> <interface1>");
return 0;
@@ -1161,9 +1183,10 @@
tetherStats.ifaceIn = argv[2];
tetherStats.ifaceOut = argv[3];
- int rc = sBandwidthCtrl->getTetherStats(tetherStats);
+ int rc = sBandwidthCtrl->getTetherStats(tetherStats, extraProcessingInfo);
if (rc) {
- sendGenericOpFailed(cli, "Failed to get tethering stats");
+ extraProcessingInfo.insert(0, "Failed to get tethering stats.\n");
+ sendGenericOpFailed(cli, extraProcessingInfo.c_str());
return 0;
}
@@ -1177,3 +1200,63 @@
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown bandwidth cmd", false);
return 0;
}
+
+CommandListener::IdletimerControlCmd::IdletimerControlCmd() :
+ NetdCommand("idletimer") {
+}
+
+int CommandListener::IdletimerControlCmd::runCommand(SocketClient *cli, int argc, char **argv) {
+ // TODO(ashish): Change the error statements
+ if (argc < 2) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+ return 0;
+ }
+
+ ALOGV("idletimerctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
+
+ if (!strcmp(argv[1], "enable")) {
+ if (0 != sIdletimerCtrl->enableIdletimerControl()) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+ } else {
+ cli->sendMsg(ResponseCode::CommandOkay, "Enable success", false);
+ }
+ return 0;
+
+ }
+ if (!strcmp(argv[1], "disable")) {
+ if (0 != sIdletimerCtrl->disableIdletimerControl()) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+ } else {
+ cli->sendMsg(ResponseCode::CommandOkay, "Disable success", false);
+ }
+ return 0;
+ }
+ if (!strcmp(argv[1], "add")) {
+ if (argc != 4) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+ return 0;
+ }
+ if(0 != sIdletimerCtrl->addInterfaceIdletimer(argv[2], atoi(argv[3]))) {
+ cli->sendMsg(ResponseCode::OperationFailed, "Failed to add interface", false);
+ } else {
+ cli->sendMsg(ResponseCode::CommandOkay, "Add success", false);
+ }
+ return 0;
+ }
+ if (!strcmp(argv[1], "remove")) {
+ if (argc != 4) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+ return 0;
+ }
+ // ashish: fixme timeout
+ if (0 != sIdletimerCtrl->removeInterfaceIdletimer(argv[2], atoi(argv[3]))) {
+ cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove interface", false);
+ } else {
+ cli->sendMsg(ResponseCode::CommandOkay, "Remove success", false);
+ }
+ return 0;
+ }
+
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown idletimer cmd", false);
+ return 0;
+}
diff --git a/CommandListener.h b/CommandListener.h
index 0ed600b..a9da6d7 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -26,6 +26,7 @@
#include "PanController.h"
#include "SoftapController.h"
#include "BandwidthController.h"
+#include "IdletimerController.h"
#include "ResolverController.h"
#include "SecondaryTableController.h"
@@ -36,6 +37,7 @@
static PanController *sPanCtrl;
static SoftapController *sSoftapCtrl;
static BandwidthController *sBandwidthCtrl;
+ static IdletimerController *sIdletimerCtrl;
static ResolverController *sResolverCtrl;
static SecondaryTableController *sSecondaryTableCtrl;
@@ -116,6 +118,13 @@
void sendGenericSyntaxError(SocketClient *cli, const char *usageMsg);
};
+ class IdletimerControlCmd : public NetdCommand {
+ public:
+ IdletimerControlCmd();
+ virtual ~IdletimerControlCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
class ResolverCmd : public NetdCommand {
public:
ResolverCmd();
diff --git a/DnsProxyListener.cpp b/DnsProxyListener.cpp
index bcb961e..6c09e69 100644
--- a/DnsProxyListener.cpp
+++ b/DnsProxyListener.cpp
@@ -32,6 +32,7 @@
#include <sysutils/SocketClient.h>
#include "DnsProxyListener.h"
+#include "ResponseCode.h"
DnsProxyListener::DnsProxyListener() :
FrameworkListener("dnsproxyd") {
@@ -68,13 +69,16 @@
void DnsProxyListener::GetAddrInfoHandler::run() {
if (DBG) {
- LOGD("GetAddrInfoHandler, now for %s / %s", mHost, mService);
+ ALOGD("GetAddrInfoHandler, now for %s / %s", mHost, mService);
}
struct addrinfo* result = NULL;
- int rv = getaddrinfo(mHost, mService, mHints, &result);
- bool success = (mClient->sendData(&rv, sizeof(rv)) == 0);
- if (rv == 0) {
+ uint32_t rv = getaddrinfo(mHost, mService, mHints, &result);
+ if (rv) {
+ // getaddrinfo failed
+ mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, &rv, sizeof(rv));
+ } else {
+ bool success = !mClient->sendCode(ResponseCode::DnsProxyQueryResult);
struct addrinfo* ai = result;
while (ai && success) {
success = sendLenAndData(mClient, sizeof(struct addrinfo), ai)
@@ -85,13 +89,13 @@
ai = ai->ai_next;
}
success = success && sendLenAndData(mClient, 0, "");
+ if (!success) {
+ ALOGW("Error writing DNS result to client");
+ }
}
if (result) {
freeaddrinfo(result);
}
- if (!success) {
- LOGW("Error writing DNS result to client");
- }
mClient->decRef();
}
@@ -103,12 +107,15 @@
int argc, char **argv) {
if (DBG) {
for (int i = 0; i < argc; i++) {
- LOGD("argv[%i]=%s", i, argv[i]);
+ ALOGD("argv[%i]=%s", i, argv[i]);
}
}
if (argc != 7) {
- LOGW("Invalid number of arguments to getaddrinfo: %i", argc);
- sendLenAndData(cli, 0, NULL);
+ char* msg = NULL;
+ asprintf( &msg, "Invalid number of arguments to getaddrinfo: %i", argc);
+ ALOGW("%s", msg);
+ cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
+ free(msg);
return -1;
}
@@ -141,7 +148,7 @@
}
if (DBG) {
- LOGD("GetAddrInfoHandler for %s / %s",
+ ALOGD("GetAddrInfoHandler for %s / %s",
name ? name : "[nullhost]",
service ? service : "[nullservice]");
}
@@ -165,12 +172,16 @@
int argc, char **argv) {
if (DBG) {
for (int i = 0; i < argc; i++) {
- LOGD("argv[%i]=%s", i, argv[i]);
+ ALOGD("argv[%i]=%s", i, argv[i]);
}
}
+
if (argc != 4) {
- LOGW("Invalid number of arguments to gethostbyaddr: %i", argc);
- sendLenAndData(cli, 0, NULL);
+ char* msg = NULL;
+ asprintf(&msg, "Invalid number of arguments to gethostbyaddr: %i", argc);
+ ALOGW("%s", msg);
+ cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
+ free(msg);
return -1;
}
@@ -182,9 +193,12 @@
errno = 0;
int result = inet_pton(addrFamily, addrStr, addr);
if (result <= 0) {
- LOGW("inet_pton(\"%s\") failed %s", addrStr, strerror(errno));
+ char* msg = NULL;
+ asprintf(&msg, "inet_pton(\"%s\") failed %s", addrStr, strerror(errno));
+ ALOGW("%s", msg);
+ cli->sendMsg(ResponseCode::OperationFailed, msg, false);
free(addr);
- sendLenAndData(cli, 0, NULL);
+ free(msg);
return -1;
}
@@ -215,7 +229,7 @@
void DnsProxyListener::GetHostByAddrHandler::run() {
if (DBG) {
- LOGD("DnsProxyListener::GetHostByAddrHandler::run\n");
+ ALOGD("DnsProxyListener::GetHostByAddrHandler::run\n");
}
struct hostent* hp;
@@ -224,17 +238,25 @@
hp = gethostbyaddr((char*)mAddress, mAddressLen, mAddressFamily);
if (DBG) {
- LOGD("GetHostByAddrHandler::run gethostbyaddr errno: %s hp->h_name = %s, name_len = %d\n",
+ ALOGD("GetHostByAddrHandler::run gethostbyaddr errno: %s hp->h_name = %s, name_len = %d\n",
hp ? "success" : strerror(errno),
(hp && hp->h_name) ? hp->h_name: "null",
(hp && hp->h_name) ? strlen(hp->h_name)+ 1 : 0);
}
- bool success = sendLenAndData(mClient, (hp && hp->h_name) ? strlen(hp->h_name)+ 1 : 0,
- (hp && hp->h_name) ? hp->h_name : "");
+ bool failed = true;
+ if (hp) {
+ failed = mClient->sendBinaryMsg(ResponseCode::DnsProxyQueryResult,
+ hp->h_name ? hp->h_name : "",
+ hp->h_name ? strlen(hp->h_name)+ 1 : 0);
+ } else {
+ uint32_t error = h_errno;
+ failed = mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed,
+ &error, sizeof(error));
+ }
- if (!success) {
- LOGW("GetHostByAddrHandler: Error writing DNS result to client\n");
+ if (failed) {
+ ALOGW("GetHostByAddrHandler: Error writing DNS result to client\n");
}
mClient->decRef();
}
diff --git a/IdletimerController.cpp b/IdletimerController.cpp
new file mode 100644
index 0000000..efe4f09
--- /dev/null
+++ b/IdletimerController.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+// #define LOG_NDEBUG 0
+
+/*
+ * MODUS OPERANDI
+ * --------------
+ *
+ * IPTABLES command sequence:
+ *
+ * iptables -F
+ *
+ * iptables -t nat -F idletimer_PREROUTING
+ * iptables -t nat -F idletimer_POSTROUTING
+ *
+ *
+ * iptables -t nat -N idletimer_PREROUTING
+ * iptables -t nat -N idletimer_POSTROUTING
+ *
+ * iptables -t nat -D PREROUTING -j idletimer_PREROUTING
+ * iptables -t nat -D POSTROUTING -j idletimer_POSTROUTING
+ *
+ *
+ * iptables -t nat -I PREROUTING -j idletimer_PREROUTING
+ * iptables -t nat -I POSTROUTING -j idletimer_POSTROUTING
+ *
+ * # For notifications to work the lable name must match the name of a valid interface.
+ * # If the label name does match an interface, the rules will be a no-op.
+ *
+ * iptables -t nat -A idletimer_PREROUTING -i rmnet0 -j IDLETIMER --timeout 5 --label test-chain --send_nl_msg 1
+ * iptables -t nat -A idletimer_POSTROUTING -o rmnet0 -j IDLETIMER --timeout 5 --label test-chain --send_nl_msg 1
+ *
+ * iptables -nxvL -t nat
+ *
+ * =================
+ *
+ * ndc command sequence
+ * ------------------
+ * ndc idletimer enable
+ * ndc idletimer add <iface> <timeout>
+ * ndc idletimer remove <iface> <timeout>
+ *
+ * Monitor effect on the iptables chains after each step using:
+ * iptables -nxvL -t nat
+ *
+ * Remember that the timeout value has to be same at the time of the
+ * removal.
+ *
+ * Note that currently if the name of the iface is incorrect, iptables
+ * will setup rules without checking if it is the name of a valid
+ * interface (although no notifications will ever be received). It is
+ * the responsibility of code in Java land to ensure that the interface name
+ * is correct. The benefit of this, is that idletimers can be setup on
+ * interfaces than come and go.
+ *
+ * A remove should be called for each add command issued during cleanup, as duplicate
+ * entries of the rule may exist and will all have to removed.
+ *
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <cutils/properties.h>
+
+#define LOG_TAG "IdletimerController"
+#include <cutils/log.h>
+
+#include "IdletimerController.h"
+#include "NetdConstants.h"
+
+extern "C" int system_nosh(const char *command);
+
+IdletimerController::IdletimerController() {
+}
+
+IdletimerController::~IdletimerController() {
+}
+/* return 0 or non-zero */
+int IdletimerController::runIpxtablesCmd(const char *cmd) {
+ char *buffer;
+ size_t len = strnlen(cmd, 255);
+ int res;
+
+ if (len == 255) {
+ ALOGE("command too long");
+ return -1;
+ }
+
+ asprintf(&buffer, "%s %s", IPTABLES_PATH, cmd);
+ res = system_nosh(buffer);
+ ALOGV("%s #%d", buffer, res);
+ free(buffer);
+
+ return res;
+}
+
+bool IdletimerController::setupIptablesHooks() {
+ runIpxtablesCmd("-t nat -D PREROUTING -j idletimer_nat_PREROUTING");
+ runIpxtablesCmd("-t nat -F idletimer_nat_PREROUTING");
+ runIpxtablesCmd("-t nat -N idletimer_nat_PREROUTING");
+
+ runIpxtablesCmd("-t nat -D POSTROUTING -j idletimer_nat_POSTROUTING");
+ runIpxtablesCmd("-t nat -F idletimer_nat_POSTROUTING");
+ runIpxtablesCmd("-t nat -N idletimer_nat_POSTROUTING");
+
+ if (runIpxtablesCmd("-t nat -I PREROUTING -j idletimer_nat_PREROUTING")
+ || runIpxtablesCmd("-t nat -I POSTROUTING -j idletimer_nat_POSTROUTING")) {
+ return false;
+ }
+ return true;
+}
+
+int IdletimerController::setDefaults() {
+ if (runIpxtablesCmd("-t nat -F idletimer_nat_PREROUTING")
+ || runIpxtablesCmd("-t nat -F idletimer_nat_POSTROUTING") )
+ return -1;
+ return 0;
+}
+
+int IdletimerController::enableIdletimerControl() {
+ int res = setDefaults();
+ return res;
+}
+
+int IdletimerController::disableIdletimerControl() {
+ int res = setDefaults();
+ return res;
+}
+
+int IdletimerController::modifyInterfaceIdletimer(IptOp op, const char *iface,
+ uint32_t timeout) {
+ int res;
+ char *buffer;
+ asprintf(&buffer, "-t nat -%c idletimer_nat_PREROUTING -i %s -j IDLETIMER"
+ " --timeout %u --label %s --send_nl_msg 1",
+ (op == IptOpAdd) ? 'A' : 'D', iface, timeout, iface);
+ res = runIpxtablesCmd(buffer);
+ free(buffer);
+
+ asprintf(&buffer, "-t nat -%c idletimer_nat_POSTROUTING -o %s -j IDLETIMER"
+ " --timeout %u --label %s --send_nl_msg 1",
+ (op == IptOpAdd) ? 'A' : 'D', iface, timeout, iface);
+ res |= runIpxtablesCmd(buffer);
+ free(buffer);
+
+ return res;
+}
+
+int IdletimerController::addInterfaceIdletimer(const char *iface, uint32_t timeout) {
+ return modifyInterfaceIdletimer(IptOpAdd, iface, timeout);
+}
+
+int IdletimerController::removeInterfaceIdletimer(const char *iface, uint32_t timeout) {
+ return modifyInterfaceIdletimer(IptOpDelete, iface, timeout);
+}
diff --git a/IdletimerController.h b/IdletimerController.h
new file mode 100644
index 0000000..a55f7af
--- /dev/null
+++ b/IdletimerController.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+#ifndef _IDLETIMER_CONTROLLER_H
+#define _IDLETIMER_CONTROLLER_H
+
+class IdletimerController {
+public:
+
+ IdletimerController();
+ virtual ~IdletimerController();
+
+ int enableIdletimerControl();
+ int disableIdletimerControl();
+ int addInterfaceIdletimer(const char *iface, uint32_t timeout);
+ int removeInterfaceIdletimer(const char *iface, uint32_t timeout);
+ bool setupIptablesHooks();
+
+ private:
+ enum IptOp { IptOpAdd, IptOpDelete };
+ int setDefaults();
+ int runIpxtablesCmd(const char *cmd);
+ int modifyInterfaceIdletimer(IptOp op, const char *iface, uint32_t timeout);
+};
+
+#endif
diff --git a/List.h b/List.h
new file mode 100644
index 0000000..856ce26
--- /dev/null
+++ b/List.h
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Templated list class. Normally we'd use STL, but we don't have that.
+// This class mimics STL's interfaces.
+//
+// Objects are copied into the list with the '=' operator or with copy-
+// construction, so if the compiler's auto-generated versions won't work for
+// you, define your own.
+//
+// The only class you want to use from here is "List".
+//
+#ifndef _NETD_LIST_H
+#define _NETD_LIST_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace android {
+namespace netd {
+
+/*
+ * Doubly-linked list. Instantiate with "List<MyClass> myList".
+ *
+ * Objects added to the list are copied using the assignment operator,
+ * so this must be defined.
+ */
+template<typename T>
+class List
+{
+protected:
+ /*
+ * One element in the list.
+ */
+ class _Node {
+ public:
+ explicit _Node(const T& val) : mVal(val) {}
+ ~_Node() {}
+ inline T& getRef() { return mVal; }
+ inline const T& getRef() const { return mVal; }
+ inline _Node* getPrev() const { return mpPrev; }
+ inline _Node* getNext() const { return mpNext; }
+ inline void setVal(const T& val) { mVal = val; }
+ inline void setPrev(_Node* ptr) { mpPrev = ptr; }
+ inline void setNext(_Node* ptr) { mpNext = ptr; }
+ private:
+ friend class List;
+ friend class _ListIterator;
+ T mVal;
+ _Node* mpPrev;
+ _Node* mpNext;
+ };
+
+ /*
+ * Iterator for walking through the list.
+ */
+
+ template <typename TYPE>
+ struct CONST_ITERATOR {
+ typedef _Node const * NodePtr;
+ typedef const TYPE Type;
+ };
+
+ template <typename TYPE>
+ struct NON_CONST_ITERATOR {
+ typedef _Node* NodePtr;
+ typedef TYPE Type;
+ };
+
+ template<
+ typename U,
+ template <class> class Constness
+ >
+ class _ListIterator {
+ typedef _ListIterator<U, Constness> _Iter;
+ typedef typename Constness<U>::NodePtr _NodePtr;
+ typedef typename Constness<U>::Type _Type;
+
+ explicit _ListIterator(_NodePtr ptr) : mpNode(ptr) {}
+
+ public:
+ _ListIterator() {}
+ _ListIterator(const _Iter& rhs) : mpNode(rhs.mpNode) {}
+ ~_ListIterator() {}
+
+ // this will handle conversions from iterator to const_iterator
+ // (and also all convertible iterators)
+ // Here, in this implementation, the iterators can be converted
+ // if the nodes can be converted
+ template<typename V> explicit
+ _ListIterator(const V& rhs) : mpNode(rhs.mpNode) {}
+
+
+ /*
+ * Dereference operator. Used to get at the juicy insides.
+ */
+ _Type& operator*() const { return mpNode->getRef(); }
+ _Type* operator->() const { return &(mpNode->getRef()); }
+
+ /*
+ * Iterator comparison.
+ */
+ inline bool operator==(const _Iter& right) const {
+ return mpNode == right.mpNode; }
+
+ inline bool operator!=(const _Iter& right) const {
+ return mpNode != right.mpNode; }
+
+ /*
+ * handle comparisons between iterator and const_iterator
+ */
+ template<typename OTHER>
+ inline bool operator==(const OTHER& right) const {
+ return mpNode == right.mpNode; }
+
+ template<typename OTHER>
+ inline bool operator!=(const OTHER& right) const {
+ return mpNode != right.mpNode; }
+
+ /*
+ * Incr/decr, used to move through the list.
+ */
+ inline _Iter& operator++() { // pre-increment
+ mpNode = mpNode->getNext();
+ return *this;
+ }
+ const _Iter operator++(int) { // post-increment
+ _Iter tmp(*this);
+ mpNode = mpNode->getNext();
+ return tmp;
+ }
+ inline _Iter& operator--() { // pre-increment
+ mpNode = mpNode->getPrev();
+ return *this;
+ }
+ const _Iter operator--(int) { // post-increment
+ _Iter tmp(*this);
+ mpNode = mpNode->getPrev();
+ return tmp;
+ }
+
+ inline _NodePtr getNode() const { return mpNode; }
+
+ _NodePtr mpNode; /* should be private, but older gcc fails */
+ private:
+ friend class List;
+ };
+
+public:
+ List() {
+ prep();
+ }
+ List(const List<T>& src) { // copy-constructor
+ prep();
+ insert(begin(), src.begin(), src.end());
+ }
+ virtual ~List() {
+ clear();
+ delete[] (unsigned char*) mpMiddle;
+ }
+
+ typedef _ListIterator<T, NON_CONST_ITERATOR> iterator;
+ typedef _ListIterator<T, CONST_ITERATOR> const_iterator;
+
+ List<T>& operator=(const List<T>& right);
+
+ /* returns true if the list is empty */
+ inline bool empty() const { return mpMiddle->getNext() == mpMiddle; }
+
+ /* return #of elements in list */
+ size_t size() const {
+ return size_t(distance(begin(), end()));
+ }
+
+ /*
+ * Return the first element or one past the last element. The
+ * _Node* we're returning is converted to an "iterator" by a
+ * constructor in _ListIterator.
+ */
+ inline iterator begin() {
+ return iterator(mpMiddle->getNext());
+ }
+ inline const_iterator begin() const {
+ return const_iterator(const_cast<_Node const*>(mpMiddle->getNext()));
+ }
+ inline iterator end() {
+ return iterator(mpMiddle);
+ }
+ inline const_iterator end() const {
+ return const_iterator(const_cast<_Node const*>(mpMiddle));
+ }
+
+ /* add the object to the head or tail of the list */
+ void push_front(const T& val) { insert(begin(), val); }
+ void push_back(const T& val) { insert(end(), val); }
+
+ /* insert before the current node; returns iterator at new node */
+ iterator insert(iterator posn, const T& val)
+ {
+ _Node* newNode = new _Node(val); // alloc & copy-construct
+ newNode->setNext(posn.getNode());
+ newNode->setPrev(posn.getNode()->getPrev());
+ posn.getNode()->getPrev()->setNext(newNode);
+ posn.getNode()->setPrev(newNode);
+ return iterator(newNode);
+ }
+
+ /* insert a range of elements before the current node */
+ void insert(iterator posn, const_iterator first, const_iterator last) {
+ for ( ; first != last; ++first)
+ insert(posn, *first);
+ }
+
+ /* remove one entry; returns iterator at next node */
+ iterator erase(iterator posn) {
+ _Node* pNext = posn.getNode()->getNext();
+ _Node* pPrev = posn.getNode()->getPrev();
+ pPrev->setNext(pNext);
+ pNext->setPrev(pPrev);
+ delete posn.getNode();
+ return iterator(pNext);
+ }
+
+ /* remove a range of elements */
+ iterator erase(iterator first, iterator last) {
+ while (first != last)
+ erase(first++); // don't erase than incr later!
+ return iterator(last);
+ }
+
+ /* remove all contents of the list */
+ void clear() {
+ _Node* pCurrent = mpMiddle->getNext();
+ _Node* pNext;
+
+ while (pCurrent != mpMiddle) {
+ pNext = pCurrent->getNext();
+ delete pCurrent;
+ pCurrent = pNext;
+ }
+ mpMiddle->setPrev(mpMiddle);
+ mpMiddle->setNext(mpMiddle);
+ }
+
+ /*
+ * Measure the distance between two iterators. On exist, "first"
+ * will be equal to "last". The iterators must refer to the same
+ * list.
+ *
+ * FIXME: This is actually a generic iterator function. It should be a
+ * template function at the top-level with specializations for things like
+ * vector<>, which can just do pointer math). Here we limit it to
+ * _ListIterator of the same type but different constness.
+ */
+ template<
+ typename U,
+ template <class> class CL,
+ template <class> class CR
+ >
+ ptrdiff_t distance(
+ _ListIterator<U, CL> first, _ListIterator<U, CR> last) const
+ {
+ ptrdiff_t count = 0;
+ while (first != last) {
+ ++first;
+ ++count;
+ }
+ return count;
+ }
+
+private:
+ /*
+ * I want a _Node but don't need it to hold valid data. More
+ * to the point, I don't want T's constructor to fire, since it
+ * might have side-effects or require arguments. So, we do this
+ * slightly uncouth storage alloc.
+ */
+ void prep() {
+ mpMiddle = (_Node*) new unsigned char[sizeof(_Node)];
+ mpMiddle->setPrev(mpMiddle);
+ mpMiddle->setNext(mpMiddle);
+ }
+
+ /*
+ * This node plays the role of "pointer to head" and "pointer to tail".
+ * It sits in the middle of a circular list of nodes. The iterator
+ * runs around the circle until it encounters this one.
+ */
+ _Node* mpMiddle;
+};
+
+/*
+ * Assignment operator.
+ *
+ * The simplest way to do this would be to clear out the target list and
+ * fill it with the source. However, we can speed things along by
+ * re-using existing elements.
+ */
+template<class T>
+List<T>& List<T>::operator=(const List<T>& right)
+{
+ if (this == &right)
+ return *this; // self-assignment
+ iterator firstDst = begin();
+ iterator lastDst = end();
+ const_iterator firstSrc = right.begin();
+ const_iterator lastSrc = right.end();
+ while (firstSrc != lastSrc && firstDst != lastDst)
+ *firstDst++ = *firstSrc++;
+ if (firstSrc == lastSrc) // ran out of elements in source?
+ erase(firstDst, lastDst); // yes, erase any extras
+ else
+ insert(lastDst, firstSrc, lastSrc); // copy remaining over
+ return *this;
+}
+
+}; // namespace netd
+}; // namespace android
+
+#endif // _NETD_LIST_H
diff --git a/MDnsSdListener.cpp b/MDnsSdListener.cpp
new file mode 100644
index 0000000..52703df
--- /dev/null
+++ b/MDnsSdListener.cpp
@@ -0,0 +1,732 @@
+/*
+ * Copyright (C) 2010 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 <arpa/inet.h>
+#include <dirent.h>
+#include <errno.h>
+#include <linux/if.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <string.h>
+
+#define LOG_TAG "MDnsDS"
+#define DBG 1
+#define VDBG 1
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <sysutils/SocketClient.h>
+
+#include "MDnsSdListener.h"
+#include "ResponseCode.h"
+
+#define MDNS_SERVICE_NAME "mdnsd"
+#define MDNS_SERVICE_STATUS "init.svc.mdnsd"
+
+MDnsSdListener::MDnsSdListener() :
+ FrameworkListener("mdns", true) {
+ Monitor *m = new Monitor();
+ registerCmd(new Handler(m, this));
+}
+
+MDnsSdListener::Handler::Handler(Monitor *m, MDnsSdListener *listener) :
+ NetdCommand("mdnssd") {
+ if (DBG) ALOGD("MDnsSdListener::Hander starting up");
+ mMonitor = m;
+ mListener = listener;
+}
+
+MDnsSdListener::Handler::~Handler() {}
+
+void MDnsSdListener::Handler::discover(SocketClient *cli,
+ const char *iface,
+ const char *regType,
+ const char *domain,
+ const int requestId,
+ const int requestFlags) {
+ if (VDBG) {
+ ALOGD("discover(%s, %s, %s, %d, %d)", iface, regType, domain, requestId,
+ requestFlags);
+ }
+ Context *context = new Context(requestId, mListener);
+ DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
+ if (ref == NULL) {
+ ALOGE("requestId %d already in use during discover call", requestId);
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "RequestId already in use during discover call", false);
+ return;
+ }
+ if (VDBG) ALOGD("using ref %p", ref);
+ DNSServiceFlags nativeFlags = iToFlags(requestFlags);
+ int interfaceInt = ifaceNameToI(iface);
+
+ DNSServiceErrorType result = DNSServiceBrowse(ref, nativeFlags, interfaceInt, regType,
+ domain, &MDnsSdListenerDiscoverCallback, context);
+ if (result != kDNSServiceErr_NoError) {
+ ALOGE("Discover request %d got an error from DNSServiceBrowse %d", requestId, result);
+ mMonitor->freeServiceRef(requestId);
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "Discover request got an error from DNSServiceBrowse", false);
+ return;
+ }
+ mMonitor->startMonitoring(requestId);
+ if (VDBG) ALOGD("discover successful");
+ cli->sendMsg(ResponseCode::CommandOkay, "Discover operation started", false);
+ return;
+}
+
+void MDnsSdListenerDiscoverCallback(DNSServiceRef sdRef, DNSServiceFlags flags,
+ uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName,
+ const char *regType, const char *replyDomain, void *inContext) {
+ MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
+ char *msg;
+ int refNumber = context->mRefNumber;
+
+ if (errorCode != kDNSServiceErr_NoError) {
+ asprintf(&msg, "%d %d", refNumber, errorCode);
+ context->mListener->sendBroadcast(ResponseCode::ServiceDiscoveryFailed, msg, false);
+ if (DBG) ALOGE("discover failure for %d, error= %d", refNumber, errorCode);
+ } else {
+ int respCode;
+ char *quotedServiceName = SocketClient::quoteArg(serviceName);
+ if (flags & kDNSServiceFlagsAdd) {
+ if (VDBG) {
+ ALOGD("Discover found new serviceName %s, regType %s and domain %s for %d",
+ serviceName, regType, replyDomain, refNumber);
+ }
+ respCode = ResponseCode::ServiceDiscoveryServiceAdded;
+ } else {
+ if (VDBG) {
+ ALOGD("Discover lost serviceName %s, regType %s and domain %s for %d",
+ serviceName, regType, replyDomain, refNumber);
+ }
+ respCode = ResponseCode::ServiceDiscoveryServiceRemoved;
+ }
+ asprintf(&msg, "%d %s %s %s", refNumber, quotedServiceName, regType, replyDomain);
+ free(quotedServiceName);
+ context->mListener->sendBroadcast(respCode, msg, false);
+ }
+ free(msg);
+}
+
+void MDnsSdListener::Handler::stop(SocketClient *cli, int argc, char **argv, const char *str) {
+ if (argc != 3) {
+ char *msg;
+ asprintf(&msg, "Invalid number of arguments to %s", str);
+ cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
+ free(msg);
+ return;
+ }
+ int requestId = atoi(argv[2]);
+ DNSServiceRef *ref = mMonitor->lookupServiceRef(requestId);
+ if (ref == NULL) {
+ if (DBG) ALOGE("%s stop used unknown requestId %d", str, requestId);
+ cli->sendMsg(ResponseCode::CommandParameterError, "Unknown requestId", false);
+ return;
+ }
+ if (VDBG) ALOGD("Stopping %s with ref %p", str, ref);
+ DNSServiceRefDeallocate(*ref);
+ mMonitor->freeServiceRef(requestId);
+ char *msg;
+ asprintf(&msg, "%s stopped", str);
+ cli->sendMsg(ResponseCode::CommandOkay, msg, false);
+ free(msg);
+}
+
+void MDnsSdListener::Handler::serviceRegister(SocketClient *cli, int requestId,
+ const char *interfaceName, const char *serviceName, const char *serviceType,
+ const char *domain, const char *host, int port, int txtLen, void *txtRecord) {
+ if (VDBG) {
+ ALOGD("serviceRegister(%d, %s, %s, %s, %s, %s, %d, %d, <binary>)", requestId,
+ interfaceName, serviceName, serviceType, domain, host, port, txtLen);
+ }
+ Context *context = new Context(requestId, mListener);
+ DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
+ port = htons(port);
+ if (ref == NULL) {
+ ALOGE("requestId %d already in use during register call", requestId);
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "RequestId already in use during register call", false);
+ return;
+ }
+ DNSServiceFlags nativeFlags = 0;
+ int interfaceInt = ifaceNameToI(interfaceName);
+ DNSServiceErrorType result = DNSServiceRegister(ref, interfaceInt, nativeFlags, serviceName,
+ serviceType, domain, host, port, txtLen, txtRecord, &MDnsSdListenerRegisterCallback,
+ context);
+ if (result != kDNSServiceErr_NoError) {
+ ALOGE("service register request %d got an error from DNSServiceRegister %d", requestId,
+ result);
+ mMonitor->freeServiceRef(requestId);
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "serviceRegister request got an error from DNSServiceRegister", false);
+ return;
+ }
+ mMonitor->startMonitoring(requestId);
+ if (VDBG) ALOGD("serviceRegister successful");
+ cli->sendMsg(ResponseCode::CommandOkay, "serviceRegister started", false);
+ return;
+}
+
+void MDnsSdListenerRegisterCallback(DNSServiceRef sdRef, DNSServiceFlags flags,
+ DNSServiceErrorType errorCode, const char *serviceName, const char *regType,
+ const char *domain, void *inContext) {
+ MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
+ char *msg;
+ int refNumber = context->mRefNumber;
+ if (errorCode != kDNSServiceErr_NoError) {
+ asprintf(&msg, "%d %d", refNumber, errorCode);
+ context->mListener->sendBroadcast(ResponseCode::ServiceRegistrationFailed, msg, false);
+ if (DBG) ALOGE("register failure for %d, error= %d", refNumber, errorCode);
+ } else {
+ char *quotedServiceName = SocketClient::quoteArg(serviceName);
+ asprintf(&msg, "%d %s", refNumber, quotedServiceName);
+ free(quotedServiceName);
+ context->mListener->sendBroadcast(ResponseCode::ServiceRegistrationSucceeded, msg, false);
+ if (VDBG) ALOGD("register succeeded for %d as %s", refNumber, serviceName);
+ }
+ free(msg);
+}
+
+
+void MDnsSdListener::Handler::resolveService(SocketClient *cli, int requestId,
+ const char *interfaceName, const char *serviceName, const char *regType,
+ const char *domain) {
+ if (VDBG) {
+ ALOGD("resolveService(%d, %s, %s, %s, %s)", requestId, interfaceName,
+ serviceName, regType, domain);
+ }
+ Context *context = new Context(requestId, mListener);
+ DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
+ if (ref == NULL) {
+ ALOGE("request Id %d already in use during resolve call", requestId);
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "RequestId already in use during resolve call", false);
+ return;
+ }
+ DNSServiceFlags nativeFlags = 0;
+ int interfaceInt = ifaceNameToI(interfaceName);
+ DNSServiceErrorType result = DNSServiceResolve(ref, nativeFlags, interfaceInt, serviceName,
+ regType, domain, &MDnsSdListenerResolveCallback, context);
+ if (result != kDNSServiceErr_NoError) {
+ ALOGE("service resolve request %d got an error from DNSServiceResolve %d", requestId,
+ result);
+ mMonitor->freeServiceRef(requestId);
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "resolveService got an error from DNSServiceResolve", false);
+ return;
+ }
+ mMonitor->startMonitoring(requestId);
+ if (VDBG) ALOGD("resolveService successful");
+ cli->sendMsg(ResponseCode::CommandOkay, "resolveService started", false);
+ return;
+}
+
+void MDnsSdListenerResolveCallback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interface,
+ DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port,
+ uint16_t txtLen, const unsigned char *txtRecord, void *inContext) {
+ MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
+ char *msg;
+ int refNumber = context->mRefNumber;
+ port = ntohs(port);
+ if (errorCode != kDNSServiceErr_NoError) {
+ asprintf(&msg, "%d %d", refNumber, errorCode);
+ context->mListener->sendBroadcast(ResponseCode::ServiceResolveFailed, msg, false);
+ if (DBG) ALOGE("resolve failure for %d, error= %d", refNumber, errorCode);
+ } else {
+ char *quotedFullName = SocketClient::quoteArg(fullname);
+ char *quotedHostTarget = SocketClient::quoteArg(hosttarget);
+ asprintf(&msg, "%d %s %s %d %d", refNumber, quotedFullName, quotedHostTarget, port, txtLen);
+ free(quotedFullName);
+ free(quotedHostTarget);
+ context->mListener->sendBroadcast(ResponseCode::ServiceResolveSuccess, msg, false);
+ if (VDBG) {
+ ALOGD("resolve succeeded for %d finding %s at %s:%d with txtLen %d",
+ refNumber, fullname, hosttarget, port, txtLen);
+ }
+ }
+ free(msg);
+}
+
+void MDnsSdListener::Handler::getAddrInfo(SocketClient *cli, int requestId,
+ const char *interfaceName, uint32_t protocol, const char *hostname) {
+ if (VDBG) ALOGD("getAddrInfo(%d, %s %d, %s)", requestId, interfaceName, protocol, hostname);
+ Context *context = new Context(requestId, mListener);
+ DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
+ if (ref == NULL) {
+ ALOGE("request ID %d already in use during getAddrInfo call", requestId);
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "RequestId already in use during getAddrInfo call", false);
+ return;
+ }
+ DNSServiceFlags nativeFlags = 0;
+ int interfaceInt = ifaceNameToI(interfaceName);
+ DNSServiceErrorType result = DNSServiceGetAddrInfo(ref, nativeFlags, interfaceInt, protocol,
+ hostname, &MDnsSdListenerGetAddrInfoCallback, context);
+ if (result != kDNSServiceErr_NoError) {
+ ALOGE("getAddrInfo request %d got an error from DNSServiceGetAddrInfo %d", requestId,
+ result);
+ mMonitor->freeServiceRef(requestId);
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "getAddrInfo request got an error from DNSServiceGetAddrInfo", false);
+ return;
+ }
+ mMonitor->startMonitoring(requestId);
+ if (VDBG) ALOGD("getAddrInfo successful");
+ cli->sendMsg(ResponseCode::CommandOkay, "getAddrInfo started", false);
+ return;
+}
+
+void MDnsSdListenerGetAddrInfoCallback(DNSServiceRef sdRef, DNSServiceFlags flags,
+ uint32_t interface, DNSServiceErrorType errorCode, const char *hostname,
+ const struct sockaddr *const sa, uint32_t ttl, void *inContext) {
+ MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
+ int refNumber = context->mRefNumber;
+
+ if (errorCode != kDNSServiceErr_NoError) {
+ char *msg;
+ asprintf(&msg, "%d %d", refNumber, errorCode);
+ context->mListener->sendBroadcast(ResponseCode::ServiceGetAddrInfoFailed, msg, false);
+ if (DBG) ALOGE("getAddrInfo failure for %d, error= %d", refNumber, errorCode);
+ free(msg);
+ } else {
+ char addr[INET6_ADDRSTRLEN];
+ char *msg;
+ char *quotedHostname = SocketClient::quoteArg(hostname);
+ if (sa->sa_family == AF_INET) {
+ inet_ntop(sa->sa_family, &(((struct sockaddr_in *)sa)->sin_addr), addr, sizeof(addr));
+ } else {
+ inet_ntop(sa->sa_family, &(((struct sockaddr_in6 *)sa)->sin6_addr), addr, sizeof(addr));
+ }
+ asprintf(&msg, "%d %s %d %s", refNumber, quotedHostname, ttl, addr);
+ free(quotedHostname);
+ context->mListener->sendBroadcast(ResponseCode::ServiceGetAddrInfoSuccess, msg, false);
+ if (VDBG) {
+ ALOGD("getAddrInfo succeeded for %d: %s", refNumber, msg);
+ }
+ free(msg);
+ }
+}
+
+void MDnsSdListener::Handler::setHostname(SocketClient *cli, int requestId,
+ const char *hostname) {
+ if (VDBG) ALOGD("setHostname(%d, %s)", requestId, hostname);
+ Context *context = new Context(requestId, mListener);
+ DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
+ if (ref == NULL) {
+ ALOGE("request Id %d already in use during setHostname call", requestId);
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "RequestId already in use during setHostname call", false);
+ return;
+ }
+ DNSServiceFlags nativeFlags = 0;
+ DNSServiceErrorType result = DNSSetHostname(ref, nativeFlags, hostname,
+ &MDnsSdListenerSetHostnameCallback, context);
+ if (result != kDNSServiceErr_NoError) {
+ ALOGE("setHostname request %d got an error from DNSSetHostname %d", requestId, result);
+ mMonitor->freeServiceRef(requestId);
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "setHostname got an error from DNSSetHostname", false);
+ return;
+ }
+ mMonitor->startMonitoring(requestId);
+ if (VDBG) ALOGD("setHostname successful");
+ cli->sendMsg(ResponseCode::CommandOkay, "setHostname started", false);
+ return;
+}
+
+void MDnsSdListenerSetHostnameCallback(DNSServiceRef sdRef, DNSServiceFlags flags,
+ DNSServiceErrorType errorCode, const char *hostname, void *inContext) {
+ MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
+ char *msg;
+ int refNumber = context->mRefNumber;
+ if (errorCode != kDNSServiceErr_NoError) {
+ asprintf(&msg, "%d %d", refNumber, errorCode);
+ context->mListener->sendBroadcast(ResponseCode::ServiceSetHostnameFailed, msg, false);
+ if (DBG) ALOGE("setHostname failure for %d, error= %d", refNumber, errorCode);
+ } else {
+ char *quotedHostname = SocketClient::quoteArg(hostname);
+ asprintf(&msg, "%d %s", refNumber, quotedHostname);
+ free(quotedHostname);
+ context->mListener->sendBroadcast(ResponseCode::ServiceSetHostnameSuccess, msg, false);
+ if (VDBG) ALOGD("setHostname succeeded for %d. Set to %s", refNumber, hostname);
+ }
+ free(msg);
+}
+
+
+int MDnsSdListener::Handler::ifaceNameToI(const char *iface) {
+ return 0;
+}
+
+const char *MDnsSdListener::Handler::iToIfaceName(int i) {
+ return NULL;
+}
+
+DNSServiceFlags MDnsSdListener::Handler::iToFlags(int i) {
+ return 0;
+}
+
+int MDnsSdListener::Handler::flagsToI(DNSServiceFlags flags) {
+ return 0;
+}
+
+int MDnsSdListener::Handler::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ if (argc < 2) {
+ char* msg = NULL;
+ asprintf( &msg, "Invalid number of arguments to mdnssd: %i", argc);
+ ALOGW("%s", msg);
+ cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
+ free(msg);
+ return -1;
+ }
+
+ char* cmd = argv[1];
+
+ if (strcmp(cmd, "discover") == 0) {
+ if (argc != 4) {
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "Invalid number of arguments to mdnssd discover", false);
+ return 0;
+ }
+ int requestId = atoi(argv[2]);
+ char *serviceType = argv[3];
+
+ discover(cli, NULL, serviceType, NULL, requestId, 0);
+ } else if (strcmp(cmd, "stop-discover") == 0) {
+ stop(cli, argc, argv, "discover");
+ } else if (strcmp(cmd, "register") == 0) {
+ if (argc != 6) {
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "Invalid number of arguments to mdnssd register", false);
+ return 0;
+ }
+ int requestId = atoi(argv[2]);
+ char *serviceName = argv[3];
+ char *serviceType = argv[4];
+ int port = atoi(argv[5]);
+ char *interfaceName = NULL; // will use all
+ char *domain = NULL; // will use default
+ char *host = NULL; // will use default hostname
+ int textLen = 0;
+ void *textRecord = NULL;
+
+ serviceRegister(cli, requestId, interfaceName, serviceName,
+ serviceType, domain, host, port, textLen, textRecord);
+ } else if (strcmp(cmd, "stop-register") == 0) {
+ stop(cli, argc, argv, "register");
+ } else if (strcmp(cmd, "resolve") == 0) {
+ if (argc != 6) {
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "Invalid number of arguments to mdnssd resolve", false);
+ return 0;
+ }
+ int requestId = atoi(argv[2]);
+ char *interfaceName = NULL; // will use all
+ char *serviceName = argv[3];
+ char *regType = argv[4];
+ char *domain = argv[5];
+ resolveService(cli, requestId, interfaceName, serviceName, regType, domain);
+ } else if (strcmp(cmd, "stop-resolve") == 0) {
+ stop(cli, argc, argv, "resolve");
+ } else if (strcmp(cmd, "start-service") == 0) {
+ if (mMonitor->startService()) {
+ cli->sendMsg(ResponseCode::CommandOkay, "Service Started", false);
+ } else {
+ cli->sendMsg(ResponseCode::ServiceStartFailed, "Service already running", false);
+ }
+ } else if (strcmp(cmd, "stop-service") == 0) {
+ if (mMonitor->stopService()) {
+ cli->sendMsg(ResponseCode::CommandOkay, "Service Stopped", false);
+ } else {
+ cli->sendMsg(ResponseCode::ServiceStopFailed, "Service still in use", false);
+ }
+ } else if (strcmp(cmd, "sethostname") == 0) {
+ if (argc != 4) {
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "Invalid number of arguments to mdnssd sethostname", false);
+ return 0;
+ }
+ int requestId = atoi(argv[2]);
+ char *hostname = argv[3];
+ setHostname(cli, requestId, hostname);
+ } else if (strcmp(cmd, "stop-sethostname") == 0) {
+ stop(cli, argc, argv, "sethostname");
+ } else if (strcmp(cmd, "getaddrinfo") == 0) {
+ if (argc != 4) {
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "Invalid number of arguments to mdnssd getaddrinfo", false);
+ return 0;
+ }
+ int requestId = atoi(argv[2]);
+ char *hostname = argv[3];
+ char *interfaceName = NULL; // default
+ int protocol = 0; // intelligient heuristic (both v4 + v6)
+ getAddrInfo(cli, requestId, interfaceName, protocol, hostname);
+ } else if (strcmp(cmd, "stop-getaddrinfo") == 0) {
+ stop(cli, argc, argv, "getaddrinfo");
+ } else {
+ if (VDBG) ALOGE("Unknown cmd %s", cmd);
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown mdnssd cmd", false);
+ return 0;
+ }
+ return 0;
+}
+
+MDnsSdListener::Monitor::Monitor() {
+ mHead = NULL;
+ pthread_mutex_init(&mHeadMutex, NULL);
+ socketpair(AF_LOCAL, SOCK_STREAM, 0, mCtrlSocketPair);
+ pthread_create(&mThread, NULL, MDnsSdListener::Monitor::threadStart, this);
+}
+
+void *MDnsSdListener::Monitor::threadStart(void *obj) {
+ Monitor *monitor = reinterpret_cast<Monitor *>(obj);
+
+ monitor->run();
+ delete monitor;
+ pthread_exit(NULL);
+ return NULL;
+}
+
+int MDnsSdListener::Monitor::startService() {
+ int result = 0;
+ char property_value[PROPERTY_VALUE_MAX];
+ pthread_mutex_lock(&mHeadMutex);
+ property_get(MDNS_SERVICE_STATUS, property_value, "");
+ if (strcmp("running", property_value) != 0) {
+ ALOGD("Starting MDNSD");
+ property_set("ctl.start", MDNS_SERVICE_NAME);
+ wait_for_property(MDNS_SERVICE_STATUS, "running", 5);
+ result = -1;
+ } else {
+ result = 0;
+ }
+ pthread_mutex_unlock(&mHeadMutex);
+ return result;
+}
+
+int MDnsSdListener::Monitor::stopService() {
+ int result = 0;
+ pthread_mutex_lock(&mHeadMutex);
+ if (mHead == NULL) {
+ ALOGD("Stopping MDNSD");
+ property_set("ctl.stop", MDNS_SERVICE_NAME);
+ wait_for_property(MDNS_SERVICE_STATUS, "stopped", 5);
+ result = -1;
+ } else {
+ result = 0;
+ }
+ pthread_mutex_unlock(&mHeadMutex);
+ return result;
+}
+
+void MDnsSdListener::Monitor::run() {
+ int pollCount = 1;
+ mPollSize = 10;
+
+ mPollFds = (struct pollfd *)calloc(sizeof(struct pollfd), mPollSize);
+ mPollRefs = (DNSServiceRef **)calloc(sizeof(DNSServiceRef *), mPollSize);
+
+ mPollFds[0].fd = mCtrlSocketPair[0];
+ mPollFds[0].events = POLLIN;
+
+ if (VDBG) ALOGD("MDnsSdListener starting to monitor");
+ while (1) {
+ if (VDBG) ALOGD("Going to poll with pollCount %d", pollCount);
+ int pollResults = poll(mPollFds, pollCount, 10000000);
+ if (pollResults < 0) {
+ ALOGE("Error in poll - got %d", errno);
+ } else if (pollResults > 0) {
+ if (VDBG) ALOGD("Monitor poll got data pollCount = %d, %d", pollCount, pollResults);
+ for(int i = 1; i < pollCount; i++) {
+ if (mPollFds[i].revents != 0) {
+ if (VDBG) {
+ ALOGD("Monitor found [%d].revents = %d - calling ProcessResults",
+ i, mPollFds[i].revents);
+ }
+ DNSServiceProcessResult(*(mPollRefs[i]));
+ mPollFds[i].revents = 0;
+ }
+ }
+ if (VDBG) ALOGD("controlSocket shows revent= %d", mPollFds[0].revents);
+ switch (mPollFds[0].revents) {
+ case POLLIN: {
+ char readBuf[2];
+ read(mCtrlSocketPair[0], &readBuf, 1);
+ if (DBG) ALOGD("MDnsSdListener::Monitor got %c", readBuf[0]);
+ if (memcmp(RESCAN, readBuf, 1) == 0) {
+ pollCount = rescan();
+ }
+ }
+ }
+ mPollFds[0].revents = 0;
+ } else {
+ if (VDBG) ALOGD("MDnsSdListener::Monitor poll timed out");
+ }
+ }
+ free(mPollFds);
+ free(mPollRefs);
+}
+
+#define DBG_RESCAN 0
+
+int MDnsSdListener::Monitor::rescan() {
+// rescan the list from mHead and make new pollfds and serviceRefs
+ if (VDBG) {
+ ALOGD("MDnsSdListener::Monitor poll rescanning - size=%d, live=%d", mPollSize, mLiveCount);
+ }
+ int count = 0;
+ pthread_mutex_lock(&mHeadMutex);
+ Element **prevPtr = &mHead;
+ int i = 1;
+ if (mPollSize <= mLiveCount) {
+ mPollSize = mLiveCount + 5;
+ free(mPollFds);
+ free(mPollRefs);
+ mPollFds = (struct pollfd *)calloc(sizeof(struct pollfd), mPollSize);
+ mPollRefs = (DNSServiceRef **)calloc(sizeof(DNSServiceRef *), mPollSize);
+ } else {
+ memset(mPollFds, sizeof(struct pollfd) * mPollSize, 0);
+ memset(mPollRefs, sizeof(DNSServiceRef *) * mPollSize, 0);
+ }
+ mPollFds[0].fd = mCtrlSocketPair[0];
+ mPollFds[0].events = POLLIN;
+ if (DBG_RESCAN) ALOGD("mHead = %p", mHead);
+ while (*prevPtr != NULL) {
+ if (DBG_RESCAN) ALOGD("checking %p, mReady = %d", *prevPtr, (*prevPtr)->mReady);
+ if ((*prevPtr)->mReady == 1) {
+ int fd = DNSServiceRefSockFD((*prevPtr)->mRef);
+ if (fd != -1) {
+ if (DBG_RESCAN) ALOGD(" adding FD %d", fd);
+ mPollFds[i].fd = fd;
+ mPollFds[i].events = POLLIN;
+ mPollRefs[i] = &((*prevPtr)->mRef);
+ i++;
+ } else {
+ ALOGE("Error retreving socket FD for live ServiceRef");
+ }
+ prevPtr = &((*prevPtr)->mNext); // advance to the next element
+ } else if ((*prevPtr)->mReady == -1) {
+ if (DBG_RESCAN) ALOGD(" removing %p from play", *prevPtr);
+ Element *cur = *prevPtr;
+ *prevPtr = (cur)->mNext; // change our notion of this element and don't advance
+ delete cur;
+ }
+ }
+ pthread_mutex_unlock(&mHeadMutex);
+ return i;
+}
+
+DNSServiceRef *MDnsSdListener::Monitor::allocateServiceRef(int id, Context *context) {
+ if (lookupServiceRef(id) != NULL) {
+ delete(context);
+ return NULL;
+ }
+ Element *e = new Element(id, context);
+ pthread_mutex_lock(&mHeadMutex);
+ e->mNext = mHead;
+ mHead = e;
+ pthread_mutex_unlock(&mHeadMutex);
+ return &(e->mRef);
+}
+
+DNSServiceRef *MDnsSdListener::Monitor::lookupServiceRef(int id) {
+ pthread_mutex_lock(&mHeadMutex);
+ Element *cur = mHead;
+ while (cur != NULL) {
+ if (cur->mId == id) {
+ DNSServiceRef *result = &(cur->mRef);
+ pthread_mutex_unlock(&mHeadMutex);
+ return result;
+ }
+ cur = cur->mNext;
+ }
+ pthread_mutex_unlock(&mHeadMutex);
+ return NULL;
+}
+
+void MDnsSdListener::Monitor::startMonitoring(int id) {
+ if (VDBG) ALOGD("startMonitoring %d", id);
+ pthread_mutex_lock(&mHeadMutex);
+ Element *cur = mHead;
+ while (cur != NULL) {
+ if (cur->mId == id) {
+ if (DBG_RESCAN) ALOGD("marking %p as ready to be added", cur);
+ mLiveCount++;
+ cur->mReady = 1;
+ pthread_mutex_unlock(&mHeadMutex);
+ write(mCtrlSocketPair[1], RESCAN, 1); // trigger a rescan for a fresh poll
+ if (VDBG) ALOGD("triggering rescan");
+ return;
+ }
+ cur = cur->mNext;
+ }
+ pthread_mutex_unlock(&mHeadMutex);
+}
+
+#define NAP_TIME 200 // 200 ms between polls
+static int wait_for_property(const char *name, const char *desired_value, int maxwait)
+{
+ char value[PROPERTY_VALUE_MAX] = {'\0'};
+ int maxnaps = (maxwait * 1000) / NAP_TIME;
+
+ if (maxnaps < 1) {
+ maxnaps = 1;
+ }
+
+ while (maxnaps-- > 0) {
+ usleep(NAP_TIME * 1000);
+ if (property_get(name, value, NULL)) {
+ if (desired_value == NULL || strcmp(value, desired_value) == 0) {
+ return 0;
+ }
+ }
+ }
+ return -1; /* failure */
+}
+
+void MDnsSdListener::Monitor::freeServiceRef(int id) {
+ if (VDBG) ALOGD("freeServiceRef %d", id);
+ pthread_mutex_lock(&mHeadMutex);
+ Element **prevPtr = &mHead;
+ Element *cur;
+ while (*prevPtr != NULL) {
+ cur = *prevPtr;
+ if (cur->mId == id) {
+ if (DBG_RESCAN) ALOGD("marking %p as ready to be removed", cur);
+ mLiveCount--;
+ if (cur->mReady == 1) {
+ cur->mReady = -1; // tell poll thread to delete
+ write(mCtrlSocketPair[1], RESCAN, 1); // trigger a rescan for a fresh poll
+ if (VDBG) ALOGD("triggering rescan");
+ } else {
+ *prevPtr = cur->mNext;
+ delete cur;
+ }
+ pthread_mutex_unlock(&mHeadMutex);
+ return;
+ }
+ prevPtr = &(cur->mNext);
+ }
+ pthread_mutex_unlock(&mHeadMutex);
+}
diff --git a/MDnsSdListener.h b/MDnsSdListener.h
new file mode 100644
index 0000000..a3b14ad
--- /dev/null
+++ b/MDnsSdListener.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef _MDNSSDLISTENER_H__
+#define _MDNSSDLISTENER_H__
+
+#include <pthread.h>
+#include <sysutils/FrameworkListener.h>
+#include <dns_sd.h>
+
+#include "NetdCommand.h"
+
+// callbacks
+void MDnsSdListenerDiscoverCallback(DNSServiceRef sdRef, DNSServiceFlags flags,
+ uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+ const char *serviceName, const char *regType, const char *replyDomain,
+ void *inContext);
+
+void MDnsSdListenerRegisterCallback(DNSServiceRef sdRef, DNSServiceFlags flags,
+ DNSServiceErrorType errorCode, const char *serviceName, const char *regType,
+ const char *domain, void *inContext);
+
+void MDnsSdListenerResolveCallback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interface,
+ DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port,
+ uint16_t txtLen, const unsigned char *txtRecord, void *inContext);
+
+void MDnsSdListenerSetHostnameCallback(DNSServiceRef, DNSServiceFlags flags,
+ DNSServiceErrorType errorCode, const char *hostname, void *inContext);
+
+void MDnsSdListenerGetAddrInfoCallback(DNSServiceRef sdRef, DNSServiceFlags flags,
+ uint32_t interface, DNSServiceErrorType errorCode, const char *hostname,
+ const struct sockaddr *const sa, uint32_t ttl, void *inContext);
+
+#define RESCAN "1"
+
+class MDnsSdListener : public FrameworkListener {
+public:
+ MDnsSdListener();
+ virtual ~MDnsSdListener() {}
+
+ class Context {
+ public:
+ MDnsSdListener *mListener;
+ int mRefNumber;
+
+ Context(int refNumber, MDnsSdListener *m) {
+ mRefNumber = refNumber;
+ mListener = m;
+ }
+
+ ~Context() {
+ }
+ };
+
+ class Monitor {
+ public:
+ Monitor();
+ virtual ~Monitor() {}
+ DNSServiceRef *allocateServiceRef(int id, Context *c);
+ void startMonitoring(int id);
+ DNSServiceRef *lookupServiceRef(int id);
+ void freeServiceRef(int id);
+ static void *threadStart(void *handler);
+ int startService();
+ int stopService();
+ private:
+ void run();
+ int rescan(); // returns the number of elements in the poll
+ class Element {
+ public:
+ int mId;
+ Element *mNext;
+ DNSServiceRef mRef;
+ Context *mContext;
+ int mReady;
+ Element(int id, Context *context)
+ : mId(id), mNext(NULL), mContext(context), mReady(0) {}
+ virtual ~Element() { delete(mContext); }
+ };
+ Element *mHead;
+ int mLiveCount;
+ struct pollfd *mPollFds;
+ DNSServiceRef **mPollRefs;
+ int mPollSize;
+ pthread_t mThread;
+ int mCtrlSocketPair[2];
+ pthread_mutex_t mHeadMutex;
+ };
+
+ class Handler : public NetdCommand {
+ public:
+ Handler(Monitor *m, MDnsSdListener *listener);
+ virtual ~Handler();
+ int runCommand(SocketClient *c, int argc, char** argv);
+
+ MDnsSdListener *mListener; // needed for broadcast purposes
+ private:
+ void stop(SocketClient *cli, int argc, char **argv, const char *str);
+
+ void discover(SocketClient *cli, const char *iface, const char *regType,
+ const char *domain, const int requestNumber,
+ const int requestFlags);
+
+ void serviceRegister(SocketClient *cli, int requestId, const char *interfaceName,
+ const char *serviceName, const char *serviceType, const char *domain,
+ const char *host, int port, int textLen, void *txtRecord);
+
+ void resolveService(SocketClient *cli, int requestId,
+ const char *interfaceName, const char *serviceName, const char *regType,
+ const char *domain);
+
+ void setHostname(SocketClient *cli, int requestId, const char *hostname);
+
+ void getAddrInfo(SocketClient *cli, int requestId, const char *interfaceName,
+ uint32_t protocol, const char *hostname);
+
+ int ifaceNameToI(const char *iface);
+ const char *iToIfaceName(int i);
+ DNSServiceFlags iToFlags(int i);
+ int flagsToI(DNSServiceFlags flags);
+ Monitor *mMonitor;
+ };
+};
+
+static int wait_for_property(const char *name, const char *desired_value, int maxwait);
+
+#endif
diff --git a/NatController.cpp b/NatController.cpp
index 4ea5d24..77c4874 100644
--- a/NatController.cpp
+++ b/NatController.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+// #define LOG_NDEBUG 0
+
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
@@ -29,16 +31,12 @@
#include "NatController.h"
#include "SecondaryTableController.h"
-#include "oem_iptables_hook.h"
+#include "NetdConstants.h"
extern "C" int system_nosh(const char *command);
-static char IPTABLES_PATH[] = "/system/bin/iptables";
-static char IP_PATH[] = "/system/bin/ip";
-
NatController::NatController(SecondaryTableController *ctrl) {
secondaryTableCtrl = ctrl;
- setDefaults();
}
NatController::~NatController() {
@@ -50,28 +48,51 @@
int res;
if (len == 255) {
- LOGE("command too long");
+ ALOGE("command too long");
errno = E2BIG;
return -1;
}
asprintf(&buffer, "%s %s", path, cmd);
res = system_nosh(buffer);
+ ALOGV("runCmd() buffer='%s' res=%d", buffer, res);
free(buffer);
return res;
}
-int NatController::setDefaults() {
-
+int NatController::setupIptablesHooks() {
if (runCmd(IPTABLES_PATH, "-P INPUT ACCEPT"))
return -1;
if (runCmd(IPTABLES_PATH, "-P OUTPUT ACCEPT"))
return -1;
- if (runCmd(IPTABLES_PATH, "-P FORWARD DROP"))
+ if (runCmd(IPTABLES_PATH, "-P FORWARD ACCEPT"))
return -1;
- if (runCmd(IPTABLES_PATH, "-F FORWARD"))
+
+ // Order is important!
+ // -D to delete any pre-existing jump rule, to prevent dupes (no-op if doesn't exist)
+ // -F to flush the chain (no-op if doesn't exist).
+ // -N to create the chain (no-op if already exist).
+
+ runCmd(IPTABLES_PATH, "-D FORWARD -j natctrl_FORWARD");
+ runCmd(IPTABLES_PATH, "-F natctrl_FORWARD");
+ runCmd(IPTABLES_PATH, "-N natctrl_FORWARD");
+ if (runCmd(IPTABLES_PATH, "-A FORWARD -j natctrl_FORWARD"))
return -1;
- if (runCmd(IPTABLES_PATH, "-t nat -F"))
+
+ runCmd(IPTABLES_PATH, "-t nat -D POSTROUTING -j natctrl_nat_POSTROUTING");
+ runCmd(IPTABLES_PATH, "-t nat -F natctrl_nat_POSTROUTING");
+ runCmd(IPTABLES_PATH, "-t nat -N natctrl_nat_POSTROUTING");
+ if (runCmd(IPTABLES_PATH, "-t nat -A POSTROUTING -j natctrl_nat_POSTROUTING"))
+ return -1;
+
+ setDefaults();
+ return 0;
+}
+
+int NatController::setDefaults() {
+ if (runCmd(IPTABLES_PATH, "-F natctrl_FORWARD"))
+ return -1;
+ if (runCmd(IPTABLES_PATH, "-t nat -F natctrl_nat_POSTROUTING"))
return -1;
runCmd(IP_PATH, "rule flush");
@@ -84,7 +105,6 @@
natCount = 0;
- setupOemIptablesHook();
return 0;
}
@@ -93,14 +113,6 @@
return true;
}
-const char *NatController::getVersion(const char *addr) {
- if (strchr(addr, ':') != NULL) {
- return "-6";
- } else {
- return "-4";
- }
-}
-
// 0 1 2 3 4 5
// nat enable intface extface addrcnt nated-ipaddr/prelength
int NatController::enableNat(const int argc, char **argv) {
@@ -113,29 +125,23 @@
int tableNumber;
if (!checkInterface(intIface) || !checkInterface(extIface)) {
- LOGE("Invalid interface specified");
+ ALOGE("Invalid interface specified");
errno = ENODEV;
return -1;
}
if (argc < 5 + addrCount) {
- LOGE("Missing Argument");
+ ALOGE("Missing Argument");
errno = EINVAL;
return -1;
}
tableNumber = secondaryTableCtrl->findTableNumber(extIface);
if (tableNumber != -1) {
- for(i = 0; i < addrCount && ret == 0; i++) {
- snprintf(cmd, sizeof(cmd), "%s rule add from %s table %d", getVersion(argv[5+i]),
- argv[5+i], tableNumber + BASE_TABLE_NUMBER);
- ret |= runCmd(IP_PATH, cmd);
- if (ret) LOGE("IP rule %s got %d", cmd, ret);
+ for(i = 0; i < addrCount; i++) {
+ ret |= secondaryTableCtrl->modifyFromRule(tableNumber, ADD, argv[5+i]);
- snprintf(cmd, sizeof(cmd), "route add %s dev %s table %d", argv[5+i], intIface,
- tableNumber + BASE_TABLE_NUMBER);
- ret |= runCmd(IP_PATH, cmd);
- if (ret) LOGE("IP route %s got %d", cmd, ret);
+ ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, ADD, intIface, argv[5+i]);
}
runCmd(IP_PATH, "route flush cache");
}
@@ -143,32 +149,35 @@
if (ret != 0 || setForwardRules(true, intIface, extIface) != 0) {
if (tableNumber != -1) {
for (i = 0; i < addrCount; i++) {
- snprintf(cmd, sizeof(cmd), "route del %s dev %s table %d", argv[5+i], intIface,
- tableNumber + BASE_TABLE_NUMBER);
- runCmd(IP_PATH, cmd);
+ secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
- snprintf(cmd, sizeof(cmd), "%s rule del from %s table %d", getVersion(argv[5+i]),
- argv[5+i], tableNumber + BASE_TABLE_NUMBER);
- runCmd(IP_PATH, cmd);
+ secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
}
runCmd(IP_PATH, "route flush cache");
}
- LOGE("Error setting forward rules");
+ ALOGE("Error setting forward rules");
errno = ENODEV;
return -1;
}
+ /* Always make sure the drop rule is at the end */
+ snprintf(cmd, sizeof(cmd), "-D natctrl_FORWARD -j DROP");
+ runCmd(IPTABLES_PATH, cmd);
+ snprintf(cmd, sizeof(cmd), "-A natctrl_FORWARD -j DROP");
+ runCmd(IPTABLES_PATH, cmd);
+
+
natCount++;
// add this if we are the first added nat
if (natCount == 1) {
- snprintf(cmd, sizeof(cmd), "-t nat -A POSTROUTING -o %s -j MASQUERADE", extIface);
+ snprintf(cmd, sizeof(cmd), "-t nat -A natctrl_nat_POSTROUTING -o %s -j MASQUERADE", extIface);
if (runCmd(IPTABLES_PATH, cmd)) {
- LOGE("Error seting postroute rule: %s", cmd);
+ ALOGE("Error seting postroute rule: %s", cmd);
// unwind what's been done, but don't care about success - what more could we do?
for (i = 0; i < addrCount; i++) {
- snprintf(cmd, sizeof(cmd), "route del %s dev %s table %d", argv[5+i], intIface,
- tableNumber + BASE_TABLE_NUMBER);
- runCmd(IP_PATH, cmd);
+ secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
+
+ secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
}
setDefaults();
return -1;
@@ -182,7 +191,7 @@
char cmd[255];
snprintf(cmd, sizeof(cmd),
- "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
+ "-%s natctrl_FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j RETURN",
(add ? "A" : "D"),
extIface, intIface);
if (runCmd(IPTABLES_PATH, cmd) && add) {
@@ -190,36 +199,37 @@
}
snprintf(cmd, sizeof(cmd),
- "-%s FORWARD -i %s -o %s -m state --state INVALID -j DROP",
+ "-%s natctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
(add ? "A" : "D"),
intIface, extIface);
if (runCmd(IPTABLES_PATH, cmd) && add) {
// bail on error, but only if adding
snprintf(cmd, sizeof(cmd),
- "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
+ "-%s natctrl_FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j RETURN",
(!add ? "A" : "D"),
extIface, intIface);
runCmd(IPTABLES_PATH, cmd);
return -1;
}
- snprintf(cmd, sizeof(cmd), "-%s FORWARD -i %s -o %s -j ACCEPT", (add ? "A" : "D"),
+ snprintf(cmd, sizeof(cmd), "-%s natctrl_FORWARD -i %s -o %s -j RETURN", (add ? "A" : "D"),
intIface, extIface);
if (runCmd(IPTABLES_PATH, cmd) && add) {
// unwind what's been done, but don't care about success - what more could we do?
snprintf(cmd, sizeof(cmd),
- "-%s FORWARD -i %s -o %s -m state --state INVALID -j DROP",
+ "-%s natctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
(!add ? "A" : "D"),
intIface, extIface);
runCmd(IPTABLES_PATH, cmd);
snprintf(cmd, sizeof(cmd),
- "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
+ "-%s natctrl_FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j RETURN",
(!add ? "A" : "D"),
extIface, intIface);
runCmd(IPTABLES_PATH, cmd);
return -1;
}
+
return 0;
}
@@ -235,13 +245,13 @@
int tableNumber;
if (!checkInterface(intIface) || !checkInterface(extIface)) {
- LOGE("Invalid interface specified");
+ ALOGE("Invalid interface specified");
errno = ENODEV;
return -1;
}
if (argc < 5 + addrCount) {
- LOGE("Missing Argument");
+ ALOGE("Missing Argument");
errno = EINVAL;
return -1;
}
@@ -251,15 +261,9 @@
tableNumber = secondaryTableCtrl->findTableNumber(extIface);
if (tableNumber != -1) {
for (i = 0; i < addrCount; i++) {
- snprintf(cmd, sizeof(cmd), "route del %s dev %s table %d", argv[5+i], intIface,
- tableNumber + BASE_TABLE_NUMBER);
- // if the interface has gone down these will be gone already and give errors
- // ignore them.
- runCmd(IP_PATH, cmd);
+ secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
- snprintf(cmd, sizeof(cmd), "%s rule del from %s table %d", getVersion(argv[5+i]),
- argv[5+i], tableNumber + BASE_TABLE_NUMBER);
- runCmd(IP_PATH, cmd);
+ secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
}
runCmd(IP_PATH, "route flush cache");
diff --git a/NatController.h b/NatController.h
index eae32b4..1d328e5 100644
--- a/NatController.h
+++ b/NatController.h
@@ -19,8 +19,6 @@
#include <linux/in.h>
-#include <utils/List.h>
-
#include "SecondaryTableController.h"
class NatController {
@@ -31,6 +29,7 @@
int enableNat(const int argc, char **argv);
int disableNat(const int argc, char **argv);
+ int setupIptablesHooks();
private:
int natCount;
@@ -40,7 +39,6 @@
int runCmd(const char *path, const char *cmd);
bool checkInterface(const char *iface);
int setForwardRules(bool set, const char *intIface, const char *extIface);
- const char *getVersion(const char *addr);
};
#endif
diff --git a/NetdConstants.cpp b/NetdConstants.cpp
new file mode 100644
index 0000000..e57b483
--- /dev/null
+++ b/NetdConstants.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2012 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 "NetdConstants.h"
+
+const char * const OEM_SCRIPT_PATH = "/system/bin/oem-iptables-init.sh";
+const char * const IPTABLES_PATH = "/system/bin/iptables";
+const char * const IP6TABLES_PATH = "/system/bin/ip6tables";
+const char * const TC_PATH = "/system/bin/tc";
+const char * const IP_PATH = "/system/bin/ip";
+const char * const ADD = "add";
+const char * const DEL = "del";
diff --git a/NetdConstants.h b/NetdConstants.h
new file mode 100644
index 0000000..9943a05
--- /dev/null
+++ b/NetdConstants.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef _NETD_CONSTANTS_H
+#define _NETD_CONSTANTS_H
+
+
+extern const char * const IPTABLES_PATH;
+extern const char * const IP6TABLES_PATH;
+extern const char * const IP_PATH;
+extern const char * const TC_PATH;
+extern const char * const OEM_SCRIPT_PATH;
+extern const char * const ADD;
+extern const char * const DEL;
+
+#endif
diff --git a/NetlinkHandler.cpp b/NetlinkHandler.cpp
index 8331ae0..94e9240 100644
--- a/NetlinkHandler.cpp
+++ b/NetlinkHandler.cpp
@@ -48,7 +48,7 @@
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
const char *subsys = evt->getSubsystem();
if (!subsys) {
- LOGW("No subsystem found in netlink event");
+ ALOGW("No subsystem found in netlink event");
return;
}
@@ -68,12 +68,25 @@
} else if (action == evt->NlActionLinkDown) {
notifyInterfaceLinkChanged(iface, false);
}
+
} else if (!strcmp(subsys, "qlog")) {
const char *alertName = evt->findParam("ALERT_NAME");
const char *iface = evt->findParam("INTERFACE");
notifyQuotaLimitReached(alertName, iface);
- }
+ } else if (!strcmp(subsys, "xt_idletimer")) {
+ int action = evt->getAction();
+ const char *iface = evt->findParam("INTERFACE");
+ const char *state = evt->findParam("STATE");
+ if (state)
+ notifyInterfaceActivity(iface, !strcmp("active", state));
+
+#if !LOG_NDEBUG
+ } else if (strcmp(subsys, "platform") && strcmp(subsys, "backlight")) {
+ /* It is not a VSYNC or a backlight event */
+ ALOGV("unexpected event from subsystem %s", subsys);
+#endif
+ }
}
void NetlinkHandler::notifyInterfaceAdded(const char *name) {
@@ -117,3 +130,13 @@
mNm->getBroadcaster()->sendBroadcast(ResponseCode::BandwidthControl,
msg, false);
}
+
+void NetlinkHandler::notifyInterfaceActivity(const char *name, bool isActive) {
+ char msg[255];
+
+ snprintf(msg, sizeof(msg), "Iface %s %s", name, isActive ? "active" : "idle");
+ ALOGV("Broadcasting interface activity msg: %s", msg);
+ mNm->getBroadcaster()->sendBroadcast(isActive ? ResponseCode::InterfaceActive
+ : ResponseCode::InterfaceIdle,
+ msg, false);
+}
diff --git a/NetlinkHandler.h b/NetlinkHandler.h
index 9466ca6..fe82934 100644
--- a/NetlinkHandler.h
+++ b/NetlinkHandler.h
@@ -38,5 +38,6 @@
void notifyInterfaceChanged(const char *name, bool isUp);
void notifyInterfaceLinkChanged(const char *name, bool isUp);
void notifyQuotaLimitReached(const char *name, const char *iface);
+ void notifyInterfaceActivity(const char *name, bool isActive);
};
#endif
diff --git a/NetlinkManager.cpp b/NetlinkManager.cpp
index 196945b..8e2bc69 100644
--- a/NetlinkManager.cpp
+++ b/NetlinkManager.cpp
@@ -63,12 +63,12 @@
nladdr.nl_groups = groups;
if ((*sock = socket(PF_NETLINK, SOCK_DGRAM, netlinkFamily)) < 0) {
- LOGE("Unable to create netlink socket: %s", strerror(errno));
+ ALOGE("Unable to create netlink socket: %s", strerror(errno));
return NULL;
}
if (setsockopt(*sock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
- LOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));
+ ALOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));
close(*sock);
return NULL;
}
@@ -80,14 +80,14 @@
}
if (bind(*sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
- LOGE("Unable to bind netlink socket: %s", strerror(errno));
+ ALOGE("Unable to bind netlink socket: %s", strerror(errno));
close(*sock);
return NULL;
}
NetlinkHandler *handler = new NetlinkHandler(this, *sock, format);
if (handler->start()) {
- LOGE("Unable to start NetlinkHandler: %s", strerror(errno));
+ ALOGE("Unable to start NetlinkHandler: %s", strerror(errno));
close(*sock);
return NULL;
}
@@ -108,9 +108,10 @@
if ((mQuotaHandler = setupSocket(&mQuotaSock, NETLINK_NFLOG,
NFLOG_QUOTA_GROUP, NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {
- LOGE("Unable to open quota2 logging socket");
+ ALOGE("Unable to open quota2 logging socket");
// TODO: return -1 once the emulator gets a new kernel.
}
+
return 0;
}
@@ -118,7 +119,7 @@
int status = 0;
if (mUeventHandler->stop()) {
- LOGE("Unable to stop uevent NetlinkHandler: %s", strerror(errno));
+ ALOGE("Unable to stop uevent NetlinkHandler: %s", strerror(errno));
status = -1;
}
@@ -129,7 +130,7 @@
mUeventSock = -1;
if (mRouteHandler->stop()) {
- LOGE("Unable to stop route NetlinkHandler: %s", strerror(errno));
+ ALOGE("Unable to stop route NetlinkHandler: %s", strerror(errno));
status = -1;
}
@@ -141,7 +142,7 @@
if (mQuotaHandler) {
if (mQuotaHandler->stop()) {
- LOGE("Unable to stop quota NetlinkHandler: %s", strerror(errno));
+ ALOGE("Unable to stop quota NetlinkHandler: %s", strerror(errno));
status = -1;
}
@@ -151,5 +152,6 @@
close(mQuotaSock);
mQuotaSock = -1;
}
+
return status;
}
diff --git a/NetlinkManager.h b/NetlinkManager.h
index c8f5507..6515ea4 100644
--- a/NetlinkManager.h
+++ b/NetlinkManager.h
@@ -32,9 +32,11 @@
NetlinkHandler *mUeventHandler;
NetlinkHandler *mRouteHandler;
NetlinkHandler *mQuotaHandler;
+ NetlinkHandler *mIfaceIdleTimerHandler;
int mUeventSock;
int mRouteSock;
int mQuotaSock;
+ int mIfaceIdleTimerSock;
public:
virtual ~NetlinkManager();
@@ -50,6 +52,9 @@
/* This is the nflog group arg that the xt_quota2 neftiler will use. */
static const int NFLOG_QUOTA_GROUP;
+ /* This is the group that the xt_IDLETIMER netfilter will use. */
+ static const int IDLETIMER_GROUP;
+
private:
NetlinkManager();
NetlinkHandler* setupSocket(int *sock, int netlinkFamily, int groups,
diff --git a/PanController.cpp b/PanController.cpp
index 253c943..164b01a 100644
--- a/PanController.cpp
+++ b/PanController.cpp
@@ -52,33 +52,33 @@
#ifdef HAVE_BLUETOOTH
if (!bt_is_enabled()) {
- LOGE("Cannot start PAN services - Bluetooth not running");
+ ALOGE("Cannot start PAN services - Bluetooth not running");
errno = ENODEV;
return -1;
}
#else
- LOGE("Cannot start PAN services - No Bluetooth support");
+ ALOGE("Cannot start PAN services - No Bluetooth support");
errno = ENODEV;
return -1;
#endif
if (mPid) {
- LOGE("PAN already started");
+ ALOGE("PAN already started");
errno = EBUSY;
return -1;
}
if ((pid = fork()) < 0) {
- LOGE("fork failed (%s)", strerror(errno));
+ ALOGE("fork failed (%s)", strerror(errno));
return -1;
}
if (!pid) {
if (execl("/system/bin/pand", "/system/bin/pand", "--nodetach", "--listen",
"--role", "NAP", (char *) NULL)) {
- LOGE("execl failed (%s)", strerror(errno));
+ ALOGE("execl failed (%s)", strerror(errno));
}
- LOGE("Should never get here!");
+ ALOGE("Should never get here!");
return 0;
} else {
mPid = pid;
@@ -89,15 +89,15 @@
int PanController::stopPan() {
if (mPid == 0) {
- LOGE("PAN already stopped");
+ ALOGE("PAN already stopped");
return 0;
}
- LOGD("Stopping PAN services");
+ ALOGD("Stopping PAN services");
kill(mPid, SIGTERM);
waitpid(mPid, NULL, 0);
mPid = 0;
- LOGD("PAN services stopped");
+ ALOGD("PAN services stopped");
return 0;
}
diff --git a/PanController.h b/PanController.h
index 4f52fee..a97e039 100644
--- a/PanController.h
+++ b/PanController.h
@@ -19,8 +19,6 @@
#include <linux/in.h>
-#include <utils/List.h>
-
class PanController {
pid_t mPid;
diff --git a/PppController.cpp b/PppController.cpp
index 4caf382..6b54c31 100644
--- a/PppController.cpp
+++ b/PppController.cpp
@@ -34,8 +34,6 @@
#include "PppController.h"
-extern "C" int logwrap(int argc, const char **argv, int background);
-
PppController::PppController() {
mTtys = new TtyCollection();
mPid = 0;
@@ -56,7 +54,7 @@
pid_t pid;
if (mPid) {
- LOGE("Multiple PPPD instances not currently supported");
+ ALOGE("Multiple PPPD instances not currently supported");
errno = EBUSY;
return -1;
}
@@ -68,13 +66,13 @@
}
}
if (it == mTtys->end()) {
- LOGE("Invalid tty '%s' specified", tty);
+ ALOGE("Invalid tty '%s' specified", tty);
errno = -EINVAL;
return -1;
}
if ((pid = fork()) < 0) {
- LOGE("fork failed (%s)", strerror(errno));
+ ALOGE("fork failed (%s)", strerror(errno));
return -1;
}
@@ -94,9 +92,9 @@
// but not getting a connection
if (execl("/system/bin/pppd", "/system/bin/pppd", "-detach", dev, "115200",
lr, "ms-dns", d1, "ms-dns", d2, "lcp-max-configure", "99999", (char *) NULL)) {
- LOGE("execl failed (%s)", strerror(errno));
+ ALOGE("execl failed (%s)", strerror(errno));
}
- LOGE("Should never get here!");
+ ALOGE("Should never get here!");
return 0;
} else {
mPid = pid;
@@ -107,15 +105,15 @@
int PppController::detachPppd(const char *tty) {
if (mPid == 0) {
- LOGE("PPPD already stopped");
+ ALOGE("PPPD already stopped");
return 0;
}
- LOGD("Stopping PPPD services on port %s", tty);
+ ALOGD("Stopping PPPD services on port %s", tty);
kill(mPid, SIGTERM);
waitpid(mPid, NULL, 0);
mPid = 0;
- LOGD("PPPD services on port %s stopped", tty);
+ ALOGD("PPPD services on port %s stopped", tty);
return 0;
}
@@ -134,7 +132,7 @@
DIR *d = opendir("/sys/class/tty");
if (!d) {
- LOGE("Error opening /sys/class/tty (%s)", strerror(errno));
+ ALOGE("Error opening /sys/class/tty (%s)", strerror(errno));
return -1;
}
diff --git a/PppController.h b/PppController.h
index bb75435..cc74c8c 100644
--- a/PppController.h
+++ b/PppController.h
@@ -19,9 +19,9 @@
#include <linux/in.h>
-#include <utils/List.h>
+#include "List.h"
-typedef android::List<char *> TtyCollection;
+typedef android::netd::List<char *> TtyCollection;
class PppController {
TtyCollection *mTtys;
diff --git a/ResolverController.cpp b/ResolverController.cpp
index b079f81..680be20 100644
--- a/ResolverController.cpp
+++ b/ResolverController.cpp
@@ -20,13 +20,16 @@
#include <cutils/log.h>
#include <linux/if.h>
-#include <resolv.h>
+
+// NOTE: <resolv_iface.h> is a private C library header that provides
+// declarations for _resolv_set_default_iface() and others.
+#include <resolv_iface.h>
#include "ResolverController.h"
int ResolverController::setDefaultInterface(const char* iface) {
if (DBG) {
- LOGD("setDefaultInterface iface = %s\n", iface);
+ ALOGD("setDefaultInterface iface = %s\n", iface);
}
_resolv_set_default_iface(iface);
@@ -36,7 +39,7 @@
int ResolverController::setInterfaceDnsServers(const char* iface, char** servers, int numservers) {
if (DBG) {
- LOGD("setInterfaceDnsServers iface = %s\n", iface);
+ ALOGD("setInterfaceDnsServers iface = %s\n", iface);
}
_resolv_set_nameservers_for_iface(iface, servers, numservers);
@@ -46,7 +49,7 @@
int ResolverController::setInterfaceAddress(const char* iface, struct in_addr* addr) {
if (DBG) {
- LOGD("setInterfaceAddress iface = %s\n", iface);
+ ALOGD("setInterfaceAddress iface = %s\n", iface);
}
_resolv_set_addr_of_iface(iface, addr);
@@ -56,7 +59,7 @@
int ResolverController::flushDefaultDnsCache() {
if (DBG) {
- LOGD("flushDefaultDnsCache\n");
+ ALOGD("flushDefaultDnsCache\n");
}
_resolv_flush_cache_for_default_iface();
@@ -66,7 +69,7 @@
int ResolverController::flushInterfaceDnsCache(const char* iface) {
if (DBG) {
- LOGD("flushInterfaceDnsCache iface = %s\n", iface);
+ ALOGD("flushInterfaceDnsCache iface = %s\n", iface);
}
_resolv_flush_cache_for_iface(iface);
diff --git a/ResponseCode.h b/ResponseCode.h
index b01c141..5bebb0f 100644
--- a/ResponseCode.h
+++ b/ResponseCode.h
@@ -44,10 +44,14 @@
static const int InterfaceTxThrottleResult = 219;
static const int QuotaCounterResult = 220;
static const int TetheringStatsResult = 221;
+ static const int DnsProxyQueryResult = 222;
// 400 series - The command was accepted but the requested action
// did not take place.
- static const int OperationFailed = 400;
+ static const int OperationFailed = 400;
+ static const int DnsProxyOperationFailed = 401;
+ static const int ServiceStartFailed = 402;
+ static const int ServiceStopFailed = 403;
// 500 series - The command was not accepted and the requested
// action did not take place.
@@ -55,7 +59,20 @@
static const int CommandParameterError = 501;
// 600 series - Unsolicited broadcasts
- static const int InterfaceChange = 600;
- static const int BandwidthControl = 601;
+ static const int InterfaceChange = 600;
+ static const int BandwidthControl = 601;
+ static const int ServiceDiscoveryFailed = 602;
+ static const int ServiceDiscoveryServiceAdded = 603;
+ static const int ServiceDiscoveryServiceRemoved = 604;
+ static const int ServiceRegistrationFailed = 605;
+ static const int ServiceRegistrationSucceeded = 606;
+ static const int ServiceResolveFailed = 607;
+ static const int ServiceResolveSuccess = 608;
+ static const int ServiceSetHostnameFailed = 609;
+ static const int ServiceSetHostnameSuccess = 610;
+ static const int ServiceGetAddrInfoFailed = 611;
+ static const int ServiceGetAddrInfoSuccess = 612;
+ static const int InterfaceActive = 613;
+ static const int InterfaceIdle = 614;
};
#endif
diff --git a/SecondaryTableController.cpp b/SecondaryTableController.cpp
index 2289259..7d3de38 100644
--- a/SecondaryTableController.cpp
+++ b/SecondaryTableController.cpp
@@ -34,12 +34,9 @@
extern "C" int system_nosh(const char *command);
#include "ResponseCode.h"
+#include "NetdConstants.h"
#include "SecondaryTableController.h"
-static char IP_PATH[] = "/system/bin/ip";
-static char ADD[] = "add";
-static char DEL[] = "del";
-
SecondaryTableController::SecondaryTableController() {
int i;
for (i=0; i < INTERFACES_TRACKED; i++) {
@@ -69,7 +66,7 @@
if (tableIndex == -1) {
tableIndex = findTableNumber(""); // look for an empty slot
if (tableIndex == -1) {
- LOGE("Max number of NATed interfaces reached");
+ ALOGE("Max number of NATed interfaces reached");
errno = ENODEV;
cli->sendMsg(ResponseCode::OperationFailed, "Max number NATed", true);
return -1;
@@ -82,8 +79,8 @@
return modifyRoute(cli, ADD, iface, dest, prefix, gateway, tableIndex);
}
-int SecondaryTableController::modifyRoute(SocketClient *cli, char *action, char *iface, char *dest,
- int prefix, char *gateway, int tableIndex) {
+int SecondaryTableController::modifyRoute(SocketClient *cli, const char *action, char *iface,
+ char *dest, int prefix, char *gateway, int tableIndex) {
char *cmd;
if (strcmp("::", gateway) == 0) {
@@ -96,7 +93,7 @@
}
if (runAndFree(cli, cmd)) {
- LOGE("ip route %s failed: %s route %s %s/%d via %s dev %s table %d", action,
+ ALOGE("ip route %s failed: %s route %s %s/%d via %s dev %s table %d", action,
IP_PATH, action, dest, prefix, gateway, iface, tableIndex+BASE_TABLE_NUMBER);
errno = ENODEV;
cli->sendMsg(ResponseCode::OperationFailed, "ip route modification failed", true);
@@ -111,15 +108,45 @@
mInterfaceTable[tableIndex][0] = 0;
}
}
+ modifyRuleCount(tableIndex, action);
cli->sendMsg(ResponseCode::CommandOkay, "Route modified", false);
return 0;
}
+void SecondaryTableController::modifyRuleCount(int tableIndex, const char *action) {
+ if (strcmp(action, ADD) == 0) {
+ mInterfaceRuleCount[tableIndex]++;
+ } else {
+ if (--mInterfaceRuleCount[tableIndex] < 1) {
+ mInterfaceRuleCount[tableIndex] = 0;
+ mInterfaceTable[tableIndex][0] = 0;
+ }
+ }
+}
+
+int SecondaryTableController::verifyTableIndex(int tableIndex) {
+ if ((tableIndex < 0) ||
+ (tableIndex >= INTERFACES_TRACKED) ||
+ (mInterfaceTable[tableIndex][0] == 0)) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+const char *SecondaryTableController::getVersion(const char *addr) {
+ if (strchr(addr, ':') != NULL) {
+ return "-6";
+ } else {
+ return "-4";
+ }
+}
+
int SecondaryTableController::removeRoute(SocketClient *cli, char *iface, char *dest, int prefix,
char *gateway) {
int tableIndex = findTableNumber(iface);
if (tableIndex == -1) {
- LOGE("Interface not found");
+ ALOGE("Interface not found");
errno = ENODEV;
cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
return -1;
@@ -128,12 +155,46 @@
return modifyRoute(cli, DEL, iface, dest, prefix, gateway, tableIndex);
}
+int SecondaryTableController::modifyFromRule(int tableIndex, const char *action,
+ const char *addr) {
+ char *cmd;
+
+ if (verifyTableIndex(tableIndex)) {
+ return -1;
+ }
+ asprintf(&cmd, "%s %s rule %s from %s table %d", IP_PATH, getVersion(addr),
+ action, addr, tableIndex + BASE_TABLE_NUMBER);
+ if (runAndFree(NULL, cmd)) {
+ return -1;
+ }
+
+ modifyRuleCount(tableIndex, action);
+ return 0;
+}
+
+int SecondaryTableController::modifyLocalRoute(int tableIndex, const char *action,
+ const char *iface, const char *addr) {
+ char *cmd;
+
+ if (verifyTableIndex(tableIndex)) {
+ return -1;
+ }
+
+ modifyRuleCount(tableIndex, action); // some del's will fail as the iface is already gone.
+
+ asprintf(&cmd, "%s route %s %s dev %s table %d", IP_PATH, action, addr, iface,
+ tableIndex+BASE_TABLE_NUMBER);
+ return runAndFree(NULL, cmd);
+}
+
int SecondaryTableController::runAndFree(SocketClient *cli, char *cmd) {
int ret = 0;
if (strlen(cmd) >= 255) {
- LOGE("ip command (%s) too long", cmd);
- errno = E2BIG;
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Too long", true);
+ if (cli != NULL) {
+ ALOGE("ip command (%s) too long", cmd);
+ errno = E2BIG;
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Too long", true);
+ }
free(cmd);
return -1;
}
diff --git a/SecondaryTableController.h b/SecondaryTableController.h
index 7f30178..58914df 100644
--- a/SecondaryTableController.h
+++ b/SecondaryTableController.h
@@ -38,13 +38,18 @@
int addRoute(SocketClient *cli, char *iface, char *dest, int prefixLen, char *gateway);
int removeRoute(SocketClient *cli, char *iface, char *dest, int prefixLen, char *gateway);
int findTableNumber(const char *iface);
+ int modifyFromRule(int tableIndex, const char *action, const char *addr);
+ int modifyLocalRoute(int tableIndex, const char *action, const char *iface, const char *addr);
private:
- int modifyRoute(SocketClient *cli, char *action, char *iface, char *dest, int prefix,
+ int modifyRoute(SocketClient *cli, const char *action, char *iface, char *dest, int prefix,
char *gateway, int tableIndex);
char mInterfaceTable[INTERFACES_TRACKED][IFNAMSIZ + 1];
int mInterfaceRuleCount[INTERFACES_TRACKED];
+ void modifyRuleCount(int tableIndex, const char *action);
+ int verifyTableIndex(int tableIndex);
+ const char *getVersion(const char *addr);
int runAndFree(SocketClient *cli, char *cmd);
};
diff --git a/SoftapController.cpp b/SoftapController.cpp
index cd61462..ce41544 100644
--- a/SoftapController.cpp
+++ b/SoftapController.cpp
@@ -47,7 +47,7 @@
mPid = 0;
mSock = socket(AF_INET, SOCK_DGRAM, 0);
if (mSock < 0)
- LOGE("Failed to open socket");
+ ALOGE("Failed to open socket");
memset(mIface, 0, sizeof(mIface));
}
@@ -71,7 +71,7 @@
wrq.u.data.length = sizeof(tBuf) / sizeof(struct iw_priv_args);
wrq.u.data.flags = 0;
if ((ret = ioctl(mSock, SIOCGIWPRIV, &wrq)) < 0) {
- LOGE("SIOCGIPRIV failed: %d", ret);
+ ALOGE("SIOCGIPRIV failed: %d", ret);
return ret;
}
@@ -84,7 +84,7 @@
}
if (i == wrq.u.data.length) {
- LOGE("iface:%s, fname: %s - function not supported", iface, fname);
+ ALOGE("iface:%s, fname: %s - function not supported", iface, fname);
return -1;
}
@@ -96,7 +96,7 @@
break;
}
if (j == i) {
- LOGE("iface:%s, fname: %s - invalid private ioctl", iface, fname);
+ ALOGE("iface:%s, fname: %s - invalid private ioctl", iface, fname);
return -1;
}
sub_cmd = cmd;
@@ -119,18 +119,18 @@
int ret;
if (mSock < 0) {
- LOGE("Softap driver start - failed to open socket");
+ ALOGE("Softap driver start - failed to open socket");
return -1;
}
if (!iface || (iface[0] == '\0')) {
- LOGD("Softap driver start - wrong interface");
+ ALOGD("Softap driver start - wrong interface");
iface = mIface;
}
*mBuf = 0;
ret = setCommand(iface, "START");
if (ret < 0) {
- LOGE("Softap driver start: %d", ret);
+ ALOGE("Softap driver start: %d", ret);
return ret;
}
#ifdef HAVE_HOSTAPD
@@ -139,7 +139,7 @@
ifc_close();
#endif
usleep(AP_DRIVER_START_DELAY);
- LOGD("Softap driver start: %d", ret);
+ ALOGD("Softap driver start: %d", ret);
return ret;
}
@@ -147,11 +147,11 @@
int ret;
if (mSock < 0) {
- LOGE("Softap driver stop - failed to open socket");
+ ALOGE("Softap driver stop - failed to open socket");
return -1;
}
if (!iface || (iface[0] == '\0')) {
- LOGD("Softap driver stop - wrong interface");
+ ALOGD("Softap driver stop - wrong interface");
iface = mIface;
}
*mBuf = 0;
@@ -160,11 +160,11 @@
ret = ifc_down(iface);
ifc_close();
if (ret < 0) {
- LOGE("Softap %s down: %d", iface, ret);
+ ALOGE("Softap %s down: %d", iface, ret);
}
#endif
ret = setCommand(iface, "STOP");
- LOGD("Softap driver stop: %d", ret);
+ ALOGD("Softap driver stop: %d", ret);
return ret;
}
@@ -173,16 +173,16 @@
int ret = 0;
if (mPid) {
- LOGE("Softap already started");
+ ALOGE("Softap already started");
return 0;
}
if (mSock < 0) {
- LOGE("Softap startap - failed to open socket");
+ ALOGE("Softap startap - failed to open socket");
return -1;
}
#ifdef HAVE_HOSTAPD
if ((pid = fork()) < 0) {
- LOGE("fork failed (%s)", strerror(errno));
+ ALOGE("fork failed (%s)", strerror(errno));
return -1;
}
#endif
@@ -192,20 +192,20 @@
if (execl("/system/bin/hostapd", "/system/bin/hostapd",
"-e", WIFI_ENTROPY_FILE,
HOSTAPD_CONF_FILE, (char *) NULL)) {
- LOGE("execl failed (%s)", strerror(errno));
+ ALOGE("execl failed (%s)", strerror(errno));
}
#endif
- LOGE("Should never get here!");
+ ALOGE("Should never get here!");
return -1;
} else {
*mBuf = 0;
ret = setCommand(mIface, "AP_BSS_START");
if (ret) {
- LOGE("Softap startap - failed: %d", ret);
+ ALOGE("Softap startap - failed: %d", ret);
}
else {
mPid = pid;
- LOGD("Softap startap - Ok");
+ ALOGD("Softap startap - Ok");
usleep(AP_BSS_START_DELAY);
}
}
@@ -217,23 +217,23 @@
int ret;
if (mPid == 0) {
- LOGE("Softap already stopped");
+ ALOGE("Softap already stopped");
return 0;
}
#ifdef HAVE_HOSTAPD
- LOGD("Stopping Softap service");
+ ALOGD("Stopping Softap service");
kill(mPid, SIGTERM);
waitpid(mPid, NULL, 0);
#endif
if (mSock < 0) {
- LOGE("Softap stopap - failed to open socket");
+ ALOGE("Softap stopap - failed to open socket");
return -1;
}
*mBuf = 0;
ret = setCommand(mIface, "AP_BSS_STOP");
mPid = 0;
- LOGD("Softap service stopped: %d", ret);
+ ALOGD("Softap service stopped: %d", ret);
usleep(AP_BSS_STOP_DELAY);
return ret;
}
@@ -247,7 +247,7 @@
if (pos < 0)
return pos;
if ((unsigned)(pos + strlen(cmd) + strlen(arg) + 1) >= sizeof(mBuf)) {
- LOGE("Command line is too big");
+ ALOGE("Command line is too big");
return -1;
}
pos += sprintf(&mBuf[pos], "%s=%s,", cmd, arg);
@@ -271,11 +271,11 @@
char *ssid, *iface;
if (mSock < 0) {
- LOGE("Softap set - failed to open socket");
+ ALOGE("Softap set - failed to open socket");
return -1;
}
if (argc < 4) {
- LOGE("Softap set - missing arguments");
+ ALOGE("Softap set - missing arguments");
return -1;
}
@@ -293,7 +293,8 @@
}
asprintf(&wbuf, "interface=%s\ndriver=nl80211\nctrl_interface="
- "/data/misc/wifi/hostapd\nssid=%s\nchannel=6\n", iface, ssid);
+ "/data/misc/wifi/hostapd\nssid=%s\nchannel=6\nieee80211n=1\n",
+ iface, ssid);
if (argc > 5) {
if (!strcmp(argv[5], "wpa-psk")) {
@@ -311,13 +312,13 @@
fd = open(HOSTAPD_CONF_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0660);
if (fd < 0) {
- LOGE("Cannot update \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
+ ALOGE("Cannot update \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
free(wbuf);
free(fbuf);
return -1;
}
if (write(fd, fbuf, strlen(fbuf)) < 0) {
- LOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
+ ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
ret = -1;
}
close(fd);
@@ -326,14 +327,14 @@
/* Note: apparently open can fail to set permissions correctly at times */
if (chmod(HOSTAPD_CONF_FILE, 0660) < 0) {
- LOGE("Error changing permissions of %s to 0660: %s",
+ ALOGE("Error changing permissions of %s to 0660: %s",
HOSTAPD_CONF_FILE, strerror(errno));
unlink(HOSTAPD_CONF_FILE);
return -1;
}
if (chown(HOSTAPD_CONF_FILE, AID_SYSTEM, AID_WIFI) < 0) {
- LOGE("Error changing group ownership of %s to %d: %s",
+ ALOGE("Error changing group ownership of %s to %d: %s",
HOSTAPD_CONF_FILE, AID_WIFI, strerror(errno));
unlink(HOSTAPD_CONF_FILE);
return -1;
@@ -375,7 +376,7 @@
i = addParam(i, "MAX_SCB", "8");
}
if ((i < 0) || ((unsigned)(i + 4) >= sizeof(mBuf))) {
- LOGE("Softap set - command is too big");
+ ALOGE("Softap set - command is too big");
return i;
}
sprintf(&mBuf[i], "END");
@@ -383,10 +384,10 @@
/* system("iwpriv eth0 WL_AP_CFG ASCII_CMD=AP_CFG,SSID=\"AndroidAP\",SEC=\"open\",KEY=12345,CHANNEL=1,PREAMBLE=0,MAX_SCB=8,END"); */
ret = setCommand(iface, "AP_SET_CFG");
if (ret) {
- LOGE("Softap set - failed: %d", ret);
+ ALOGE("Softap set - failed: %d", ret);
}
else {
- LOGD("Softap set - Ok");
+ ALOGD("Softap set - Ok");
usleep(AP_SET_CFG_DELAY);
}
#endif
@@ -419,11 +420,11 @@
char *fwpath;
if (mSock < 0) {
- LOGE("Softap fwrealod - failed to open socket");
+ ALOGE("Softap fwrealod - failed to open socket");
return -1;
}
if (argc < 4) {
- LOGE("Softap fwreload - missing arguments");
+ ALOGE("Softap fwreload - missing arguments");
return -1;
}
@@ -445,10 +446,10 @@
ret = setCommand(iface, "WL_FW_RELOAD");
#endif
if (ret) {
- LOGE("Softap fwReload - failed: %d", ret);
+ ALOGE("Softap fwReload - failed: %d", ret);
}
else {
- LOGD("Softap fwReload - Ok");
+ ALOGD("Softap fwReload - Ok");
}
return ret;
}
@@ -458,16 +459,16 @@
int ret;
if (mSock < 0) {
- LOGE("Softap clients - failed to open socket");
+ ALOGE("Softap clients - failed to open socket");
return -1;
}
*mBuf = 0;
ret = setCommand(mIface, "AP_GET_STA_LIST", SOFTAP_MAX_BUFFER_SIZE);
if (ret) {
- LOGE("Softap clients - failed: %d", ret);
+ ALOGE("Softap clients - failed: %d", ret);
} else {
asprintf(retbuf, "Softap clients:%s", mBuf);
- LOGD("Softap clients:%s", mBuf);
+ ALOGD("Softap clients:%s", mBuf);
}
return ret;
}
diff --git a/SoftapController.h b/SoftapController.h
index 647b4fa..0d275d2 100644
--- a/SoftapController.h
+++ b/SoftapController.h
@@ -19,7 +19,6 @@
#include <linux/in.h>
#include <net/if.h>
-#include <utils/List.h>
#define SOFTAP_MAX_BUFFER_SIZE 4096
#define AP_BSS_START_DELAY 200000
diff --git a/TetherController.cpp b/TetherController.cpp
index 4f54c4d..8d14a14 100644
--- a/TetherController.cpp
+++ b/TetherController.cpp
@@ -53,7 +53,7 @@
int TetherController::setIpFwdEnabled(bool enable) {
- LOGD("Setting IP forward enable = %d", enable);
+ ALOGD("Setting IP forward enable = %d", enable);
// In BP tools mode, do not disable IP forwarding
char bootmode[PROPERTY_VALUE_MAX] = {0};
@@ -64,12 +64,12 @@
int fd = open("/proc/sys/net/ipv4/ip_forward", O_WRONLY);
if (fd < 0) {
- LOGE("Failed to open ip_forward (%s)", strerror(errno));
+ ALOGE("Failed to open ip_forward (%s)", strerror(errno));
return -1;
}
if (write(fd, (enable ? "1" : "0"), 1) != 1) {
- LOGE("Failed to write ip_forward (%s)", strerror(errno));
+ ALOGE("Failed to write ip_forward (%s)", strerror(errno));
close(fd);
return -1;
}
@@ -81,13 +81,13 @@
int fd = open("/proc/sys/net/ipv4/ip_forward", O_RDONLY);
if (fd < 0) {
- LOGE("Failed to open ip_forward (%s)", strerror(errno));
+ ALOGE("Failed to open ip_forward (%s)", strerror(errno));
return false;
}
char enabled;
if (read(fd, &enabled, 1) != 1) {
- LOGE("Failed to read ip_forward (%s)", strerror(errno));
+ ALOGE("Failed to read ip_forward (%s)", strerror(errno));
close(fd);
return -1;
}
@@ -98,18 +98,18 @@
int TetherController::startTethering(int num_addrs, struct in_addr* addrs) {
if (mDaemonPid != 0) {
- LOGE("Tethering already started");
+ ALOGE("Tethering already started");
errno = EBUSY;
return -1;
}
- LOGD("Starting tethering services");
+ ALOGD("Starting tethering services");
pid_t pid;
int pipefd[2];
if (pipe(pipefd) < 0) {
- LOGE("pipe failed (%s)", strerror(errno));
+ ALOGE("pipe failed (%s)", strerror(errno));
return -1;
}
@@ -118,7 +118,7 @@
* the daemon if it exits prematurely
*/
if ((pid = fork()) < 0) {
- LOGE("fork failed (%s)", strerror(errno));
+ ALOGE("fork failed (%s)", strerror(errno));
close(pipefd[0]);
close(pipefd[1]);
return -1;
@@ -128,23 +128,25 @@
close(pipefd[1]);
if (pipefd[0] != STDIN_FILENO) {
if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
- LOGE("dup2 failed (%s)", strerror(errno));
+ ALOGE("dup2 failed (%s)", strerror(errno));
return -1;
}
close(pipefd[0]);
}
- int num_processed_args = 6 + (num_addrs/2) + 1; // 1 null for termination
+ int num_processed_args = 7 + (num_addrs/2) + 1; // 1 null for termination
char **args = (char **)malloc(sizeof(char *) * num_processed_args);
args[num_processed_args - 1] = NULL;
args[0] = (char *)"/system/bin/dnsmasq";
args[1] = (char *)"--keep-in-foreground";
args[2] = (char *)"--no-resolv";
args[3] = (char *)"--no-poll";
- args[4] = (char *)"--pid-file";
- args[5] = (char *)"";
+ // TODO: pipe through metered status from ConnService
+ args[4] = (char *)"--dhcp-option-force=43,ANDROID_METERED";
+ args[5] = (char *)"--pid-file";
+ args[6] = (char *)"";
- int nextArg = 6;
+ int nextArg = 7;
for (int addrIndex=0; addrIndex < num_addrs;) {
char *start = strdup(inet_ntoa(addrs[addrIndex++]));
char *end = strdup(inet_ntoa(addrs[addrIndex++]));
@@ -152,16 +154,16 @@
}
if (execv(args[0], args)) {
- LOGE("execl failed (%s)", strerror(errno));
+ ALOGE("execl failed (%s)", strerror(errno));
}
- LOGE("Should never get here!");
+ ALOGE("Should never get here!");
free(args);
return 0;
} else {
close(pipefd[0]);
mDaemonPid = pid;
mDaemonFd = pipefd[1];
- LOGD("Tethering services running");
+ ALOGD("Tethering services running");
}
return 0;
@@ -170,18 +172,18 @@
int TetherController::stopTethering() {
if (mDaemonPid == 0) {
- LOGE("Tethering already stopped");
+ ALOGE("Tethering already stopped");
return 0;
}
- LOGD("Stopping tethering services");
+ ALOGD("Stopping tethering services");
kill(mDaemonPid, SIGTERM);
waitpid(mDaemonPid, NULL, 0);
mDaemonPid = 0;
close(mDaemonFd);
mDaemonFd = -1;
- LOGD("Tethering services stopped");
+ ALOGD("Tethering services stopped");
return 0;
}
@@ -200,19 +202,19 @@
mDnsForwarders->clear();
for (i = 0; i < numServers; i++) {
- LOGD("setDnsForwarders(%d = '%s')", i, servers[i]);
+ ALOGD("setDnsForwarders(%d = '%s')", i, servers[i]);
struct in_addr a;
if (!inet_aton(servers[i], &a)) {
- LOGE("Failed to parse DNS server '%s'", servers[i]);
+ ALOGE("Failed to parse DNS server '%s'", servers[i]);
mDnsForwarders->clear();
return -1;
}
cmdLen += strlen(servers[i]);
if (cmdLen + 2 >= MAX_CMD_SIZE) {
- LOGD("Too many DNS servers listed");
+ ALOGD("Too many DNS servers listed");
break;
}
@@ -222,9 +224,9 @@
}
if (mDaemonFd != -1) {
- LOGD("Sending update msg to dnsmasq [%s]", daemonCmd);
+ ALOGD("Sending update msg to dnsmasq [%s]", daemonCmd);
if (write(mDaemonFd, daemonCmd, strlen(daemonCmd) +1) < 0) {
- LOGE("Failed to send update command to dnsmasq (%s)", strerror(errno));
+ ALOGE("Failed to send update command to dnsmasq (%s)", strerror(errno));
mDnsForwarders->clear();
return -1;
}
diff --git a/TetherController.h b/TetherController.h
index 1fd4f95..eef94fe 100644
--- a/TetherController.h
+++ b/TetherController.h
@@ -19,10 +19,10 @@
#include <linux/in.h>
-#include <utils/List.h>
+#include "List.h"
-typedef android::List<char *> InterfaceCollection;
-typedef android::List<struct in_addr> NetAddressCollection;
+typedef android::netd::List<char *> InterfaceCollection;
+typedef android::netd::List<struct in_addr> NetAddressCollection;
class TetherController {
InterfaceCollection *mInterfaces;
diff --git a/ThrottleController.cpp b/ThrottleController.cpp
index 1ae31b8..5bd7ad5 100644
--- a/ThrottleController.cpp
+++ b/ThrottleController.cpp
@@ -33,8 +33,7 @@
#include "ThrottleController.h"
-
-static char TC_PATH[] = "/system/bin/tc";
+#include "NetdConstants.h"
extern "C" int system_nosh(const char *command);
extern "C" int ifc_init(void);
@@ -47,7 +46,7 @@
int res;
if (len == 255) {
- LOGE("tc command too long");
+ ALOGE("tc command too long");
errno = E2BIG;
return -1;
}
@@ -82,7 +81,7 @@
*/
sprintf(cmd, "qdisc add dev %s root handle 1: htb default 1 r2q 1000", ifn);
if (runTcCmd(cmd)) {
- LOGE("Failed to add root qdisc (%s)", strerror(errno));
+ ALOGE("Failed to add root qdisc (%s)", strerror(errno));
goto fail;
}
@@ -91,7 +90,7 @@
*/
sprintf(cmd, "class add dev %s parent 1: classid 1:1 htb rate %dkbit", ifn, txKbps);
if (runTcCmd(cmd)) {
- LOGE("Failed to add egress throttling class (%s)", strerror(errno));
+ ALOGE("Failed to add egress throttling class (%s)", strerror(errno));
goto fail;
}
@@ -100,7 +99,7 @@
*/
ifc_init();
if (ifc_up("ifb0")) {
- LOGE("Failed to up ifb0 (%s)", strerror(errno));
+ ALOGE("Failed to up ifb0 (%s)", strerror(errno));
goto fail;
}
@@ -109,7 +108,7 @@
*/
sprintf(cmd, "qdisc add dev ifb0 root handle 1: htb default 1 r2q 1000");
if (runTcCmd(cmd)) {
- LOGE("Failed to add root ifb qdisc (%s)", strerror(errno));
+ ALOGE("Failed to add root ifb qdisc (%s)", strerror(errno));
goto fail;
}
@@ -118,7 +117,7 @@
*/
sprintf(cmd, "class add dev ifb0 parent 1: classid 1:1 htb rate %dkbit", rxKbps);
if (runTcCmd(cmd)) {
- LOGE("Failed to add ingress throttling class (%s)", strerror(errno));
+ ALOGE("Failed to add ingress throttling class (%s)", strerror(errno));
goto fail;
}
@@ -127,7 +126,7 @@
*/
sprintf(cmd, "qdisc add dev %s ingress", ifn);
if (runTcCmd(cmd)) {
- LOGE("Failed to add ingress qdisc (%s)", strerror(errno));
+ ALOGE("Failed to add ingress qdisc (%s)", strerror(errno));
goto fail;
}
@@ -137,7 +136,7 @@
sprintf(cmd, "filter add dev %s parent ffff: protocol ip prio 10 u32 match "
"u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0", ifn);
if (runTcCmd(cmd)) {
- LOGE("Failed to add ifb filter (%s)", strerror(errno));
+ ALOGE("Failed to add ifb filter (%s)", strerror(errno));
goto fail;
}
diff --git a/logwrapper.c b/logwrapper.c
index 3601b70..f5f4548 100644
--- a/logwrapper.c
+++ b/logwrapper.c
@@ -43,7 +43,7 @@
} else if (buffer[b] == '\n') {
buffer[b] = '\0';
- LOG(LOG_INFO, tag, "%s", &buffer[a]);
+ ALOG(LOG_INFO, tag, "%s", &buffer[a]);
a = b + 1;
}
}
@@ -51,7 +51,7 @@
if (a == 0 && b == sizeof(buffer) - 1) {
// buffer is full, flush
buffer[b] = '\0';
- LOG(LOG_INFO, tag, "%s", &buffer[a]);
+ ALOG(LOG_INFO, tag, "%s", &buffer[a]);
b = 0;
} else if (a != b) {
// Keep left-overs
@@ -67,24 +67,24 @@
// Flush remaining data
if (a != b) {
buffer[b] = '\0';
- LOG(LOG_INFO, tag, "%s", &buffer[a]);
+ ALOG(LOG_INFO, tag, "%s", &buffer[a]);
}
status = 0xAAAA;
if (wait(&status) != -1) { // Wait for child
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != 0) {
- LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
+ ALOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
WEXITSTATUS(status));
}
return WEXITSTATUS(status);
} else if (WIFSIGNALED(status))
- LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
+ ALOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
WTERMSIG(status));
else if (WIFSTOPPED(status))
- LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
+ ALOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
WSTOPSIG(status));
} else
- LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
+ ALOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
strerror(errno), errno);
return -EAGAIN;
}
@@ -97,13 +97,13 @@
// XXX: PROTECT FROM VIKING KILLER
if (execv(argv_child[0], argv_child)) {
- LOG(LOG_ERROR, "logwrapper",
+ ALOG(LOG_ERROR, "logwrapper",
"executing %s failed: %s", argv_child[0], strerror(errno));
}
_exit(1);
}
-int logwrap(int argc, const char* argv[], int background)
+int logwrap(int argc, const char* argv[])
{
pid_t pid;
@@ -114,21 +114,21 @@
/* Use ptty instead of socketpair so that STDOUT is not buffered */
parent_ptty = open("/dev/ptmx", O_RDWR);
if (parent_ptty < 0) {
- LOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty");
- return -errno;
+ ALOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty");
+ return -errno;
}
if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
ptsname_r(parent_ptty, child_devname, sizeof(child_devname))) {
close(parent_ptty);
- LOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx");
- return -1;
+ ALOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx");
+ return -1;
}
pid = fork();
if (pid < 0) {
close(parent_ptty);
- LOG(LOG_ERROR, "logwrapper", "Failed to fork");
+ ALOG(LOG_ERROR, "logwrapper", "Failed to fork");
return -errno;
} else if (pid == 0) {
/*
@@ -137,7 +137,7 @@
child_ptty = open(child_devname, O_RDWR);
if (child_ptty < 0) {
close(parent_ptty);
- LOG(LOG_ERROR, "logwrapper", "Problem with child ptty");
+ ALOG(LOG_ERROR, "logwrapper", "Problem with child ptty");
_exit(errno < 128 ? errno : 1); // XXX lame
}
@@ -147,22 +147,6 @@
dup2(child_ptty, 2);
close(child_ptty);
- if (background) {
- int fd = open("/dev/cpuctl/bg_non_interactive/tasks", O_WRONLY);
- if (fd >= 0) {
- char text[64];
- sprintf(text, "%d", getpid());
- if (write(fd, text, strlen(text)) < 0) {
- LOG(LOG_WARN, "logwrapper",
- "Unable to background process (%s)", strerror(errno));
- }
- close(fd);
- } else {
- LOG(LOG_WARN, "logwrapper",
- "Unable to background process (%s)", strerror(errno));
- }
- }
-
child(argc, argv);
} else {
/*
@@ -201,7 +185,7 @@
* reverted in Change: 11b4e9b2
*/
if (strnlen(command, sizeof(buffer) - 1) == sizeof(buffer) - 1) {
- LOGE("command line too long while processing: %s", command);
+ ALOGE("command line too long while processing: %s", command);
errno = E2BIG;
return -1;
}
@@ -209,7 +193,7 @@
while ((tmp = strsep(&next, " "))) {
argp[i++] = tmp;
if (i == 32) {
- LOGE("argument overflow while processing: %s", command);
+ ALOGE("argument overflow while processing: %s", command);
errno = E2BIG;
return -1;
}
diff --git a/main.cpp b/main.cpp
index 36712a4..b466e42 100644
--- a/main.cpp
+++ b/main.cpp
@@ -33,22 +33,26 @@
#include "CommandListener.h"
#include "NetlinkManager.h"
#include "DnsProxyListener.h"
+#include "MDnsSdListener.h"
static void coldboot(const char *path);
static void sigchld_handler(int sig);
+static void blockSigpipe();
int main() {
CommandListener *cl;
NetlinkManager *nm;
DnsProxyListener *dpl;
+ MDnsSdListener *mdnsl;
- LOGI("Netd 1.0 starting");
+ ALOGI("Netd 1.0 starting");
// signal(SIGCHLD, sigchld_handler);
+ blockSigpipe();
if (!(nm = NetlinkManager::Instance())) {
- LOGE("Unable to create NetlinkManager");
+ ALOGE("Unable to create NetlinkManager");
exit(1);
};
@@ -57,7 +61,7 @@
nm->setBroadcaster((SocketListener *) cl);
if (nm->start()) {
- LOGE("Unable to start NetlinkManager (%s)", strerror(errno));
+ ALOGE("Unable to start NetlinkManager (%s)", strerror(errno));
exit(1);
}
@@ -66,15 +70,20 @@
setenv("ANDROID_DNS_MODE", "local", 1);
dpl = new DnsProxyListener();
if (dpl->startListener()) {
- LOGE("Unable to start DnsProxyListener (%s)", strerror(errno));
+ ALOGE("Unable to start DnsProxyListener (%s)", strerror(errno));
exit(1);
}
+ mdnsl = new MDnsSdListener();
+ if (mdnsl->startListener()) {
+ ALOGE("Unable to start MDnsSdListener (%s)", strerror(errno));
+ exit(1);
+ }
/*
* Now that we're up, we can respond to commands
*/
if (cl->startListener()) {
- LOGE("Unable to start CommandListener (%s)", strerror(errno));
+ ALOGE("Unable to start CommandListener (%s)", strerror(errno));
exit(1);
}
@@ -83,7 +92,7 @@
sleep(1000);
}
- LOGI("Netd exiting");
+ ALOGI("Netd exiting");
exit(0);
}
@@ -134,5 +143,15 @@
static void sigchld_handler(int sig) {
pid_t pid = wait(NULL);
- LOGD("Child process %d exited", pid);
+ ALOGD("Child process %d exited", pid);
+}
+
+static void blockSigpipe()
+{
+ sigset_t mask;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGPIPE);
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) != 0)
+ ALOGW("WARNING: SIGPIPE not blocked\n");
}
diff --git a/ndc.c b/ndc.c
index a828f9b..17750bd 100644
--- a/ndc.c
+++ b/ndc.c
@@ -37,24 +37,35 @@
int main(int argc, char **argv) {
int sock;
+ int cmdOffset = 0;
if (argc < 2)
usage(argv[0]);
- if ((sock = socket_local_client("netd",
+ // try interpreting the first arg as the socket name - if it fails go back to netd
+
+ if ((sock = socket_local_client(argv[1],
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM)) < 0) {
- fprintf(stderr, "Error connecting (%s)\n", strerror(errno));
- exit(4);
+ if ((sock = socket_local_client("netd",
+ ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM)) < 0) {
+ fprintf(stderr, "Error connecting (%s)\n", strerror(errno));
+ exit(4);
+ }
+ } else {
+ if (argc < 3) usage(argv[0]);
+ printf("Using alt socket %s\n", argv[1]);
+ cmdOffset = 1;
}
- if (!strcmp(argv[1], "monitor"))
+ if (!strcmp(argv[1+cmdOffset], "monitor"))
exit(do_monitor(sock, 0));
- exit(do_cmd(sock, argc, argv));
+ exit(do_cmd(sock, argc-cmdOffset, &(argv[cmdOffset])));
}
static int do_cmd(int sock, int argc, char **argv) {
- char final_cmd[255] = { '\0' };
+ char final_cmd[255] = { '0', ' ', '\0' };
int i;
for (i = 1; i < argc; i++) {
@@ -114,7 +125,7 @@
return ECONNRESET;
return errno;
}
-
+
int offset = 0;
int i = 0;
@@ -142,7 +153,6 @@
}
static void usage(char *progname) {
- fprintf(stderr, "Usage: %s <monitor>|<cmd> [arg1] [arg2...]\n", progname);
+ fprintf(stderr, "Usage: %s [sockname] <monitor>|<cmd> [arg1] [arg2...]\n", progname);
exit(1);
}
-
diff --git a/oem_iptables_hook.cpp b/oem_iptables_hook.cpp
index e50ea6a..d3026a9 100644
--- a/oem_iptables_hook.cpp
+++ b/oem_iptables_hook.cpp
@@ -24,11 +24,10 @@
#define LOG_TAG "OemIptablesHook"
#include <cutils/log.h>
+#include "NetdConstants.h"
extern "C" int system_nosh(const char *command);
-static char IPTABLES_PATH[] = "/system/bin/iptables";
-static char OEM_SCRIPT_PATH[] = "/system/bin/oem-iptables-init.sh";
static int runIptablesCmd(const char *cmd) {
char *buffer;
@@ -36,7 +35,7 @@
int res;
if (len == 255) {
- LOGE("command too long");
+ ALOGE("command too long");
return -1;
}
@@ -94,7 +93,7 @@
static bool oemInitChains() {
int ret = system(OEM_SCRIPT_PATH);
if ((-1 == ret) || (0 != WEXITSTATUS(ret))) {
- LOGE("%s failed: %s", OEM_SCRIPT_PATH, strerror(errno));
+ ALOGE("%s failed: %s", OEM_SCRIPT_PATH, strerror(errno));
oemCleanupHooks();
return false;
}
@@ -108,7 +107,7 @@
// but is needed for the case where netd has crashed/stopped and is
// restarted.
if (oemCleanupHooks() && oemSetupHooks() && oemInitChains()) {
- LOGI("OEM iptable hook installed.");
+ ALOGI("OEM iptable hook installed.");
}
}
}