Skip to content

Commit 86a2ec6

Browse files
committed
Updated all binaries to 0.2.4.23, added geoip6 file & hardened tests
The tests were too fragile given the realities of Tor land so I hardened them so that if Tor is even vaguely working then they should pass.
1 parent 1afe3ef commit 86a2ec6

File tree

16 files changed

+49680
-97849
lines changed

16 files changed

+49680
-97849
lines changed

android/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
/.idea
33
*.iml
44
/src/main/assets/geoip
5+
/src/main/assets/geoip6
56
/src/main/assets/torrc

android/build.gradle

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,17 @@ artifacts {
9393

9494
task deleteSourceFiles(type: Delete) {
9595
delete 'src/main/assets/geoip'
96+
delete 'src/main/assets/geoip6'
9697
delete 'src/main/assets/torrc'
9798
}
9899

99100
task copyResources(type: Copy, dependsOn: deleteSourceFiles) {
100101
from "../universal/commonResources/torrc"
101102
from "../universal/commonResources/geoip"
103+
from "../universal/commonResources/geoip6"
102104
into 'src/main/assets'
103105
}
104106

105-
build.dependsOn(copyResources)
107+
// I tried to depend on assemble directly and when I would run debug tests the dependency didn't work right
108+
preBuild.dependsOn(copyResources)
109+

android/src/androidTest/java/com/msopentech/thali/toronionproxy/TorOnionProxySmokeTest.java

Lines changed: 68 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,15 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
7474
import java.io.*;
7575
import java.net.*;
7676
import java.util.Calendar;
77-
import java.util.concurrent.CountDownLatch;
77+
import java.util.concurrent.SynchronousQueue;
7878
import java.util.concurrent.TimeUnit;
7979

8080
public class TorOnionProxySmokeTest extends TorOnionProxyTestCase {
8181
private static final int CONNECT_TIMEOUT_MILLISECONDS = 60000;
8282
private static final int READ_TIMEOUT_MILLISECONDS = 60000;
83-
private static final int TOTAL_MINUTES_FOR_TEST_TO_RUN = 3;
83+
private static final int TOTAL_SECONDS_PER_TOR_STARTUP = 4 * 60;
84+
private static final int TOTAL_TRIES_PER_TOR_STARTUP = 5;
85+
private static final int WAIT_FOR_HIDDEN_SERVICE_MINUTES = 3;
8486
private static final Logger LOG = LoggerFactory.getLogger(TorOnionProxySmokeTest.class);
8587

8688
/**
@@ -96,18 +98,24 @@ public void testHiddenServiceRecycleTime() throws IOException, InterruptedExcept
9698
try {
9799
hiddenServiceManager = getOnionProxyManager(hiddenServiceManagerDirectoryName);
98100
deleteTorWorkingDirectory(hiddenServiceManager.getWorkingDirectory());
99-
assertTrue(hiddenServiceManager.startWithRepeat(30, 5));
101+
assertTrue(hiddenServiceManager.startWithRepeat(TOTAL_SECONDS_PER_TOR_STARTUP, TOTAL_TRIES_PER_TOR_STARTUP));
102+
103+
LOG.warn("Hidden Service Manager is running.");
100104

101105
clientManager = getOnionProxyManager(clientManagerDirectoryName);
102106
deleteTorWorkingDirectory(clientManager.getWorkingDirectory());
103-
assertTrue(clientManager.startWithRepeat(30, 5));
107+
assertTrue(clientManager.startWithRepeat(TOTAL_SECONDS_PER_TOR_STARTUP, TOTAL_TRIES_PER_TOR_STARTUP));
108+
109+
LOG.warn("Client Manager is running.");
104110

105111
String onionAddress = runHiddenServiceTest(hiddenServiceManager, clientManager);
106112

113+
LOG.warn("We successfully sent a message from client manager to hidden service manager!");
114+
107115
// Now take down the hidden service manager and bring it back up with a new descriptor but the
108116
// same address
109117
hiddenServiceManager.stop();
110-
hiddenServiceManager.startWithRepeat(30, 5);
118+
hiddenServiceManager.startWithRepeat(TOTAL_SECONDS_PER_TOR_STARTUP, TOTAL_TRIES_PER_TOR_STARTUP);
111119
// It's possible that one of our deletes could have nuked the hidden service directory
112120
// in which case we would actually be testing against a new hidden service which would
113121
// remove the point of this test. So we check that they are the same.
@@ -122,6 +130,8 @@ public void testHiddenServiceRecycleTime() throws IOException, InterruptedExcept
122130
}
123131
}
124132

133+
public enum ServerState { success, timedout, othererror }
134+
125135
private String runHiddenServiceTest(OnionProxyManager hiddenServiceManager, OnionProxyManager clientManager)
126136
throws IOException, InterruptedException {
127137
int localPort = 9343;
@@ -131,16 +141,32 @@ private String runHiddenServiceTest(OnionProxyManager hiddenServiceManager, Onio
131141

132142
byte[] testBytes = new byte[] { 0x01, 0x02, 0x03, 0x05};
133143

134-
CountDownLatch countDownLatch = receiveExpectedBytes(testBytes, localPort);
135-
136-
Socket clientSocket =
137-
getClientSocket(onionAddress, hiddenServicePort, clientManager.getIPv4LocalHostSocksPort());
138-
139-
DataOutputStream clientOutputStream = new DataOutputStream(clientSocket.getOutputStream());
140-
clientOutputStream.write(testBytes);
141-
clientOutputStream.flush();
142-
assertTrue(countDownLatch.await(TOTAL_MINUTES_FOR_TEST_TO_RUN, TimeUnit.MINUTES));
143-
return onionAddress;
144+
long timeToExit = Calendar.getInstance().getTimeInMillis() + WAIT_FOR_HIDDEN_SERVICE_MINUTES * 60 * 1000;
145+
while(Calendar.getInstance().getTimeInMillis() < timeToExit) {
146+
SynchronousQueue<ServerState> serverQueue = new SynchronousQueue<ServerState>();
147+
Thread serverThread = receiveExpectedBytes(testBytes, localPort, serverQueue);
148+
149+
Socket clientSocket =
150+
getClientSocket(onionAddress, hiddenServicePort, clientManager.getIPv4LocalHostSocksPort());
151+
152+
DataOutputStream clientOutputStream = new DataOutputStream(clientSocket.getOutputStream());
153+
clientOutputStream.write(testBytes);
154+
clientOutputStream.flush();
155+
ServerState serverState = serverQueue.poll(WAIT_FOR_HIDDEN_SERVICE_MINUTES, TimeUnit.MINUTES);
156+
if (serverState == ServerState.success) {
157+
return onionAddress;
158+
} else {
159+
long timeForThreadToExit = Calendar.getInstance().getTimeInMillis() + 1000;
160+
while(Calendar.getInstance().getTimeInMillis() < timeForThreadToExit &&
161+
serverThread.getState() != Thread.State.TERMINATED) {
162+
Thread.sleep(1000,0);
163+
}
164+
if (serverThread.getState() != Thread.State.TERMINATED) {
165+
throw new RuntimeException("Server thread doesn't want to terminate and free up our port!");
166+
}
167+
}
168+
}
169+
throw new RuntimeException("Test timed out!");
144170
}
145171

146172
/**
@@ -152,11 +178,13 @@ private String runHiddenServiceTest(OnionProxyManager hiddenServiceManager, Onio
152178
*/
153179
private Socket getClientSocket(String onionAddress, int hiddenServicePort, int socksPort)
154180
throws InterruptedException {
155-
long timeToExit = Calendar.getInstance().getTimeInMillis() + TOTAL_MINUTES_FOR_TEST_TO_RUN*60*1000;
181+
long timeToExit = Calendar.getInstance().getTimeInMillis() + WAIT_FOR_HIDDEN_SERVICE_MINUTES *60*1000;
156182
Socket clientSocket = null;
157183
while (Calendar.getInstance().getTimeInMillis() < timeToExit && clientSocket == null) {
158184
try {
159185
clientSocket = socks4aSocketConnection(onionAddress, hiddenServicePort, "127.0.0.1", socksPort);
186+
clientSocket.setTcpNoDelay(true);
187+
LOG.info("We connected via the clientSocket to try and talk to the hidden service.");
160188
} catch (IOException e) {
161189
LOG.error("attempt to set clientSocket failed, will retry", e);
162190
Thread.sleep(5000, 0);
@@ -170,29 +198,46 @@ private Socket getClientSocket(String onionAddress, int hiddenServicePort, int s
170198
return clientSocket;
171199
}
172200

173-
private CountDownLatch receiveExpectedBytes(final byte[] expectedBytes, int localPort) throws IOException {
201+
private Thread receiveExpectedBytes(final byte[] expectedBytes, int localPort,
202+
final SynchronousQueue<ServerState> serverQueue) throws IOException {
174203
final ServerSocket serverSocket = new ServerSocket(localPort);
175-
final CountDownLatch countDownLatch = new CountDownLatch(1);
176204

177-
new Thread(new Runnable() {
205+
Thread thread = new Thread(new Runnable() {
178206
public void run() {
179207
Socket receivedSocket = null;
180208
try {
181209
receivedSocket = serverSocket.accept();
210+
// Yes, setTcpNoDelay is useless because we are just reading but I'm being paranoid
211+
receivedSocket.setTcpNoDelay(true);
212+
receivedSocket.setSoTimeout(10*1000);
182213
LOG.info("Received incoming connection");
183214
DataInputStream dataInputStream = new DataInputStream(receivedSocket.getInputStream());
184215
for(byte nextByte : expectedBytes) {
185216
byte receivedByte = dataInputStream.readByte();
186217
if (nextByte != receivedByte) {
187218
LOG.error("Received " + receivedByte + ", but expected " + nextByte);
219+
serverQueue.put(ServerState.othererror);
188220
return;
189221
} else {
190222
LOG.info("Received " + receivedByte);
191223
}
192224
}
193-
countDownLatch.countDown();
225+
LOG.info("All Bytes Successfully Received!");
226+
serverQueue.put(ServerState.success);
194227
} catch(IOException e) {
228+
LOG.warn("We got an io exception waiting for the server bytes, this really shouldn't happen, but does.", e);
229+
try {
230+
serverQueue.put(ServerState.timedout);
231+
} catch (InterruptedException e1) {
232+
LOG.error("We couldn't send notice that we had a server time out! EEEK!");
233+
}
234+
} catch (InterruptedException e) {
195235
LOG.error("Test Failed", e);
236+
try {
237+
serverQueue.put(ServerState.othererror);
238+
} catch (InterruptedException e1) {
239+
LOG.error("We got an InterruptedException and couldn't tell the server queue about it!", e1);
240+
}
196241
} finally {
197242
// I suddenly am getting IncompatibleClassChangeError: interface no implemented when
198243
// calling these functions. I saw a random Internet claim (therefore it must be true!)
@@ -210,9 +255,9 @@ public void run() {
210255
}
211256
}
212257
}
213-
}).start();
214-
215-
return countDownLatch;
258+
});
259+
thread.start();
260+
return thread;
216261
}
217262

218263
private void deleteTorWorkingDirectory(File torWorkingDirectory) {

android/src/main/assets/tor

617 KB
Binary file not shown.

android/src/main/java/com/msopentech/thali/android/toronionproxy/AndroidOnionProxyManager.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,6 @@ public class AndroidOnionProxyManager extends OnionProxyManager {
5757
public AndroidOnionProxyManager(Context context, String workingSubDirectoryName) {
5858
super(new AndroidOnionProxyContext(context, workingSubDirectoryName));
5959
this.context = context;
60-
61-
// Register to receive network status events
62-
networkStateReceiver = new NetworkStateReceiver();
63-
IntentFilter filter = new IntentFilter(CONNECTIVITY_ACTION);
64-
context.registerReceiver(networkStateReceiver, filter);
6560
}
6661

6762
@Override
@@ -82,7 +77,16 @@ public void stop() throws IOException {
8277
super.stop();
8378
} finally {
8479
if (networkStateReceiver != null) {
85-
context.unregisterReceiver(networkStateReceiver);
80+
try {
81+
if (networkStateReceiver != null) {
82+
context.unregisterReceiver(networkStateReceiver);
83+
}
84+
} catch(IllegalArgumentException e) {
85+
// There is a race condition where if someone calls stop before installAndStartTorOp is done
86+
// then we could get an exception because the network state receiver might not be properly
87+
// registered.
88+
LOG.info("Someone tried to call stop before we had finished registering the receiver", e);
89+
}
8690
}
8791
}
8892
}

java/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ install {
101101
}
102102
}
103103

104+
test.testLogging.showStandardStreams = true;
104105

105106
task sourcesJar(type: Jar, dependsOn: classes) {
106107
classifier = 'sources'
@@ -123,6 +124,7 @@ artifacts {
123124
task deleteSourceFiles(type: Delete) {
124125
delete 'src/main/resources/torrc'
125126
delete 'src/main/resources/geoip'
127+
delete 'src/main/resources/geoip6'
126128
}
127129

128130
task copyTorOnionProxyTest(type: Copy, dependsOn: deleteSourceFiles) {
@@ -133,6 +135,7 @@ task copyTorOnionProxyTest(type: Copy, dependsOn: deleteSourceFiles) {
133135
task copyResources(type: Copy, dependsOn: copyTorOnionProxyTest) {
134136
from "../universal/commonResources/torrc"
135137
from "../universal/commonResources/geoip"
138+
from "../universal/commonResources/geoip6"
136139
into 'src/main/resources'
137140
}
138141

java/src/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
main/resources/torrc
22
main/resources/geoip
3+
main/resources/geoip6
8.05 KB
Binary file not shown.
4.7 KB
Binary file not shown.
1.23 KB
Binary file not shown.

0 commit comments

Comments
 (0)