Skip to content
Merged
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
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Added

- Added async traceroute, stop SHIM, and use 30041
[#14](https://github.com/netsec-ethz/scion-java-multiping/pull/14)

### Fixed

- ISD-AS assignment parser broken after website change
[#12](https://github.com/netsec-ethz/scion-java-multiping/pull/12)
[#13](https://github.com/netsec-ethz/scion-java-multiping/pull/13)

## [0.4.0] - 2025-04-04

### Added

- REPEAT setting in PingAll + some output cleanup
[#9](https://github.com/netsec-ethz/scion-java-multiping/pull/9),
[#10](https://github.com/netsec-ethz/scion-java-multiping/pull/10)
Expand Down
106 changes: 98 additions & 8 deletions src/main/java/org/scion/multiping/PingAll.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.scion.jpan.*;
import org.scion.jpan.internal.PathRawParser;
import org.scion.multiping.util.*;
Expand All @@ -47,6 +50,9 @@ public class PingAll {
private static final boolean SHOW_ONLY_ICMP = false;
private static final Config config = new Config();

private static final int localPort = 30041;
private static final boolean STOP_SHIM = true;

static {
config.tryICMP = false;
if (SHOW_ONLY_ICMP) {
Expand All @@ -71,20 +77,22 @@ public class PingAll {
private enum Policy {
/** Fastest path using SCMP traceroute */
FASTEST_TR,
/** Fastest path using SCMP async traceroute */
FASTEST_ECHO,
FASTEST_TR_ASYNC,
/** Shortest path using SCMP traceroute */
SHORTEST_TR,
/** Fastest path using SCMP echo */
FASTEST_ECHO,
/** Fastest path using SCMP echo */
SHORTEST_ECHO
}

private static final Policy POLICY = Policy.SHORTEST_TR; // Policy.FASTEST_TR; // SHORTEST_TR;
private static final Policy POLICY = Policy.FASTEST_TR_ASYNC;
private static final boolean SHOW_PATH = !true;

public static void main(String[] args) throws IOException {
PRINT = true;
// System.setProperty(Constants.PROPERTY_DNS_SEARCH_DOMAINS, "ethz.ch.");
System.setProperty(Constants.PROPERTY_SHIM, STOP_SHIM ? "false" : "true"); // disable SHIM

println("Settings:");
println(" Path policy = " + POLICY);
Expand Down Expand Up @@ -142,7 +150,7 @@ private void runDemo(ParseAssignments.HostEntry remote) throws IOException {
ScionService service = Scion.defaultService();
// Dummy address. The traceroute will contact the control service IP instead.
InetSocketAddress destinationAddress =
new InetSocketAddress(InetAddress.getByAddress(new byte[] {1, 2, 3, 4}), 12345);
new InetSocketAddress(InetAddress.getByAddress(new byte[] {0, 0, 0, 0}), 30041);
int nPaths;
Scmp.TimedMessage[] msg = new Scmp.TimedMessage[REPEAT];
Ref<Path> bestPath = Ref.empty();
Expand All @@ -161,7 +169,7 @@ private void runDemo(ParseAssignments.HostEntry remote) throws IOException {
nPaths = paths.size();
msg[0] = findPaths(paths, bestPath);
if (msg[0] != null && REPEAT > 1) {
try (ScmpSender sender = Scmp.newSenderBuilder().build()) {
try (ScmpSender sender = Scmp.newSenderBuilder().setLocalPort(localPort).build()) {
for (int i = 1; i < msg.length; i++) {
List<Scmp.TracerouteMessage> messages = sender.sendTracerouteRequest(bestPath.get());
msg[i] = messages.get(messages.size() - 1);
Expand Down Expand Up @@ -221,6 +229,8 @@ private Scmp.TimedMessage findPaths(List<Path> paths, Ref<Path> bestOut) {
switch (POLICY) {
case FASTEST_TR:
return findFastestTR(paths, bestOut);
case FASTEST_TR_ASYNC:
return findFastestTRasync(paths, bestOut);
case SHORTEST_TR:
return findShortestTR(paths, bestOut);
case SHORTEST_ECHO:
Expand All @@ -234,7 +244,7 @@ private Scmp.EchoMessage findShortestEcho(List<Path> paths, Ref<Path> refBest) {
Path path = PathPolicy.MIN_HOPS.filter(paths).get(0);
refBest.set(path);
ByteBuffer bb = ByteBuffer.allocate(0);
try (ScmpSender sender = Scmp.newSenderBuilder().build()) {
try (ScmpSender sender = Scmp.newSenderBuilder().setLocalPort(localPort).build()) {
nPathTried++;
Scmp.EchoMessage msg = sender.sendEchoRequest(path, bb);
if (msg == null) {
Expand All @@ -261,7 +271,7 @@ private Scmp.EchoMessage findShortestEcho(List<Path> paths, Ref<Path> refBest) {
private Scmp.TracerouteMessage findShortestTR(List<Path> paths, Ref<Path> refBest) {
Path path = PathPolicy.MIN_HOPS.filter(paths).get(0);
refBest.set(path);
try (ScmpSender sender = Scmp.newSenderBuilder().build()) {
try (ScmpSender sender = Scmp.newSenderBuilder().setLocalPort(localPort).build()) {
nPathTried++;
List<Scmp.TracerouteMessage> messages = sender.sendTracerouteRequest(path);
if (messages.isEmpty()) {
Expand Down Expand Up @@ -292,7 +302,7 @@ private Scmp.TracerouteMessage findShortestTR(List<Path> paths, Ref<Path> refBes

private Scmp.TracerouteMessage findFastestTR(List<Path> paths, Ref<Path> refBest) {
Scmp.TracerouteMessage best = null;
try (ScmpSender sender = Scmp.newSenderBuilder().build()) {
try (ScmpSender sender = Scmp.newSenderBuilder().setLocalPort(localPort).build()) {
for (Path path : paths) {
nPathTried++;
List<Scmp.TracerouteMessage> messages = sender.sendTracerouteRequest(path);
Expand Down Expand Up @@ -327,4 +337,84 @@ private Scmp.TracerouteMessage findFastestTR(List<Path> paths, Ref<Path> refBest
return null;
}
}

private Scmp.TracerouteMessage findFastestTRasync(List<Path> paths, Ref<Path> refBest) {
ConcurrentHashMap<Integer, Scmp.TimedMessage> messages = new ConcurrentHashMap<>();
CountDownLatch barrier = new CountDownLatch(paths.size());
ScmpSenderAsync.ResponseHandler handler =
new ScmpSenderAsync.ResponseHandler() {
@Override
public void onResponse(Scmp.TimedMessage msg) {
barrier.countDown();
messages.put(msg.getIdentifier(), msg);
}

@Override
public void onTimeout(Scmp.TimedMessage msg) {
barrier.countDown();
messages.put(msg.getIdentifier(), msg);
}

@Override
public void onError(Scmp.ErrorMessage msg) {
barrier.countDown();
}

@Override
public void onException(Throwable t) {
barrier.countDown();
}
};

Scmp.TracerouteMessage best = null;
try (ScmpSenderAsync sender =
Scmp.newSenderAsyncBuilder(handler).setLocalPort(localPort).build()) {
for (Path path : paths) {
nPathTried++;
int id = sender.sendTracerouteLast(path);
if (id == -1) {
println(" -> local AS, no timing available");
nPathSuccess++;
nAsSuccess++;
return null;
}
}

// Wait for all messages to be received
try {
if (!barrier.await(1100, TimeUnit.MILLISECONDS)) {
throw new IllegalStateException("Missing messages: " + barrier.getCount() + "/" + paths.size());
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException(e);
}

} catch (IOException e) {
println("ERROR: " + e.getMessage());
nAsError++;
return null;
}

for (Scmp.TimedMessage tm : messages.values()) {
Scmp.TracerouteMessage msg = (Scmp.TracerouteMessage) tm;
seenAs.add(msg.getIsdAs());

if (msg.isTimedOut()) {
nPathTimeout++;
if (best == null) {
best = msg;
}
continue;
}

nPathSuccess++;

if (best == null || msg.getNanoSeconds() < best.getNanoSeconds()) {
best = msg;
refBest.set(msg.getRequest().getPath());
}
}
return best;
}
}