netd: BandwidthController: support reading out tethering stats
* Add
ndc bandwidth gettetherstats <ifaceIn> <ifaceOut>
which returns
221 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
If the iface pair is not found it will fail.
221 is the new response code for TetheringStatsResult.
It gets the stats by looking at the iptables FORWARD chain's counters.
* Fixed return handling after some of the responses.
- no need for errorno
- after ResponseCode >= 200, don't return another.
* Correctly initialize the alert values on "bandwidth enable"
Bug: 5244846,5230066
Change-Id: I81c941441525fa4055ae270d5cad05e6c42b8f72
diff --git a/BandwidthController.cpp b/BandwidthController.cpp
index ed32d3d..1761145 100644
--- a/BandwidthController.cpp
+++ b/BandwidthController.cpp
@@ -14,8 +14,17 @@
* limitations under the License.
*/
+// #define LOG_NDEBUG 0
+
+/*
+ * The CommandListener, FrameworkListener don't allow for
+ * multiple calls in parallel to reach the BandwidthController.
+ * If they ever were to allow it, then netd/ would need some tweaking.
+ */
+
#include <errno.h>
#include <fcntl.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -36,13 +45,16 @@
#include "BandwidthController.h"
-const int BandwidthController::MAX_CMD_LEN = 1024;
-const int BandwidthController::MAX_IFACENAME_LEN = 64;
-const int BandwidthController::MAX_CMD_ARGS = 32;
-const char BandwidthController::IPTABLES_PATH[] = "/system/bin/iptables";
-const char BandwidthController::IP6TABLES_PATH[] = "/system/bin/ip6tables";
+/* Alphabetical */
const char BandwidthController::ALERT_IPT_TEMPLATE[] = "%s %s %s -m quota2 ! --quota %lld --name %s";
-const int BandwidthController::ALERT_RULE_POS_IN_COSTLY_CHAIN = 4;
+const int BandwidthController::ALERT_RULE_POS_IN_COSTLY_CHAIN = 4;
+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;
+const int BandwidthController::MAX_IPT_OUTPUT_LINE_LEN = 256;
+
bool BandwidthController::useLogwrapCall = false;
/**
@@ -83,7 +95,7 @@
* iptables -A penalty_box -m owner --uid-owner app_3 \
* --jump REJECT --reject-with icmp-net-prohibited
*/
-const char *BandwidthController::cleanupCommands[] = {
+const char *BandwidthController::IPT_CLEANUP_COMMANDS[] = {
/* Cleanup rules. */
"-F",
"-t raw -F",
@@ -93,13 +105,13 @@
"-X", /* Should normally only be costly_shared, penalty_box, and costly_<iface> */
};
-const char *BandwidthController::setupCommands[] = {
+const char *BandwidthController::IPT_SETUP_COMMANDS[] = {
/* Created needed chains. */
"-N costly_shared",
"-N penalty_box",
};
-const char *BandwidthController::basicAccountingCommands[] = {
+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. */
@@ -132,7 +144,7 @@
int BandwidthController::runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling) {
int res = 0;
- LOGD("runIpxtablesCmd(cmd=%s)", cmd);
+ LOGV("runIpxtablesCmd(cmd=%s)", cmd);
res |= runIptablesCmd(cmd, rejectHandling, IptIpV4);
res |= runIptablesCmd(cmd, rejectHandling, IptIpV6);
return res;
@@ -199,31 +211,38 @@
int BandwidthController::enableBandwidthControl(void) {
int res;
- /* Some of the initialCommands are allowed to fail */
- runCommands(sizeof(cleanupCommands) / sizeof(char*), cleanupCommands, RunCmdFailureOk);
- runCommands(sizeof(setupCommands) / sizeof(char*), setupCommands, RunCmdFailureOk);
- res = runCommands(sizeof(basicAccountingCommands) / sizeof(char*), basicAccountingCommands,
- RunCmdFailureBad);
- sharedQuotaBytes = sharedAlertBytes = 0;
+ /* Let's pretend we started from scratch ... */
sharedQuotaIfaces.clear();
quotaIfaces.clear();
naughtyAppUids.clear();
+ globalAlertBytes = 0;
+ sharedQuotaBytes = sharedAlertBytes = 0;
+
+
+ /* 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*),
+ IPT_BASIC_ACCOUNTING_COMMANDS, RunCmdFailureBad);
return res;
}
int BandwidthController::disableBandwidthControl(void) {
- /* The cleanupCommands are allowed to fail. */
- runCommands(sizeof(cleanupCommands) / sizeof(char*), cleanupCommands, RunCmdFailureOk);
+ /* The IPT_CLEANUP_COMMANDS are allowed to fail. */
+ runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
+ IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
return 0;
}
int BandwidthController::runCommands(int numCommands, const char *commands[],
RunCmdErrHandling cmdErrHandling) {
int res = 0;
- LOGD("runCommands(): %d commands", numCommands);
+ LOGV("runCommands(): %d commands", numCommands);
for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
res = runIpxtablesCmd(commands[cmdNum], IptRejectNoAdd);
if (res && cmdErrHandling != RunCmdFailureBad)
@@ -312,7 +331,7 @@
char *buff;
const char *opFlag;
- LOGD("makeIptablesQuotaCmd(%d, %lld)", op, quota);
+ LOGV("makeIptablesQuotaCmd(%d, %lld)", op, quota);
switch (op) {
case IptOpInsert:
@@ -593,7 +612,7 @@
return -1;
}
scanRes = fscanf(fp, "%lld", bytes);
- LOGD("Read quota res=%d bytes=%lld", scanRes, *bytes);
+ LOGV("Read quota res=%d bytes=%lld", scanRes, *bytes);
fclose(fp);
return scanRes == 1 ? 0 : -1;
}
@@ -812,3 +831,86 @@
free(alertName);
return res;
}
+
+/*
+ * Parse the ptks and bytes out of:
+ * Chain FORWARD (policy ACCEPT 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 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
+ *
+ */
+int BandwidthController::parseForwardChainStats(TetherStats &stats, FILE *fp) {
+ int res;
+ char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
+ char iface0[MAX_IPT_OUTPUT_LINE_LEN];
+ char iface1[MAX_IPT_OUTPUT_LINE_LEN];
+ char rest[MAX_IPT_OUTPUT_LINE_LEN];
+
+ char *buffPtr;
+ int64_t packets, bytes;
+
+ 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",
+ &packets, &bytes, iface0, iface1, rest);
+ LOGV("parse res=%d iface0=<%s> iface1=<%s> pkts=%lld bytes=%lld rest=<%s> orig line=<%s>", res,
+ iface0, iface1, packets, bytes, rest, 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);
+ 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);
+ stats.txPackets = packets;
+ stats.txBytes = bytes;
+ }
+ }
+ /* Failure if rx or tx was not found */
+ return (stats.rxBytes == -1 || stats.txBytes == -1) ? -1 : 0;
+}
+
+
+char *BandwidthController::TetherStats::getStatsLine(void) {
+ char *msg;
+ asprintf(&msg, "%s %s %lld %lld %lld %lld", ifaceIn.c_str(), ifaceOut.c_str(),
+ rxBytes, rxPackets, txBytes, txPackets);
+ return msg;
+}
+
+int BandwidthController::getTetherStats(TetherStats &stats) {
+ 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.");
+ return -1;
+ }
+
+ /*
+ * Why not use some kind of lib to talk to iptables?
+ * Because the only libs are libiptc and libip6tc in iptables, and they are
+ * not easy to use. They require the known iptables match modules to be
+ * preloaded/linked, and require apparently a lot of wrapper code to get
+ * the wanted info.
+ */
+ fullCmd = IPTABLES_PATH;
+ fullCmd += " -nvx -L FORWARD";
+ iptOutput = popen(fullCmd.c_str(), "r");
+ if (!iptOutput) {
+ LOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
+ return -1;
+ }
+ res = parseForwardChainStats(stats, iptOutput);
+ pclose(iptOutput);
+
+ /* Currently NatController doesn't do ipv6 tethering, so we are done. */
+ return res;
+}
diff --git a/BandwidthController.h b/BandwidthController.h
index 3e45d40..401609f 100644
--- a/BandwidthController.h
+++ b/BandwidthController.h
@@ -19,8 +19,32 @@
#include <list>
#include <string>
#include <utility> // for pair
+
class BandwidthController {
public:
+ class TetherStats {
+ public:
+ TetherStats(void)
+ : rxBytes(-1), rxPackets(-1),
+ txBytes(-1), txPackets(-1) {};
+ TetherStats(std::string ifnIn, std::string ifnOut,
+ int64_t rxB, int64_t rxP,
+ int64_t txB, int64_t txP)
+ : ifaceIn(ifnIn), ifaceOut(ifnOut),
+ rxBytes(rxB), rxPackets(rxP),
+ txBytes(txB), txPackets(txP) {};
+ std::string ifaceIn;
+ std::string ifaceOut;
+ int64_t rxBytes, rxPackets;
+ int64_t txBytes, txPackets;
+ /*
+ * Allocates a new string representing this:
+ * ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
+ * The caller is responsible for free()'ing the returned ptr.
+ */
+ char *getStatsLine(void);
+ };
+
BandwidthController();
int enableBandwidthControl(void);
int disableBandwidthControl(void);
@@ -45,6 +69,12 @@
int setInterfaceAlert(const char *iface, int64_t bytes);
int removeInterfaceAlert(const char *iface);
+ /*
+ * stats should have ifaceIn and ifaceOut initialized.
+ * Byte counts should be left to the default (-1).
+ */
+ int getTetherStats(TetherStats &stats);
+
protected:
class QuotaInfo {
public:
@@ -54,6 +84,7 @@
int64_t quota;
int64_t alert;
};
+
enum IptIpVer { IptIpV4, IptIpV6 };
enum IptOp { IptOpInsert, IptOpReplace, IptOpDelete };
enum IptRejectOp { IptRejectAdd, IptRejectNoAdd };
@@ -61,13 +92,6 @@
enum QuotaType { QuotaUnique, QuotaShared };
enum RunCmdErrHandling { RunCmdFailureBad, RunCmdFailureOk };
- std::list<std::string> sharedQuotaIfaces;
- int64_t sharedQuotaBytes;
- int64_t sharedAlertBytes;
-
- std::list<QuotaInfo> quotaIfaces;
-
- std::list<int /*appUid*/> naughtyAppUids;
int maninpulateNaughtyApps(int numUids, char *appStrUids[], NaughtyAppOp appOp);
int prepCostlyIface(const char *ifn, QuotaType quotaType);
@@ -89,26 +113,43 @@
int updateQuota(const char *alertName, int64_t bytes);
- int64_t globalAlertBytes;
int setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes);
int removeCostlyAlert(const char *costName, int64_t *alertBytes);
/*
+ * stats should have ifaceIn and ifaceOut initialized.
+ * fp should be a file to the FORWARD rules of iptables.
+ */
+ static int parseForwardChainStats(TetherStats &stats, FILE *fp);
+
+ /*------------------*/
+
+ std::list<std::string> sharedQuotaIfaces;
+ int64_t sharedQuotaBytes;
+ int64_t sharedAlertBytes;
+ int64_t globalAlertBytes;
+ std::list<QuotaInfo> quotaIfaces;
+ std::list<int /*appUid*/> naughtyAppUids;
+
+private:
+ 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 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;
+ static const int MAX_IPT_OUTPUT_LINE_LEN;
+
+ /*
* When false, it will directly use system() instead of logwrap()
*/
static bool useLogwrapCall;
-
-private:
- static const char *cleanupCommands[];
- static const char *setupCommands[];
- static const char *basicAccountingCommands[];
- static const int MAX_CMD_LEN;
- static const int MAX_IFACENAME_LEN;
- static const int MAX_CMD_ARGS;
- static const char IPTABLES_PATH[];
- static const char IP6TABLES_PATH[];
- static const char ALERT_IPT_TEMPLATE[];
- static const int ALERT_RULE_POS_IN_COSTLY_CHAIN;
};
#endif
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 204565b..d11e34f 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+// #define LOG_NDEBUG 0
+
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
@@ -847,75 +849,109 @@
NetdCommand("bandwidth") {
}
+void CommandListener::BandwidthControlCmd::sendGenericSyntaxError(SocketClient *cli, const char *usageMsg) {
+ char *msg;
+ asprintf(&msg, "Usage: bandwidth %s", usageMsg);
+ cli->sendMsg(ResponseCode::CommandSyntaxError, msg, false);
+ free(msg);
+}
+
+void CommandListener::BandwidthControlCmd::sendGenericOkFail(SocketClient *cli, int cond) {
+ if (!cond) {
+ cli->sendMsg(ResponseCode::CommandOkay, "Bandwidth command succeeeded", false);
+ } else {
+ cli->sendMsg(ResponseCode::OperationFailed, "Bandwidth command failed", false);
+ }
+}
+
+void CommandListener::BandwidthControlCmd::sendGenericOpFailed(SocketClient *cli, const char *errMsg) {
+ cli->sendMsg(ResponseCode::OperationFailed, errMsg, false);
+}
+
int CommandListener::BandwidthControlCmd::runCommand(SocketClient *cli, int argc, char **argv) {
- int rc = 0;
- LOGD("bwctrlcmd: argc=%d argv[0]=%s", argc, argv[0]);
if (argc < 2) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+ sendGenericSyntaxError(cli, "<cmds> <args...>");
return 0;
}
- if (!strcmp(argv[1], "enable")) {
- rc = sBandwidthCtrl->enableBandwidthControl();
- } else if (!strcmp(argv[1], "disable")) {
- rc = sBandwidthCtrl->disableBandwidthControl();
+ LOGV("bwctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
- } else if (!strcmp(argv[1], "removequota") || !strcmp(argv[1], "rq")) {
+ if (!strcmp(argv[1], "enable")) {
+ int rc = sBandwidthCtrl->enableBandwidthControl();
+ sendGenericOkFail(cli, rc);
+ return 0;
+
+ }
+ if (!strcmp(argv[1], "disable")) {
+ int rc = sBandwidthCtrl->disableBandwidthControl();
+ sendGenericOkFail(cli, rc);
+ return 0;
+
+ }
+ if (!strcmp(argv[1], "removequota") || !strcmp(argv[1], "rq")) {
if (argc != 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth removequota <interface>", false);
+ sendGenericSyntaxError(cli, "removequota <interface>");
return 0;
}
- rc = sBandwidthCtrl->removeInterfaceSharedQuota(argv[2]);
+ int rc = sBandwidthCtrl->removeInterfaceSharedQuota(argv[2]);
+ sendGenericOkFail(cli, rc);
+ return 0;
- } else if (!strcmp(argv[1], "getquota") || !strcmp(argv[1], "gq")) {
+ }
+ if (!strcmp(argv[1], "getquota") || !strcmp(argv[1], "gq")) {
int64_t bytes;
if (argc != 2) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth getquota", false);
+ sendGenericSyntaxError(cli, "getquota");
return 0;
}
- rc = sBandwidthCtrl->getInterfaceSharedQuota(&bytes);
+ int rc = sBandwidthCtrl->getInterfaceSharedQuota(&bytes);
if (rc) {
- cli->sendMsg(ResponseCode::OperationFailed, "Failed to get quota", true);
+ sendGenericOpFailed(cli, "Failed to get quota");
return 0;
}
+
char *msg;
asprintf(&msg, "%lld", bytes);
cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false);
free(msg);
+ return 0;
- } else if (!strcmp(argv[1], "getiquota") || !strcmp(argv[1], "giq")) {
+ }
+ if (!strcmp(argv[1], "getiquota") || !strcmp(argv[1], "giq")) {
int64_t bytes;
if (argc != 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth getiquota <iface>", false);
+ sendGenericSyntaxError(cli, "getiquota <iface>");
return 0;
}
- rc = sBandwidthCtrl->getInterfaceQuota(argv[2], &bytes);
+
+ int rc = sBandwidthCtrl->getInterfaceQuota(argv[2], &bytes);
if (rc) {
- cli->sendMsg(ResponseCode::OperationFailed, "Failed to get quota", true);
+ sendGenericOpFailed(cli, "Failed to get quota");
return 0;
}
char *msg;
asprintf(&msg, "%lld", bytes);
cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false);
free(msg);
+ return 0;
- } else if (!strcmp(argv[1], "setquota") || !strcmp(argv[1], "sq")) {
+ }
+ if (!strcmp(argv[1], "setquota") || !strcmp(argv[1], "sq")) {
if (argc != 4) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth setquota <interface> <bytes>", false);
+ sendGenericSyntaxError(cli, "setquota <interface> <bytes>");
return 0;
}
- rc = sBandwidthCtrl->setInterfaceSharedQuota(argv[2], atoll(argv[3]));
-
- } else if (!strcmp(argv[1], "setquotas") || !strcmp(argv[1], "sqs")) {
+ int rc = sBandwidthCtrl->setInterfaceSharedQuota(argv[2], atoll(argv[3]));
+ sendGenericOkFail(cli, rc);
+ return 0;
+ }
+ if (!strcmp(argv[1], "setquotas") || !strcmp(argv[1], "sqs")) {
+ int rc;
if (argc < 4) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth setquotas <bytes> <interface> ...", false);
+ sendGenericSyntaxError(cli, "setquotas <bytes> <interface> ...");
return 0;
}
+
for (int q = 3; argc >= 4; q++, argc--) {
rc = sBandwidthCtrl->setInterfaceSharedQuota(argv[q], atoll(argv[2]));
if (rc) {
@@ -924,16 +960,20 @@
cli->sendMsg(ResponseCode::OperationFailed,
msg, false);
free(msg);
- break;
+ return 0;
}
}
+ sendGenericOkFail(cli, rc);
+ return 0;
- } else if (!strcmp(argv[1], "removequotas") || !strcmp(argv[1], "rqs")) {
+ }
+ if (!strcmp(argv[1], "removequotas") || !strcmp(argv[1], "rqs")) {
+ int rc;
if (argc < 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth removequotas <interface> ...", false);
+ sendGenericSyntaxError(cli, "removequotas <interface> ...");
return 0;
}
+
for (int q = 2; argc >= 3; q++, argc--) {
rc = sBandwidthCtrl->removeInterfaceSharedQuota(argv[q]);
if (rc) {
@@ -942,99 +982,136 @@
cli->sendMsg(ResponseCode::OperationFailed,
msg, false);
free(msg);
- break;
+ return 0;
}
}
-
- } else if (!strcmp(argv[1], "removeiquota") || !strcmp(argv[1], "riq")) {
- if (argc != 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth removeiquota <interface>", false);
- return 0;
- }
- rc = sBandwidthCtrl->removeInterfaceQuota(argv[2]);
-
- } else if (!strcmp(argv[1], "setiquota") || !strcmp(argv[1], "siq")) {
- if (argc != 4) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth setiquota <interface> <bytes>", false);
- return 0;
- }
- rc = sBandwidthCtrl->setInterfaceQuota(argv[2], atoll(argv[3]));
-
- } else if (!strcmp(argv[1], "addnaughtyapps") || !strcmp(argv[1], "ana")) {
- if (argc < 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth addnaughtyapps <appUid> ...", false);
- return 0;
- }
- rc = sBandwidthCtrl->addNaughtyApps(argc - 2, argv + 2);
-
- } else if (!strcmp(argv[1], "removenaughtyapps") || !strcmp(argv[1], "rna")) {
- if (argc < 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth removenaughtyapps <appUid> ...", false);
- return 0;
- }
- rc = sBandwidthCtrl->removeNaughtyApps(argc - 2, argv + 2);
-
- } else if (!strcmp(argv[1], "setglobalalert") || !strcmp(argv[1], "sga")) {
- if (argc != 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth setglobalalert <bytes>", false);
- return 0;
- }
- rc = sBandwidthCtrl->setGlobalAlert(atoll(argv[2]));
-
- } else if (!strcmp(argv[1], "removeglobalalert") || !strcmp(argv[1], "rga")) {
- if (argc != 2) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth removeglobalalert", false);
- return 0;
- }
- rc = sBandwidthCtrl->removeGlobalAlert();
-
- } else if (!strcmp(argv[1], "setsharedalert") || !strcmp(argv[1], "ssa")) {
- if (argc != 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth setsharedalert <bytes>", false);
- return 0;
- }
- rc = sBandwidthCtrl->setSharedAlert(atoll(argv[2]));
-
- } else if (!strcmp(argv[1], "removesharedalert") || !strcmp(argv[1], "rsa")) {
- if (argc != 2) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth removesharedalert", false);
- return 0;
- }
- rc = sBandwidthCtrl->removeSharedAlert();
-
- } else if (!strcmp(argv[1], "setinterfacealert") || !strcmp(argv[1], "sia")) {
- if (argc != 4) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth setinterfacealert <interface> <bytes>", false);
- return 0;
- }
- rc = sBandwidthCtrl->setInterfaceAlert(argv[2], atoll(argv[3]));
-
- } else if (!strcmp(argv[1], "removeinterfacealert") || !strcmp(argv[1], "ria")) {
- if (argc != 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: bandwidth removeinterfacealert <interface>", false);
- return 0;
- }
- rc = sBandwidthCtrl->removeInterfaceAlert(argv[2]);
-
- } else {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown bandwidth cmd", false);
+ sendGenericOkFail(cli, rc);
return 0;
+
+ }
+ if (!strcmp(argv[1], "removeiquota") || !strcmp(argv[1], "riq")) {
+ if (argc != 3) {
+ sendGenericSyntaxError(cli, "removeiquota <interface>");
+ return 0;
+ }
+ int rc = sBandwidthCtrl->removeInterfaceQuota(argv[2]);
+ sendGenericOkFail(cli, rc);
+ return 0;
+
+ }
+ if (!strcmp(argv[1], "setiquota") || !strcmp(argv[1], "siq")) {
+ if (argc != 4) {
+ sendGenericSyntaxError(cli, "setiquota <interface> <bytes>");
+ return 0;
+ }
+ int rc = sBandwidthCtrl->setInterfaceQuota(argv[2], atoll(argv[3]));
+ sendGenericOkFail(cli, rc);
+ return 0;
+
+ }
+ if (!strcmp(argv[1], "addnaughtyapps") || !strcmp(argv[1], "ana")) {
+ if (argc < 3) {
+ sendGenericSyntaxError(cli, "addnaughtyapps <appUid> ...");
+ return 0;
+ }
+ int rc = sBandwidthCtrl->addNaughtyApps(argc - 2, argv + 2);
+ sendGenericOkFail(cli, rc);
+ return 0;
+
+
+ }
+ if (!strcmp(argv[1], "removenaughtyapps") || !strcmp(argv[1], "rna")) {
+ if (argc < 3) {
+ sendGenericSyntaxError(cli, "removenaughtyapps <appUid> ...");
+ return 0;
+ }
+ int rc = sBandwidthCtrl->removeNaughtyApps(argc - 2, argv + 2);
+ sendGenericOkFail(cli, rc);
+ return 0;
+
+ }
+ if (!strcmp(argv[1], "setglobalalert") || !strcmp(argv[1], "sga")) {
+ if (argc != 3) {
+ sendGenericSyntaxError(cli, "setglobalalert <bytes>");
+ return 0;
+ }
+ int rc = sBandwidthCtrl->setGlobalAlert(atoll(argv[2]));
+ sendGenericOkFail(cli, rc);
+ return 0;
+
+ }
+ if (!strcmp(argv[1], "removeglobalalert") || !strcmp(argv[1], "rga")) {
+ if (argc != 2) {
+ sendGenericSyntaxError(cli, "removeglobalalert");
+ return 0;
+ }
+ int rc = sBandwidthCtrl->removeGlobalAlert();
+ sendGenericOkFail(cli, rc);
+ return 0;
+
+ }
+ if (!strcmp(argv[1], "setsharedalert") || !strcmp(argv[1], "ssa")) {
+ if (argc != 3) {
+ sendGenericSyntaxError(cli, "setsharedalert <bytes>");
+ return 0;
+ }
+ int rc = sBandwidthCtrl->setSharedAlert(atoll(argv[2]));
+ sendGenericOkFail(cli, rc);
+ return 0;
+
+ }
+ if (!strcmp(argv[1], "removesharedalert") || !strcmp(argv[1], "rsa")) {
+ if (argc != 2) {
+ sendGenericSyntaxError(cli, "removesharedalert");
+ return 0;
+ }
+ int rc = sBandwidthCtrl->removeSharedAlert();
+ sendGenericOkFail(cli, rc);
+ return 0;
+
+ }
+ if (!strcmp(argv[1], "setinterfacealert") || !strcmp(argv[1], "sia")) {
+ if (argc != 4) {
+ sendGenericSyntaxError(cli, "setinterfacealert <interface> <bytes>");
+ return 0;
+ }
+ int rc = sBandwidthCtrl->setInterfaceAlert(argv[2], atoll(argv[3]));
+ sendGenericOkFail(cli, rc);
+ return 0;
+
+ }
+ if (!strcmp(argv[1], "removeinterfacealert") || !strcmp(argv[1], "ria")) {
+ if (argc != 3) {
+ sendGenericSyntaxError(cli, "removeinterfacealert <interface>");
+ return 0;
+ }
+ int rc = sBandwidthCtrl->removeInterfaceAlert(argv[2]);
+ sendGenericOkFail(cli, rc);
+ return 0;
+
+ }
+ if (!strcmp(argv[1], "gettetherstats") || !strcmp(argv[1], "gts")) {
+ BandwidthController::TetherStats tetherStats;
+ if (argc != 4) {
+ sendGenericSyntaxError(cli, "gettetherstats <interface0> <interface1>");
+ return 0;
+ }
+
+ tetherStats.ifaceIn = argv[2];
+ tetherStats.ifaceOut = argv[3];
+ int rc = sBandwidthCtrl->getTetherStats(tetherStats);
+ if (rc) {
+ sendGenericOpFailed(cli, "Failed to get tethering stats");
+ return 0;
+ }
+
+ char *msg = tetherStats.getStatsLine();
+ cli->sendMsg(ResponseCode::TetheringStatsResult, msg, false);
+ free(msg);
+ return 0;
+
}
- if (!rc) {
- cli->sendMsg(ResponseCode::CommandOkay, "Bandwidth command succeeeded", false);
- } else {
- cli->sendMsg(ResponseCode::OperationFailed, "Bandwidth command failed", true);
- }
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown bandwidth cmd", false);
return 0;
}
diff --git a/CommandListener.h b/CommandListener.h
index 05e990e..7c0cfd9 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -106,6 +106,10 @@
BandwidthControlCmd();
virtual ~BandwidthControlCmd() {}
int runCommand(SocketClient *c, int argc, char ** argv);
+ protected:
+ void sendGenericOkFail(SocketClient *cli, int cond);
+ void sendGenericOpFailed(SocketClient *cli, const char *errMsg);
+ void sendGenericSyntaxError(SocketClient *cli, const char *usageMsg);
};
class ResolverCmd : public NetdCommand {
diff --git a/ResponseCode.h b/ResponseCode.h
index 9d0ccb5..b01c141 100644
--- a/ResponseCode.h
+++ b/ResponseCode.h
@@ -43,6 +43,7 @@
static const int InterfaceRxThrottleResult = 218;
static const int InterfaceTxThrottleResult = 219;
static const int QuotaCounterResult = 220;
+ static const int TetheringStatsResult = 221;
// 400 series - The command was accepted but the requested action
// did not take place.