From 54d24671257a202450628a7f2edc78eda5f9d3bb Mon Sep 17 00:00:00 2001 From: George Kutsurua Date: Sun, 31 Oct 2021 16:19:31 +0400 Subject: [PATCH] support peer last handshake time in statistics Signed-off-by: George Kutsurua --- .../wireguard/android/backend/GoBackend.java | 29 ++++++++- .../android/backend/PeerStatistics.java | 64 +++++++++++++++++++ .../wireguard/android/backend/Statistics.java | 59 +++++++++++------ 3 files changed, 129 insertions(+), 23 deletions(-) create mode 100644 tunnel/src/main/java/com/wireguard/android/backend/PeerStatistics.java diff --git a/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java b/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java index 3d0886cfc..cdf7fcfc1 100644 --- a/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java +++ b/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java @@ -24,6 +24,8 @@ import com.wireguard.util.NonNullForAll; import java.net.InetAddress; +import java.time.LocalDateTime; +import java.time.ZoneOffset; import java.util.Collections; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -125,12 +127,16 @@ public Statistics getStatistics(final Tunnel tunnel) { Key key = null; long rx = 0; long tx = 0; + long lastHandshakeTimeSec = 0; + int lastHandshakeTimeNSec = 0; for (final String line : config.split("\\n")) { if (line.startsWith("public_key=")) { if (key != null) - stats.add(key, rx, tx); + stats.add(key, rx, tx, LocalDateTime.ofEpochSecond(lastHandshakeTimeSec, lastHandshakeTimeNSec, ZoneOffset.UTC)); rx = 0; tx = 0; + lastHandshakeTimeSec = 0; + lastHandshakeTimeNSec = 0; try { key = Key.fromHex(line.substring(11)); } catch (final KeyFormatException ignored) { @@ -152,10 +158,26 @@ public Statistics getStatistics(final Tunnel tunnel) { } catch (final NumberFormatException ignored) { tx = 0; } + } else if (line.startsWith("last_handshake_time_sec=")) { + if (key == null) + continue; + try { + lastHandshakeTimeSec = Long.parseLong(line.substring(24)); + } catch (final NumberFormatException ignored) { + lastHandshakeTimeSec = 0; + } + } else if (line.startsWith("last_handshake_time_nsec=")) { + if (key == null) + continue; + try { + lastHandshakeTimeNSec = Integer.parseInt(line.substring(25)); + } catch (final NumberFormatException ignored) { + lastHandshakeTimeNSec = 0; + } } } if (key != null) - stats.add(key, rx, tx); + stats.add(key, rx, tx, LocalDateTime.ofEpochSecond(lastHandshakeTimeSec, lastHandshakeTimeNSec, ZoneOffset.UTC)); return stats; } @@ -237,7 +259,8 @@ private void setStateInternal(final Tunnel tunnel, @Nullable final Config config } - dnsRetry: for (int i = 0; i < DNS_RESOLUTION_RETRIES; ++i) { + dnsRetry: + for (int i = 0; i < DNS_RESOLUTION_RETRIES; ++i) { // Pre-resolve IPs so they're cached when building the userspace string for (final Peer peer : config.getPeers()) { final InetEndpoint ep = peer.getEndpoint().orElse(null); diff --git a/tunnel/src/main/java/com/wireguard/android/backend/PeerStatistics.java b/tunnel/src/main/java/com/wireguard/android/backend/PeerStatistics.java new file mode 100644 index 000000000..4f95c4271 --- /dev/null +++ b/tunnel/src/main/java/com/wireguard/android/backend/PeerStatistics.java @@ -0,0 +1,64 @@ +/* + * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.wireguard.android.backend; + +import com.wireguard.util.NonNullForAll; + +import java.time.LocalDateTime; + +/** + * Class representing transfer statistics and last handshake time for a + * {@link com.wireguard.config.Peer} instance. + */ +@NonNullForAll +public class PeerStatistics { + private final long rx; + private final long tx; + private final LocalDateTime lastHandshakeTime; + + /** + * Create a peer statistics data object. + * + * @param rx The received traffic for the {@link com.wireguard.config.Peer}. + * This value is in bytes + * @param tx The transmitted traffic for the {@link com.wireguard.config.Peer}. + * This value is in bytes. + * @param lastHandshakeTime The last handshake time for the {@link com.wireguard.config.Peer}. + * This value is in LocalDateTime. + */ + PeerStatistics(long rx, long tx, LocalDateTime lastHandshakeTime) { + this.rx = rx; + this.tx = tx; + this.lastHandshakeTime = lastHandshakeTime; + } + + /** + * Get the received traffic (in bytes) for the {@link com.wireguard.config.Peer} + * + * @return a long representing the number of bytes received by this peer. + */ + public long getRx() { + return rx; + } + + /** + * Get the transmitted traffic (in bytes) for the {@link com.wireguard.config.Peer} + * + * @return a long representing the number of bytes transmitted by this peer. + */ + public long getTx() { + return tx; + } + + /** + * Get last handshake time for the {@link com.wireguard.config.Peer} + * + * @return a LocalDateTime. + */ + public LocalDateTime getLastHandshakeTime() { + return lastHandshakeTime; + } +} diff --git a/tunnel/src/main/java/com/wireguard/android/backend/Statistics.java b/tunnel/src/main/java/com/wireguard/android/backend/Statistics.java index 5d658019c..d0cb3745c 100644 --- a/tunnel/src/main/java/com/wireguard/android/backend/Statistics.java +++ b/tunnel/src/main/java/com/wireguard/android/backend/Statistics.java @@ -6,21 +6,24 @@ package com.wireguard.android.backend; import android.os.SystemClock; -import android.util.Pair; import com.wireguard.crypto.Key; import com.wireguard.util.NonNullForAll; +import java.time.ZoneOffset; import java.util.HashMap; import java.util.Map; +import java.time.LocalDateTime; /** * Class representing transfer statistics for a {@link Tunnel} instance. */ @NonNullForAll public class Statistics { - private final Map> peerBytes = new HashMap<>(); + private final Map peerStats = new HashMap<>(); private long lastTouched = SystemClock.elapsedRealtime(); + private LocalDateTime defaultLastHandshakeTime = LocalDateTime.ofEpochSecond( + 0, 0, ZoneOffset.UTC); Statistics() { } @@ -28,14 +31,16 @@ public class Statistics { /** * Add a peer and its current data usage to the internal map. * - * @param key A WireGuard public key bound to a particular peer - * @param rx The received traffic for the {@link com.wireguard.config.Peer} referenced by - * the provided {@link Key}. This value is in bytes - * @param tx The transmitted traffic for the {@link com.wireguard.config.Peer} referenced by - * the provided {@link Key}. This value is in bytes. + * @param key A WireGuard public key bound to a particular peer + * @param rx The received traffic for the {@link com.wireguard.config.Peer} referenced by + * the provided {@link Key}. This value is in bytes + * @param tx The transmitted traffic for the {@link com.wireguard.config.Peer} referenced by + * the provided {@link Key}. This value is in bytes. + * @param lastHandshakeTime The last handshake time for the {@link com.wireguard.config.Peer} referenced by + * the provided {@link Key}. This value is in LocalDateTime. */ - void add(final Key key, final long rx, final long tx) { - peerBytes.put(key, Pair.create(rx, tx)); + void add(final Key key, final long rx, final long tx, final LocalDateTime lastHandshakeTime) { + peerStats.put(key, new PeerStatistics(rx, tx, lastHandshakeTime)); lastTouched = SystemClock.elapsedRealtime(); } @@ -56,10 +61,10 @@ public boolean isStale() { * @return a long representing the number of bytes received by this peer. */ public long peerRx(final Key peer) { - final Pair rxTx = peerBytes.get(peer); - if (rxTx == null) + final PeerStatistics stats = peerStats.get(peer); + if (stats == null) return 0; - return rxTx.first; + return stats.getRx(); } /** @@ -70,10 +75,24 @@ public long peerRx(final Key peer) { * @return a long representing the number of bytes transmitted by this peer. */ public long peerTx(final Key peer) { - final Pair rxTx = peerBytes.get(peer); - if (rxTx == null) + final PeerStatistics stats = peerStats.get(peer); + if (stats == null) return 0; - return rxTx.second; + return stats.getTx(); + } + + /** + * Get the last handshake time for the {@link com.wireguard.config.Peer} referenced by + * the provided {@link Key} + * + * @param peer A {@link Key} representing a {@link com.wireguard.config.Peer}. + * @return a LocalDateTime representing the last handshake time by this peer. + */ + public LocalDateTime peerLastHandshakeTime(final Key peer) { + final PeerStatistics info = peerStats.get(peer); + if (info == null) + return defaultLastHandshakeTime; + return info.getLastHandshakeTime(); } /** @@ -83,7 +102,7 @@ public long peerTx(final Key peer) { * {@link com.wireguard.config.Peer}s */ public Key[] peers() { - return peerBytes.keySet().toArray(new Key[0]); + return peerStats.keySet().toArray(new Key[0]); } /** @@ -93,8 +112,8 @@ public Key[] peers() { */ public long totalRx() { long rx = 0; - for (final Pair val : peerBytes.values()) { - rx += val.first; + for (final PeerStatistics val : peerStats.values()) { + rx += val.getRx(); } return rx; } @@ -106,8 +125,8 @@ public long totalRx() { */ public long totalTx() { long tx = 0; - for (final Pair val : peerBytes.values()) { - tx += val.second; + for (final PeerStatistics val : peerStats.values()) { + tx += val.getTx(); } return tx; }