Skip to content

WIP: support peer last handshake time in statistics #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
59 changes: 39 additions & 20 deletions tunnel/src/main/java/com/wireguard/android/backend/Statistics.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,41 @@
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<Key, Pair<Long, Long>> peerBytes = new HashMap<>();
private final Map<Key, PeerStatistics> peerStats = new HashMap<>();
private long lastTouched = SystemClock.elapsedRealtime();
private LocalDateTime defaultLastHandshakeTime = LocalDateTime.ofEpochSecond(
0, 0, ZoneOffset.UTC);

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();
}

Expand All @@ -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<Long, Long> rxTx = peerBytes.get(peer);
if (rxTx == null)
final PeerStatistics stats = peerStats.get(peer);
if (stats == null)
return 0;
return rxTx.first;
return stats.getRx();
}

/**
Expand All @@ -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<Long, Long> 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();
}

/**
Expand All @@ -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]);
}

/**
Expand All @@ -93,8 +112,8 @@ public Key[] peers() {
*/
public long totalRx() {
long rx = 0;
for (final Pair<Long, Long> val : peerBytes.values()) {
rx += val.first;
for (final PeerStatistics val : peerStats.values()) {
rx += val.getRx();
}
return rx;
}
Expand All @@ -106,8 +125,8 @@ public long totalRx() {
*/
public long totalTx() {
long tx = 0;
for (final Pair<Long, Long> val : peerBytes.values()) {
tx += val.second;
for (final PeerStatistics val : peerStats.values()) {
tx += val.getTx();
}
return tx;
}
Expand Down