OpenVPN bandwidth counter for Android

This commit is contained in:
Dmitriy Karpushin 2022-12-14 18:52:19 +03:00
parent 7345f464a5
commit d417fa58ab
7 changed files with 108 additions and 14 deletions

View file

@ -31,6 +31,31 @@ class OpenVPNThreadv3(var service: VPNService): ClientAPI_OpenVPNClient(), Runna
private var mAlreadyInitialised = false
private var mService: VPNService = service
private var bytesInIndex = -1
private var bytesOutIndex = -1
init {
findConfigIndicies()
}
private fun findConfigIndicies() {
val n: Int = stats_n()
for (i in 0 until n) {
val name: String = stats_name(i)
if (name == "BYTES_IN") bytesInIndex = i
if (name == "BYTES_OUT") bytesOutIndex = i
}
}
fun getTotalRxBytes(): Long {
return stats_value(bytesInIndex)
}
fun getTotalTxBytes(): Long {
return stats_value(bytesOutIndex)
}
override fun run() {
val config: ClientAPI_Config = ClientAPI_Config()

View file

@ -319,17 +319,52 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
mBinder.dispatchEvent(VPNServiceBinder.EVENTS.disconnected, "")
mConnectionTime = 0
}
val status: JSONObject
get() {
val deviceIpv4: String = ""
val status = when (mProtocol) {
"openvpn" -> {
if (mOpenVPNThreadv3 == null) {
Status(null, null, null, null)
} else {
val rx = mOpenVPNThreadv3?.getTotalRxBytes() ?: ""
val tx = mOpenVPNThreadv3?.getTotalTxBytes() ?: ""
Status(
rx.toString(),
tx.toString(),
if (mConfig!!.has("server")) { mConfig?.getJSONObject("server")?.getString("ipv4Gateway") } else {""},
if (mConfig!!.has("device")) { mConfig?.getJSONObject("device")?.getString("ipv4Address") } else {""}
)
}
}
else -> {
Status(
getConfigValue("rx_bytes"),
getConfigValue("tx_bytes"),
mConfig?.getJSONObject("server")?.getString("ipv4Gateway"),
mConfig?.getJSONObject("device")?.getString("ipv4Address")
)
}
}
return JSONObject().apply {
putOpt("rx_bytes", getConfigValue("rx_bytes"))
putOpt("tx_bytes", getConfigValue("tx_bytes"))
putOpt("endpoint", mConfig?.getJSONObject("server")?.getString("ipv4Gateway"))
putOpt("deviceIpv4", mConfig?.getJSONObject("device")?.getString("ipv4Address"))
putOpt("rx_bytes", status.rxBytes)
putOpt("tx_bytes", status.txBytes)
putOpt("endpoint", status.endpoint)
putOpt("deviceIpv4", status.device)
}
}
data class Status(
var rxBytes: String?,
var txBytes: String?,
var endpoint: String?,
var device: String?
)
/*
* Checks if the VPN Permission is given.
* If the permission is given, returns true

View file

@ -52,7 +52,7 @@ constexpr auto PERMISSIONHELPER_CLASS =
AndroidController::AndroidController():
m_binder(this)
{
connect(this, &AndroidController::scheduleStatusCheckSignal, this, &AndroidController::scheduleStatusCheckSlot);
}
AndroidController* AndroidController::instance() {
@ -237,6 +237,14 @@ void AndroidController::setVpnConfig(const QJsonObject &newVpnConfig)
m_vpnConfig = newVpnConfig;
}
void AndroidController::scheduleStatusCheckSlot()
{
QTimer::singleShot(1000, [this]() {
if (isConnected) {
checkStatus();
}
});
}
/**
* @brief AndroidController::VPNBinder::onTransact
@ -271,22 +279,30 @@ bool AndroidController::VPNBinder::onTransact(int code,
case EVENT_CONNECTED:
qDebug() << "Transact: connected";
emit m_controller->connectionStateChanged(VpnProtocol::Connected);
m_controller->isConnected = true;
emit m_controller->scheduleStatusCheckSignal();
break;
case EVENT_DISCONNECTED:
qDebug() << "Transact: disconnected";
emit m_controller->connectionStateChanged(VpnProtocol::Disconnected);
m_controller->isConnected = false;
break;
case EVENT_STATISTIC_UPDATE:
{
qDebug() << "Transact:: update";
// Data is here a JSON String
doc = QJsonDocument::fromJson(data.readData());
// TODO update counters
// emit m_controller->statusUpdated(doc.object()["endpoint"].toString(),
// doc.object()["deviceIpv4"].toString(),
// doc.object()["totalTX"].toInt(),
// doc.object()["totalRX"].toInt());
QString rx = doc.object()["rx_bytes"].toString();
QString tx = doc.object()["tx_bytes"].toString();
QString endpoint = doc.object()["endpoint"].toString();
QString deviceIPv4 = doc.object()["deviceIpv4"].toString();
emit m_controller->statusUpdated(rx, tx, endpoint, deviceIPv4);
emit m_controller->scheduleStatusCheckSignal();
break;
}
case EVENT_BACKEND_LOGS:
qDebug() << "Transact: backend logs";

View file

@ -53,7 +53,11 @@ signals:
void initialized(bool status, bool connected,
const QDateTime& connectionDate);
void statusUpdated(QString totalRx, QString totalTx, QString endpoint, QString deviceIPv4);
void scheduleStatusCheckSignal();
protected slots:
void scheduleStatusCheckSlot();
protected:
@ -84,6 +88,10 @@ private:
VPNBinder m_binder;
bool isConnected = false;
void scheduleStatusCheck();
static void startActivityForResult(JNIEnv* env, jobject /*thiz*/, jobject intent);
};

View file

@ -23,9 +23,7 @@
AndroidVpnProtocol::AndroidVpnProtocol(Proto protocol, const QJsonObject &configuration, QObject* parent)
: VpnProtocol(configuration, parent),
m_protocol(protocol)
{
}
{ }
ErrorCode AndroidVpnProtocol::start()
{
@ -39,3 +37,11 @@ void AndroidVpnProtocol::stop()
AndroidController::instance()->stop();
}
void AndroidVpnProtocol::connectionDataUpdated(QString totalRx, QString totalTx, QString endpoint, QString deviceIPv4)
{
quint64 rxBytes = totalRx.toLongLong();
quint64 txBytes = totalTx.toLongLong();
setBytesChanged(rxBytes, txBytes);
}

View file

@ -25,6 +25,9 @@ public:
signals:
public slots:
void connectionDataUpdated(QString totalRx, QString totalTx, QString endpoint, QString deviceIPv4);
protected slots:
protected:

View file

@ -362,6 +362,7 @@ void VpnConnection::connectToVpn(int serverIndex,
Proto proto = ContainerProps::defaultProtocol(container);
AndroidVpnProtocol *androidVpnProtocol = new AndroidVpnProtocol(proto, m_vpnConfiguration);
connect(AndroidController::instance(), &AndroidController::connectionStateChanged, androidVpnProtocol, &AndroidVpnProtocol::setConnectionState);
connect(AndroidController::instance(), &AndroidController::statusUpdated, androidVpnProtocol, &AndroidVpnProtocol::connectionDataUpdated);
m_vpnProtocol.reset(androidVpnProtocol);
#elif defined Q_OS_IOS