mirror of
https://github.com/VibedByKaKi/alexandroid.git
synced 2026-11-15 02:17:18 +01:00
390 lines
14 KiB
Java
390 lines
14 KiB
Java
package org.java_websocket;
|
|
|
|
import java.io.IOException;
|
|
import java.net.Socket;
|
|
import java.net.SocketAddress;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.channels.ByteChannel;
|
|
import java.nio.channels.SelectableChannel;
|
|
import java.nio.channels.SelectionKey;
|
|
import java.nio.channels.SocketChannel;
|
|
import java.util.ArrayList;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.concurrent.ExecutionException;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.Future;
|
|
import javax.net.ssl.SSLEngine;
|
|
import javax.net.ssl.SSLEngineResult;
|
|
import javax.net.ssl.SSLException;
|
|
import javax.net.ssl.SSLSession;
|
|
import okio.Buffer$$ExternalSyntheticBUOutline0;
|
|
import org.java_websocket.interfaces.ISSLChannel;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import rx.Single$$ExternalSyntheticBUOutline0;
|
|
|
|
/* compiled from: r8-map-id-b9432e0f623b4a4bff4ba50a8a24c4aafad2c1e11092747b9fb5e6a22af5a940 */
|
|
/* loaded from: classes11.dex */
|
|
public class SSLSocketChannel2 implements ByteChannel, WrappedByteChannel, ISSLChannel {
|
|
static final /* synthetic */ boolean $assertionsDisabled = false;
|
|
protected static ByteBuffer emptybuffer = ByteBuffer.allocate(0);
|
|
protected ExecutorService exec;
|
|
protected ByteBuffer inCrypt;
|
|
protected ByteBuffer inData;
|
|
protected ByteBuffer outCrypt;
|
|
protected SSLEngineResult readEngineResult;
|
|
protected SelectionKey selectionKey;
|
|
protected SocketChannel socketChannel;
|
|
protected SSLEngine sslEngine;
|
|
protected List<Future<?>> tasks;
|
|
protected SSLEngineResult writeEngineResult;
|
|
private final Logger log = LoggerFactory.getLogger((Class<?>) SSLSocketChannel2.class);
|
|
protected int bufferallocations = 0;
|
|
private byte[] saveCryptData = null;
|
|
|
|
public SSLSocketChannel2(SocketChannel socketChannel, SSLEngine sSLEngine, ExecutorService executorService, SelectionKey selectionKey) throws IOException {
|
|
if (socketChannel == null || sSLEngine == null || executorService == null) {
|
|
Single$$ExternalSyntheticBUOutline0.m$3("parameter must not be null");
|
|
throw null;
|
|
}
|
|
this.socketChannel = socketChannel;
|
|
this.sslEngine = sSLEngine;
|
|
this.exec = executorService;
|
|
SSLEngineResult sSLEngineResult = new SSLEngineResult(SSLEngineResult.Status.BUFFER_UNDERFLOW, sSLEngine.getHandshakeStatus(), 0, 0);
|
|
this.writeEngineResult = sSLEngineResult;
|
|
this.readEngineResult = sSLEngineResult;
|
|
this.tasks = new ArrayList(3);
|
|
if (selectionKey != null) {
|
|
selectionKey.interestOps(selectionKey.interestOps() | 4);
|
|
this.selectionKey = selectionKey;
|
|
}
|
|
createBuffers(sSLEngine.getSession());
|
|
this.socketChannel.write(wrap(emptybuffer));
|
|
processHandshake();
|
|
}
|
|
|
|
private void consumeFutureUninterruptible(Future<?> future) {
|
|
while (true) {
|
|
try {
|
|
try {
|
|
future.get();
|
|
return;
|
|
} catch (InterruptedException unused) {
|
|
Thread.currentThread().interrupt();
|
|
}
|
|
} catch (ExecutionException e) {
|
|
Buffer$$ExternalSyntheticBUOutline0.m((Throwable) e);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean isHandShakeComplete() {
|
|
SSLEngineResult.HandshakeStatus handshakeStatus = this.sslEngine.getHandshakeStatus();
|
|
return handshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED || handshakeStatus == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
|
|
}
|
|
|
|
private synchronized void processHandshake() throws IOException {
|
|
try {
|
|
if (this.sslEngine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
|
|
return;
|
|
}
|
|
if (!this.tasks.isEmpty()) {
|
|
Iterator<Future<?>> it2 = this.tasks.iterator();
|
|
while (it2.hasNext()) {
|
|
Future<?> next = it2.next();
|
|
if (!next.isDone()) {
|
|
if (isBlocking()) {
|
|
consumeFutureUninterruptible(next);
|
|
}
|
|
return;
|
|
}
|
|
it2.remove();
|
|
}
|
|
}
|
|
if (this.sslEngine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
|
|
if (!isBlocking() || this.readEngineResult.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
|
|
this.inCrypt.compact();
|
|
if (this.socketChannel.read(this.inCrypt) == -1) {
|
|
throw new IOException("connection closed unexpectedly by peer");
|
|
}
|
|
this.inCrypt.flip();
|
|
}
|
|
this.inData.compact();
|
|
unwrap();
|
|
if (this.readEngineResult.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) {
|
|
createBuffers(this.sslEngine.getSession());
|
|
return;
|
|
}
|
|
}
|
|
consumeDelegatedTasks();
|
|
if (this.tasks.isEmpty() || this.sslEngine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
|
|
this.socketChannel.write(wrap(emptybuffer));
|
|
if (this.writeEngineResult.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) {
|
|
createBuffers(this.sslEngine.getSession());
|
|
return;
|
|
}
|
|
}
|
|
this.bufferallocations = 1;
|
|
} catch (Throwable th) {
|
|
throw th;
|
|
}
|
|
}
|
|
|
|
private int readRemaining(ByteBuffer byteBuffer) throws SSLException {
|
|
boolean hasRemaining = this.inData.hasRemaining();
|
|
ByteBuffer byteBuffer2 = this.inData;
|
|
if (hasRemaining) {
|
|
return transfereTo(byteBuffer2, byteBuffer);
|
|
}
|
|
if (!byteBuffer2.hasRemaining()) {
|
|
this.inData.clear();
|
|
}
|
|
tryRestoreCryptedData();
|
|
if (!this.inCrypt.hasRemaining()) {
|
|
return 0;
|
|
}
|
|
unwrap();
|
|
int transfereTo = transfereTo(this.inData, byteBuffer);
|
|
if (this.readEngineResult.getStatus() == SSLEngineResult.Status.CLOSED) {
|
|
return -1;
|
|
}
|
|
if (transfereTo > 0) {
|
|
return transfereTo;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private void saveCryptedData() {
|
|
ByteBuffer byteBuffer = this.inCrypt;
|
|
if (byteBuffer == null || byteBuffer.remaining() <= 0) {
|
|
return;
|
|
}
|
|
byte[] bArr = new byte[this.inCrypt.remaining()];
|
|
this.saveCryptData = bArr;
|
|
this.inCrypt.get(bArr);
|
|
}
|
|
|
|
private int transfereTo(ByteBuffer byteBuffer, ByteBuffer byteBuffer2) {
|
|
int remaining = byteBuffer.remaining();
|
|
int remaining2 = byteBuffer2.remaining();
|
|
if (remaining <= remaining2) {
|
|
byteBuffer2.put(byteBuffer);
|
|
return remaining;
|
|
}
|
|
int min = Math.min(remaining, remaining2);
|
|
for (int i = 0; i < min; i++) {
|
|
byteBuffer2.put(byteBuffer.get());
|
|
}
|
|
return min;
|
|
}
|
|
|
|
private void tryRestoreCryptedData() {
|
|
if (this.saveCryptData != null) {
|
|
this.inCrypt.clear();
|
|
this.inCrypt.put(this.saveCryptData);
|
|
this.inCrypt.flip();
|
|
this.saveCryptData = null;
|
|
}
|
|
}
|
|
|
|
private synchronized ByteBuffer unwrap() throws SSLException {
|
|
if (this.readEngineResult.getStatus() == SSLEngineResult.Status.CLOSED && this.sslEngine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
|
|
try {
|
|
close();
|
|
} catch (IOException unused) {
|
|
}
|
|
}
|
|
while (true) {
|
|
int remaining = this.inData.remaining();
|
|
SSLEngineResult unwrap = this.sslEngine.unwrap(this.inCrypt, this.inData);
|
|
this.readEngineResult = unwrap;
|
|
if (unwrap.getStatus() != SSLEngineResult.Status.OK || (remaining == this.inData.remaining() && this.sslEngine.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NEED_UNWRAP)) {
|
|
break;
|
|
}
|
|
}
|
|
this.inData.flip();
|
|
return this.inData;
|
|
}
|
|
|
|
private synchronized ByteBuffer wrap(ByteBuffer byteBuffer) throws SSLException {
|
|
this.outCrypt.compact();
|
|
this.writeEngineResult = this.sslEngine.wrap(byteBuffer, this.outCrypt);
|
|
this.outCrypt.flip();
|
|
return this.outCrypt;
|
|
}
|
|
|
|
@Override // java.nio.channels.Channel, java.io.Closeable, java.lang.AutoCloseable
|
|
public void close() throws IOException {
|
|
this.sslEngine.closeOutbound();
|
|
this.sslEngine.getSession().invalidate();
|
|
if (this.socketChannel.isOpen()) {
|
|
this.socketChannel.write(wrap(emptybuffer));
|
|
}
|
|
this.socketChannel.close();
|
|
}
|
|
|
|
public SelectableChannel configureBlocking(boolean z) throws IOException {
|
|
return this.socketChannel.configureBlocking(z);
|
|
}
|
|
|
|
public boolean connect(SocketAddress socketAddress) throws IOException {
|
|
return this.socketChannel.connect(socketAddress);
|
|
}
|
|
|
|
public void consumeDelegatedTasks() {
|
|
while (true) {
|
|
Runnable delegatedTask = this.sslEngine.getDelegatedTask();
|
|
if (delegatedTask == null) {
|
|
return;
|
|
} else {
|
|
this.tasks.add(this.exec.submit(delegatedTask));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void createBuffers(SSLSession sSLSession) {
|
|
saveCryptedData();
|
|
int packetBufferSize = sSLSession.getPacketBufferSize();
|
|
int max = Math.max(sSLSession.getApplicationBufferSize(), packetBufferSize);
|
|
ByteBuffer byteBuffer = this.inData;
|
|
if (byteBuffer == null) {
|
|
this.inData = ByteBuffer.allocate(max);
|
|
this.outCrypt = ByteBuffer.allocate(packetBufferSize);
|
|
this.inCrypt = ByteBuffer.allocate(packetBufferSize);
|
|
} else {
|
|
if (byteBuffer.capacity() != max) {
|
|
this.inData = ByteBuffer.allocate(max);
|
|
}
|
|
if (this.outCrypt.capacity() != packetBufferSize) {
|
|
this.outCrypt = ByteBuffer.allocate(packetBufferSize);
|
|
}
|
|
if (this.inCrypt.capacity() != packetBufferSize) {
|
|
this.inCrypt = ByteBuffer.allocate(packetBufferSize);
|
|
}
|
|
}
|
|
if (this.inData.remaining() != 0 && this.log.isTraceEnabled()) {
|
|
this.log.trace(new String(this.inData.array(), this.inData.position(), this.inData.remaining()));
|
|
}
|
|
this.inData.rewind();
|
|
this.inData.flip();
|
|
if (this.inCrypt.remaining() != 0 && this.log.isTraceEnabled()) {
|
|
this.log.trace(new String(this.inCrypt.array(), this.inCrypt.position(), this.inCrypt.remaining()));
|
|
}
|
|
this.inCrypt.rewind();
|
|
this.inCrypt.flip();
|
|
this.outCrypt.rewind();
|
|
this.outCrypt.flip();
|
|
this.bufferallocations++;
|
|
}
|
|
|
|
public boolean finishConnect() throws IOException {
|
|
return this.socketChannel.finishConnect();
|
|
}
|
|
|
|
@Override // org.java_websocket.interfaces.ISSLChannel
|
|
public SSLEngine getSSLEngine() {
|
|
return this.sslEngine;
|
|
}
|
|
|
|
@Override // org.java_websocket.WrappedByteChannel
|
|
public boolean isBlocking() {
|
|
return this.socketChannel.isBlocking();
|
|
}
|
|
|
|
public boolean isConnected() {
|
|
return this.socketChannel.isConnected();
|
|
}
|
|
|
|
public boolean isInboundDone() {
|
|
return this.sslEngine.isInboundDone();
|
|
}
|
|
|
|
@Override // org.java_websocket.WrappedByteChannel
|
|
public boolean isNeedRead() {
|
|
if (this.saveCryptData != null || this.inData.hasRemaining()) {
|
|
return true;
|
|
}
|
|
return (!this.inCrypt.hasRemaining() || this.readEngineResult.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW || this.readEngineResult.getStatus() == SSLEngineResult.Status.CLOSED) ? false : true;
|
|
}
|
|
|
|
@Override // org.java_websocket.WrappedByteChannel
|
|
public boolean isNeedWrite() {
|
|
return this.outCrypt.hasRemaining() || !isHandShakeComplete();
|
|
}
|
|
|
|
@Override // java.nio.channels.Channel
|
|
public boolean isOpen() {
|
|
return this.socketChannel.isOpen();
|
|
}
|
|
|
|
@Override // java.nio.channels.ReadableByteChannel
|
|
public int read(ByteBuffer byteBuffer) throws IOException {
|
|
tryRestoreCryptedData();
|
|
while (byteBuffer.hasRemaining()) {
|
|
if (!isHandShakeComplete()) {
|
|
if (isBlocking()) {
|
|
while (!isHandShakeComplete()) {
|
|
processHandshake();
|
|
}
|
|
} else {
|
|
processHandshake();
|
|
if (!isHandShakeComplete()) {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
int readRemaining = readRemaining(byteBuffer);
|
|
if (readRemaining != 0) {
|
|
return readRemaining;
|
|
}
|
|
this.inData.clear();
|
|
boolean hasRemaining = this.inCrypt.hasRemaining();
|
|
ByteBuffer byteBuffer2 = this.inCrypt;
|
|
if (hasRemaining) {
|
|
byteBuffer2.compact();
|
|
} else {
|
|
byteBuffer2.clear();
|
|
}
|
|
if ((isBlocking() || this.readEngineResult.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) && this.socketChannel.read(this.inCrypt) == -1) {
|
|
return -1;
|
|
}
|
|
this.inCrypt.flip();
|
|
unwrap();
|
|
int transfereTo = transfereTo(this.inData, byteBuffer);
|
|
if (transfereTo != 0 || !isBlocking()) {
|
|
return transfereTo;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
@Override // org.java_websocket.WrappedByteChannel
|
|
public int readMore(ByteBuffer byteBuffer) throws SSLException {
|
|
return readRemaining(byteBuffer);
|
|
}
|
|
|
|
public Socket socket() {
|
|
return this.socketChannel.socket();
|
|
}
|
|
|
|
@Override // java.nio.channels.WritableByteChannel
|
|
public int write(ByteBuffer byteBuffer) throws IOException {
|
|
if (!isHandShakeComplete()) {
|
|
processHandshake();
|
|
return 0;
|
|
}
|
|
int write = this.socketChannel.write(wrap(byteBuffer));
|
|
if (this.writeEngineResult.getStatus() != SSLEngineResult.Status.CLOSED) {
|
|
return write;
|
|
}
|
|
Buffer$$ExternalSyntheticBUOutline0.m$3("Connection is closed");
|
|
return 0;
|
|
}
|
|
|
|
@Override // org.java_websocket.WrappedByteChannel
|
|
public void writeMore() throws IOException {
|
|
write(this.outCrypt);
|
|
}
|
|
}
|