Prioritize Android WebSocket downlink packets

This commit is contained in:
2026-05-15 17:09:35 +03:00
parent af85f6e309
commit ceda460d09
2 changed files with 50 additions and 7 deletions
+2 -2
View File
@@ -30,8 +30,8 @@ android {
applicationId "su.cin.rapvpn" applicationId "su.cin.rapvpn"
minSdk 26 minSdk 26
targetSdk 35 targetSdk 35
versionCode 201 versionCode 202
versionName "0.2.201" versionName "0.2.202"
buildConfigField "String", "DEFAULT_BACKEND_URL", "\"${normalizeGradleString(defaultBackendUrl)}\"" buildConfigField "String", "DEFAULT_BACKEND_URL", "\"${normalizeGradleString(defaultBackendUrl)}\""
buildConfigField "String", "DEFAULT_CLUSTER_ID", "\"${normalizeGradleString(defaultClusterId)}\"" buildConfigField "String", "DEFAULT_CLUSTER_ID", "\"${normalizeGradleString(defaultClusterId)}\""
buildConfigField "String", "DEFAULT_ORGANIZATION_ID", "\"${normalizeGradleString(defaultOrganizationId)}\"" buildConfigField "String", "DEFAULT_ORGANIZATION_ID", "\"${normalizeGradleString(defaultOrganizationId)}\""
@@ -31,6 +31,7 @@ final class VpnPacketWebSocketRelay {
private final VpnService vpnService; private final VpnService vpnService;
private final OkHttpClient httpClient; private final OkHttpClient httpClient;
private final FabricServiceChannel fabricServiceChannel; private final FabricServiceChannel fabricServiceChannel;
private final BlockingQueue<List<byte[]>> priorityIncoming = new ArrayBlockingQueue<>(512);
private final BlockingQueue<List<byte[]>> incoming = new ArrayBlockingQueue<>(2048); private final BlockingQueue<List<byte[]>> incoming = new ArrayBlockingQueue<>(2048);
private final Object lock = new Object(); private final Object lock = new Object();
@@ -153,7 +154,19 @@ final class VpnPacketWebSocketRelay {
connect(clusterId, vpnConnectionId); connect(clusterId, vpnConnectionId);
awaitOpen(Math.min(OPEN_WAIT_MS, Math.max(1, timeoutMs))); awaitOpen(Math.min(OPEN_WAIT_MS, Math.max(1, timeoutMs)));
int waitMs = Math.max(1, timeoutMs); int waitMs = Math.max(1, timeoutMs);
List<byte[]> packets = incoming.poll(waitMs, TimeUnit.MILLISECONDS); List<byte[]> packets = priorityIncoming.poll();
if (packets != null) {
return packets;
}
packets = incoming.poll(Math.min(2, waitMs), TimeUnit.MILLISECONDS);
if (packets != null) {
return packets;
}
packets = priorityIncoming.poll();
if (packets != null) {
return packets;
}
packets = incoming.poll(Math.max(1, waitMs - 2), TimeUnit.MILLISECONDS);
return packets == null ? new ArrayList<>() : packets; return packets == null ? new ArrayList<>() : packets;
} }
@@ -167,6 +180,7 @@ final class VpnPacketWebSocketRelay {
open = false; open = false;
connecting = false; connecting = false;
connectingSinceMs = 0; connectingSinceMs = 0;
priorityIncoming.clear();
incoming.clear(); incoming.clear();
if (webSocket != null) { if (webSocket != null) {
try { try {
@@ -238,10 +252,7 @@ final class VpnPacketWebSocketRelay {
if (packets.isEmpty()) { if (packets.isEmpty()) {
return; return;
} }
if (!incoming.offer(packets)) { offerIncomingPacketBatch(packets);
incoming.poll();
incoming.offer(packets);
}
} }
@Override @Override
@@ -333,6 +344,38 @@ final class VpnPacketWebSocketRelay {
return packets; return packets;
} }
private void offerIncomingPacketBatch(List<byte[]> packets) {
BlockingQueue<List<byte[]>> target = containsTCPControlPacket(packets) ? priorityIncoming : incoming;
if (!target.offer(packets)) {
target.poll();
target.offer(packets);
}
}
private static boolean containsTCPControlPacket(List<byte[]> packets) {
if (packets == null) {
return false;
}
for (byte[] packet : packets) {
if (isTCPControlPacket(packet)) {
return true;
}
}
return false;
}
private static boolean isTCPControlPacket(byte[] packet) {
if (packet == null || packet.length < 20 || (packet[0] >> 4) != 4) {
return false;
}
int ihl = (packet[0] & 0x0f) * 4;
if (ihl < 20 || packet.length < ihl + 20 || packet[9] != 6) {
return false;
}
int flags = packet[ihl + 13] & 0xff;
return (flags & 0x17) != 0;
}
private static String trimRight(String value) { private static String trimRight(String value) {
if (value == null) { if (value == null) {
return ""; return "";