Skip to content

Commit 5adb6e0

Browse files
committed
fixup server stop to not wait by default
fixup potential selector issue trustmanager doesnt need to be used, sslcontext does it automatically
1 parent acf7297 commit 5adb6e0

File tree

4 files changed

+104
-111
lines changed

4 files changed

+104
-111
lines changed

AndroidAsync-Kotlin/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
33
apply plugin: 'kotlin-android-extensions'
44

55
buildscript {
6-
ext.kotlin_version = '1.3.50'
6+
ext.kotlin_version = '1.3.61'
77
repositories {
88
mavenCentral()
99
}

AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -385,40 +385,28 @@ private void handleHandshakeStatus(HandshakeStatus status) {
385385
try {
386386
if (!finishedHandshake && (engine.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING || engine.getHandshakeStatus() == HandshakeStatus.FINISHED)) {
387387
if (clientMode) {
388-
TrustManager[] trustManagers = this.trustManagers;
389-
if (trustManagers == null) {
390-
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
391-
tmf.init((KeyStore) null);
392-
trustManagers = tmf.getTrustManagers();
393-
}
394-
boolean trusted = false;
395388
Exception peerUnverifiedCause = null;
396-
for (TrustManager tm : trustManagers) {
397-
try {
398-
X509TrustManager xtm = (X509TrustManager) tm;
399-
peerCertificates = (X509Certificate[]) engine.getSession().getPeerCertificates();
400-
xtm.checkServerTrusted(peerCertificates, "SSL");
401-
if (mHost != null) {
402-
if (hostnameVerifier == null) {
403-
StrictHostnameVerifier verifier = new StrictHostnameVerifier();
404-
verifier.verify(mHost, StrictHostnameVerifier.getCNs(peerCertificates[0]), StrictHostnameVerifier.getDNSSubjectAlts(peerCertificates[0]));
405-
}
406-
else {
407-
if (!hostnameVerifier.verify(mHost, engine.getSession())) {
408-
throw new SSLException("hostname <" + mHost + "> has been denied");
409-
}
389+
boolean trusted = false;
390+
try {
391+
peerCertificates = (X509Certificate[]) engine.getSession().getPeerCertificates();
392+
if (mHost != null) {
393+
if (hostnameVerifier == null) {
394+
StrictHostnameVerifier verifier = new StrictHostnameVerifier();
395+
verifier.verify(mHost, StrictHostnameVerifier.getCNs(peerCertificates[0]), StrictHostnameVerifier.getDNSSubjectAlts(peerCertificates[0]));
396+
}
397+
else {
398+
if (!hostnameVerifier.verify(mHost, engine.getSession())) {
399+
throw new SSLException("hostname <" + mHost + "> has been denied");
410400
}
411401
}
412-
trusted = true;
413-
break;
414-
}
415-
catch (GeneralSecurityException ex) {
416-
peerUnverifiedCause = ex;
417-
}
418-
catch (SSLException ex) {
419-
peerUnverifiedCause = ex;
420402
}
403+
404+
trusted = true;
405+
}
406+
catch (SSLException ex) {
407+
peerUnverifiedCause = ex;
421408
}
409+
422410
finishedHandshake = true;
423411
if (!trusted) {
424412
AsyncSSLException e = new AsyncSSLException(peerUnverifiedCause);
@@ -446,13 +434,7 @@ public void run() {
446434
onDataAvailable();
447435
}
448436
}
449-
catch (NoSuchAlgorithmException ex) {
450-
throw new RuntimeException(ex);
451-
}
452-
catch (GeneralSecurityException ex) {
453-
report(ex);
454-
}
455-
catch (AsyncSSLException ex) {
437+
catch (Exception ex) {
456438
report(ex);
457439
}
458440
}

AndroidAsync/src/com/koushikdutta/async/AsyncServer.java

Lines changed: 60 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,11 @@ public AsyncServer(String name) {
122122

123123
private static ExecutorService synchronousWorkers = newSynchronousWorkers("AsyncServer-worker-");
124124
private static void wakeup(final SelectorWrapper selector) {
125-
synchronousWorkers.execute(new Runnable() {
126-
@Override
127-
public void run() {
128-
try {
129-
selector.wakeupOnce();
130-
}
131-
catch (Exception e) {
132-
Log.i(LOGTAG, "Selector Exception? L Preview?");
133-
}
125+
synchronousWorkers.execute(() -> {
126+
try {
127+
selector.wakeupOnce();
128+
}
129+
catch (Exception e) {
134130
}
135131
});
136132
}
@@ -275,7 +271,7 @@ public int compare(Scheduled s1, Scheduled s2) {
275271

276272

277273
public void stop() {
278-
stop(true);
274+
stop(false);
279275
}
280276

281277
public void stop(boolean wait) {
@@ -298,7 +294,13 @@ public void run() {
298294
semaphore.release();
299295
}
300296
}, 0));
301-
currentSelector.wakeupOnce();
297+
synchronousWorkers.execute(() -> {
298+
try {
299+
currentSelector.wakeupOnce();
300+
}
301+
catch (Exception e) {
302+
}
303+
});
302304

303305
// force any existing connections to die
304306
shutdownKeys(currentSelector);
@@ -589,58 +591,66 @@ public AsyncDatagramSocket openDatagram(final InetAddress host, final int port,
589591
// ugh.. this should really be post to make it nonblocking...
590592
// but i want datagrams to be immediately writable.
591593
// they're not really used anyways.
592-
run(new Runnable() {
593-
@Override
594-
public void run() {
595-
final DatagramChannel socket;
596-
try {
597-
socket = DatagramChannel.open();
598-
}
599-
catch (Exception e) {
600-
return;
601-
}
602-
try {
603-
handler.attach(socket);
594+
Runnable runnable = () -> {
595+
final DatagramChannel socket;
596+
try {
597+
socket = DatagramChannel.open();
598+
}
599+
catch (Exception e) {
600+
return;
601+
}
602+
try {
603+
handler.attach(socket);
604604

605-
InetSocketAddress address;
606-
if (host == null)
607-
address = new InetSocketAddress(port);
608-
else
609-
address = new InetSocketAddress(host, port);
605+
InetSocketAddress address;
606+
if (host == null)
607+
address = new InetSocketAddress(port);
608+
else
609+
address = new InetSocketAddress(host, port);
610610

611-
if (reuseAddress)
612-
socket.socket().setReuseAddress(reuseAddress);
613-
socket.socket().bind(address);
614-
handleSocket(handler);
615-
}
616-
catch (IOException e) {
617-
Log.e(LOGTAG, "Datagram error", e);
618-
StreamUtility.closeQuietly(socket);
619-
}
611+
if (reuseAddress)
612+
socket.socket().setReuseAddress(reuseAddress);
613+
socket.socket().bind(address);
614+
handleSocket(handler);
620615
}
621-
});
616+
catch (IOException e) {
617+
Log.e(LOGTAG, "Datagram error", e);
618+
StreamUtility.closeQuietly(socket);
619+
}
620+
};
621+
622+
if (getAffinity() != Thread.currentThread()) {
623+
run(runnable);
624+
return handler;
625+
}
626+
627+
runnable.run();
622628
return handler;
623629
}
624630

625631
public AsyncDatagramSocket connectDatagram(final SocketAddress remote) throws IOException {
626-
final DatagramChannel socket = DatagramChannel.open();
627632
final AsyncDatagramSocket handler = new AsyncDatagramSocket();
633+
final DatagramChannel socket = DatagramChannel.open();
628634
handler.attach(socket);
629635
// ugh.. this should really be post to make it nonblocking...
630636
// but i want datagrams to be immediately writable.
631637
// they're not really used anyways.
632-
run(new Runnable() {
633-
@Override
634-
public void run() {
635-
try {
636-
handleSocket(handler);
637-
socket.connect(remote);
638-
}
639-
catch (IOException e) {
640-
StreamUtility.closeQuietly(socket);
641-
}
638+
Runnable runnable = () -> {
639+
try {
640+
handleSocket(handler);
641+
socket.connect(remote);
642642
}
643-
});
643+
catch (IOException e) {
644+
StreamUtility.closeQuietly(socket);
645+
}
646+
};
647+
648+
if (getAffinity() != Thread.currentThread()) {
649+
run(runnable);
650+
return handler;
651+
}
652+
653+
runnable.run();
644654
return handler;
645655
}
646656

AndroidAsync/src/com/koushikdutta/async/SelectorWrapper.java

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
import java.util.Set;
88
import java.util.concurrent.Semaphore;
99
import java.util.concurrent.TimeUnit;
10+
import java.util.concurrent.atomic.AtomicBoolean;
1011

1112
/**
1213
* Created by koush on 2/13/14.
1314
*/
1415
class SelectorWrapper implements Closeable {
1516
private Selector selector;
16-
boolean isWaking;
17+
public AtomicBoolean isWaking = new AtomicBoolean(false);
1718
Semaphore semaphore = new Semaphore(0);
1819
public Selector getSelector() {
1920
return selector;
@@ -67,34 +68,34 @@ public void wakeupOnce() {
6768
return;
6869

6970
// now, we NEED to wait for the select to start to forcibly wake it.
70-
synchronized (this) {
71-
// check if another thread is already waiting
72-
if (isWaking) {
73-
// System.out.println("race wakeup already progressing");
74-
return;
75-
}
76-
isWaking = true;
71+
if (isWaking.getAndSet(true)) {
72+
selector.wakeup();
73+
return;
7774
}
7875

7976
try {
80-
// System.out.println("performing race wakup");
81-
// try to wake up 10 times
82-
for (int i = 0; i < 100; i++) {
83-
try {
84-
if (semaphore.tryAcquire(10, TimeUnit.MILLISECONDS)) {
85-
// System.out.println("race wakeup success");
86-
return;
87-
}
88-
}
89-
catch (InterruptedException e) {
90-
}
91-
selector.wakeup();
92-
}
77+
waitForSelect();
78+
selector.wakeup();
79+
} finally {
80+
isWaking.set(false);
9381
}
94-
finally {
95-
synchronized (this) {
96-
isWaking = false;
82+
}
83+
84+
public boolean waitForSelect() {
85+
// try to wake up 10 times
86+
for (int i = 0; i < 100; i++) {
87+
try {
88+
if (semaphore.tryAcquire(10, TimeUnit.MILLISECONDS)) {
89+
// successfully acquiring means the selector is NOT selecting, since select
90+
// will drain all permits.
91+
continue;
92+
}
93+
} catch (InterruptedException e) {
94+
// an InterruptedException means the acquire failed a select is in progress,
95+
// since it holds all permits
96+
return true;
9797
}
9898
}
99+
return false;
99100
}
100101
}

0 commit comments

Comments
 (0)