Skip to content

Commit 2fa0a2f

Browse files
committed
Refactor & cleanup logic around post-abort connection shutdown
I don't want to change this behaviour too much as it's all delicate and poorly understood or tested, but this aborting state is what we hit after most errors, and triggers a session shutdown, which then results in downstream RST on any ongoing usage, much like any other silent connection death. This change tries to centralize that logic into the session (which is slowly gaining ownership over session activity) and commonize logic between the reader, writer & NIO service to link that all together.
1 parent ccf6734 commit 2fa0a2f

File tree

3 files changed

+40
-68
lines changed

3 files changed

+40
-68
lines changed

app/src/main/java/tech/httptoolkit/android/vpn/Session.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
import java.io.ByteArrayOutputStream;
3131
import java.io.IOException;
3232
import java.nio.ByteBuffer;
33+
import java.nio.channels.DatagramChannel;
3334
import java.nio.channels.SelectionKey;
35+
import java.nio.channels.SocketChannel;
3436
import java.nio.channels.spi.AbstractSelectableChannel;
3537

3638
/**
@@ -379,7 +381,28 @@ public void unsubscribeKey(int OP) {
379381
}
380382
}
381383

382-
public void closeSession() {
384+
// Cleanly close a session - stopping all events, closing the upstream connection, and unregistering
385+
// from the session manager
386+
public void shutdown() {
387+
AbstractSelectableChannel channel = this.getChannel();
388+
this.cancelKey();
389+
390+
try {
391+
if (channel instanceof SocketChannel) {
392+
SocketChannel socketChannel = (SocketChannel) channel;
393+
if (socketChannel.isConnected()) {
394+
socketChannel.close();
395+
}
396+
} else {
397+
DatagramChannel datagramChannel = (DatagramChannel) channel;
398+
if (datagramChannel.isConnected()) {
399+
datagramChannel.close();
400+
}
401+
}
402+
} catch (IOException e) {
403+
Log.e(TAG, e.toString());
404+
}
405+
383406
this.sessionCloser.closeSession(this);
384407
}
385408

app/src/main/java/tech/httptoolkit/android/vpn/socket/SocketChannelReader.java

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -48,50 +48,26 @@ public SocketChannelReader(ClientPacketWriter writer) {
4848
}
4949

5050
public void read(Session session) {
51-
AbstractSelectableChannel channel = session.getChannel();
51+
if (session.isAbortingConnection()) {
52+
Log.d(TAG,"shutting down aborted connection on read -> "+ session);
53+
session.shutdown();
54+
return;
55+
}
5256

53-
if(channel instanceof SocketChannel) {
57+
AbstractSelectableChannel channel = session.getChannel();
58+
if (channel instanceof SocketChannel) {
5459
readTCP(session);
55-
} else if(channel instanceof DatagramChannel){
60+
} else if (channel instanceof DatagramChannel) {
5661
readUDP(session);
5762
} else {
5863
return;
5964
}
6065

6166
// Resubscribe to reads, so that we're triggered again if more data arrives later.
6267
session.subscribeKey(SelectionKey.OP_READ);
63-
64-
if (session.isAbortingConnection()) {
65-
Log.d(TAG,"removing aborted connection -> "+ session);
66-
session.cancelKey();
67-
if (channel instanceof SocketChannel){
68-
try {
69-
SocketChannel socketChannel = (SocketChannel) channel;
70-
if (socketChannel.isConnected()) {
71-
socketChannel.close();
72-
}
73-
} catch (IOException e) {
74-
Log.e(TAG, e.toString());
75-
}
76-
} else {
77-
try {
78-
DatagramChannel datagramChannel = (DatagramChannel) channel;
79-
if (datagramChannel.isConnected()) {
80-
datagramChannel.close();
81-
}
82-
} catch (IOException e) {
83-
e.printStackTrace();
84-
}
85-
}
86-
session.closeSession();
87-
}
8868
}
8969

9070
private void readTCP(@NonNull Session session) {
91-
if (session.isAbortingConnection()) {
92-
return;
93-
}
94-
9571
SocketChannel channel = (SocketChannel) session.getChannel();
9672
int len;
9773

@@ -211,11 +187,7 @@ private void readUDP(Session session){
211187
int len;
212188

213189
try {
214-
do{
215-
if (session.isAbortingConnection()) {
216-
break;
217-
}
218-
190+
do {
219191
len = channel.read(readBuffer);
220192
if (len > 0) {
221193
readBuffer.limit(len);
@@ -232,7 +204,7 @@ private void readUDP(Session session){
232204
+ packetData.length);
233205
}
234206
} while(len > 0);
235-
}catch(NotYetConnectedException ex){
207+
} catch(NotYetConnectedException ex){
236208
Log.e(TAG,"failed to read from unconnected UDP socket");
237209
} catch (IOException e) {
238210
Log.e(TAG,"Failed to read from UDP socket, aborting connection");

app/src/main/java/tech/httptoolkit/android/vpn/socket/SocketChannelWriter.java

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ public boolean isReadyToWrite(@NonNull Session session) {
4848
}
4949

5050
public void write(@NonNull Session session) {
51+
if (session.isAbortingConnection()) {
52+
Log.d(TAG,"shutting down aborted connection on write -> "+ session);
53+
session.shutdown();
54+
return;
55+
}
56+
5157
AbstractSelectableChannel channel = session.getChannel();
5258
if (channel instanceof SocketChannel) {
5359
writeTCP(session);
@@ -57,33 +63,6 @@ public void write(@NonNull Session session) {
5763
// We only ever create TCP & UDP channels, so this should never happen
5864
throw new IllegalArgumentException("Unexpected channel type: " + channel);
5965
}
60-
61-
if (session.isAbortingConnection()) {
62-
Log.d(TAG,"removing aborted connection -> " + session);
63-
session.cancelKey();
64-
65-
if (channel instanceof SocketChannel) {
66-
try {
67-
SocketChannel socketChannel = (SocketChannel) channel;
68-
if (socketChannel.isConnected()) {
69-
socketChannel.close();
70-
}
71-
} catch (IOException e) {
72-
e.printStackTrace();
73-
}
74-
} else if (channel instanceof DatagramChannel) {
75-
try {
76-
DatagramChannel datagramChannel = (DatagramChannel) channel;
77-
if (datagramChannel.isConnected()) {
78-
datagramChannel.close();
79-
}
80-
} catch (IOException e) {
81-
e.printStackTrace();
82-
}
83-
}
84-
85-
session.closeSession();
86-
}
8766
}
8867

8968
private void writeUDP(Session session) {
@@ -102,8 +81,6 @@ private void writeUDP(Session session) {
10281
}
10382

10483
private void writeTCP(Session session) {
105-
if (!this.isReadyToWrite(session)) return;
106-
10784
try {
10885
ProxyProtocolHandler setupHandler = session.getProxySetupHandler();
10986

0 commit comments

Comments
 (0)