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 mAlreadyInitialised = false
private var mService: VPNService = service 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() { override fun run() {
val config: ClientAPI_Config = ClientAPI_Config() val config: ClientAPI_Config = ClientAPI_Config()

View file

@ -319,17 +319,52 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
mBinder.dispatchEvent(VPNServiceBinder.EVENTS.disconnected, "") mBinder.dispatchEvent(VPNServiceBinder.EVENTS.disconnected, "")
mConnectionTime = 0 mConnectionTime = 0
} }
val status: JSONObject val status: JSONObject
get() { get() {
val deviceIpv4: String = "" 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 { return JSONObject().apply {
putOpt("rx_bytes", getConfigValue("rx_bytes")) putOpt("rx_bytes", status.rxBytes)
putOpt("tx_bytes", getConfigValue("tx_bytes")) putOpt("tx_bytes", status.txBytes)
putOpt("endpoint", mConfig?.getJSONObject("server")?.getString("ipv4Gateway")) putOpt("endpoint", status.endpoint)
putOpt("deviceIpv4", mConfig?.getJSONObject("device")?.getString("ipv4Address")) 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. * Checks if the VPN Permission is given.
* If the permission is given, returns true * If the permission is given, returns true

View file

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

View file

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

View file

@ -23,9 +23,7 @@
AndroidVpnProtocol::AndroidVpnProtocol(Proto protocol, const QJsonObject &configuration, QObject* parent) AndroidVpnProtocol::AndroidVpnProtocol(Proto protocol, const QJsonObject &configuration, QObject* parent)
: VpnProtocol(configuration, parent), : VpnProtocol(configuration, parent),
m_protocol(protocol) m_protocol(protocol)
{ { }
}
ErrorCode AndroidVpnProtocol::start() ErrorCode AndroidVpnProtocol::start()
{ {
@ -39,3 +37,11 @@ void AndroidVpnProtocol::stop()
AndroidController::instance()->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: signals:
public slots:
void connectionDataUpdated(QString totalRx, QString totalTx, QString endpoint, QString deviceIPv4);
protected slots: protected slots:
protected: protected:

View file

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