Index: java/src/org/apache/tomcat/jni/socket/AprSocket.java |
diff --git a/java/src/org/apache/tomcat/jni/socket/AprSocket.java b/java/src/org/apache/tomcat/jni/socket/AprSocket.java |
deleted file mode 100644 |
index 1800bab4490809e2de6ebca0a0d020c8a08550fa..0000000000000000000000000000000000000000 |
--- a/java/src/org/apache/tomcat/jni/socket/AprSocket.java |
+++ /dev/null |
@@ -1,922 +0,0 @@ |
-/* |
- * Licensed to the Apache Software Foundation (ASF) under one or more |
- * contributor license agreements. See the NOTICE file distributed with |
- * this work for additional information regarding copyright ownership. |
- * The ASF licenses this file to You under the Apache License, Version 2.0 |
- * (the "License"); you may not use this file except in compliance with |
- * the License. You may obtain a copy of the License at |
- * |
- * http://www.apache.org/licenses/LICENSE-2.0 |
- * |
- * Unless required by applicable law or agreed to in writing, software |
- * distributed under the License is distributed on an "AS IS" BASIS, |
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
- * See the License for the specific language governing permissions and |
- * limitations under the License. |
- */ |
-package org.apache.tomcat.jni.socket; |
- |
-import java.io.ByteArrayInputStream; |
-import java.io.IOException; |
-import java.security.cert.CertificateException; |
-import java.security.cert.CertificateFactory; |
-import java.security.cert.X509Certificate; |
-import java.util.logging.Level; |
-import java.util.logging.Logger; |
- |
-import org.apache.tomcat.jni.Address; |
-import org.apache.tomcat.jni.Error; |
-import org.apache.tomcat.jni.Poll; |
-import org.apache.tomcat.jni.SSL; |
-import org.apache.tomcat.jni.SSLExt; |
-import org.apache.tomcat.jni.SSLSocket; |
-import org.apache.tomcat.jni.Sockaddr; |
-import org.apache.tomcat.jni.Socket; |
-import org.apache.tomcat.jni.Status; |
-import org.apache.tomcat.jni.socket.AprSocketContext.AprPoller; |
-import org.apache.tomcat.jni.socket.AprSocketContext.BlockingPollHandler; |
- |
-/** |
- * Native socket, using JNI + APR + openssl. |
- * |
- * The socket is non-blocking - you can register either a blocking or non |
- * blocking callback. |
- * |
- * There is no explicit method to register/unregister poll interest - |
- * it is done automatically, when read/write methods return 0. |
- * |
- * To keep the socket polling you must read all the available data, until |
- * read() returns 0. If you want to pause - don't read all input. To resume - |
- * read again until it returns 0. |
- * |
- * Same for write - when write() returns 0 the socket is registered for |
- * write interest. |
- * |
- * You can also use the blocking read/write methods. |
- */ |
-public class AprSocket implements Runnable { |
- |
- private static final Logger log = |
- Logger.getLogger("org.apache.tomcat.jni.socket.AprSocket"); |
- |
- private static final byte[][] NO_CERTS = new byte[0][]; |
- |
- static final int CONNECTING = 0x1; |
- static final int CONNECTED = 0x2; |
- |
- // Current ( real ) poll status |
- static final int POLLIN_ACTIVE = 0x4; |
- static final int POLLOUT_ACTIVE = 0x8; |
- |
- static final int POLL = 0x10; |
- |
- static final int SSL_ATTACHED = 0x40; |
- |
- // Requested poll status. Set by read/write when needed. |
- // Cleared when polled |
- static final int POLLIN = 0x80; |
- static final int POLLOUT = 0x100; |
- |
- static final int ACCEPTED = 0x200; |
- static final int ERROR = 0x400; |
- static final int CLOSED = 0x800; |
- |
- static final int READING = 0x1000; |
- static final int WRITING = 0x2000; |
- |
- // Not null |
- private final AprSocketContext context; |
- |
- // only one - to save per/socket memory - context has similar callbacks. |
- BlockingPollHandler handler; |
- |
- // Set while it's associated with a poller - it'll stay associated after |
- // connect until close. Destroy will happen in the poller. |
- // POLL bit indicates if the socket is actually polling. |
- AprPoller poller; |
- |
- // Bit field indicating the status and socket should only be accessed with |
- // socketLock protection |
- private int status; |
- |
- long socket; |
- |
- //long to = 10000; |
- |
- // Persistent info about the peer ( SSL, etc ) |
- private HostInfo hostInfo; |
- |
- AprSocket(AprSocketContext context) { |
- this.context = context; |
- } |
- |
- public void recycle() { |
- status = 0; |
- hostInfo = null; |
- handler = null; |
- socket = 0; |
- poller = null; |
- } |
- |
- @Override |
- public String toString() { |
- return (context.isServer() ? "AprSrv-" : "AprCli-") + |
- Long.toHexString(socket) + " " + Integer.toHexString(status); |
- } |
- |
- public void setHandler(BlockingPollHandler l) { |
- handler = l; |
- } |
- |
- private void setNonBlocking() { |
- if (socket != 0 && context.running) { |
- Socket.optSet(socket, Socket.APR_SO_NONBLOCK, 1); |
- Socket.timeoutSet(socket, 0); |
- } |
- } |
- |
- /** |
- * Check if the socket is currently registered with a poller. |
- */ |
- public boolean isPolling() { |
- synchronized (this) { |
- return (status & POLL) != 0; |
- } |
- } |
- |
- public BlockingPollHandler getHandler() { |
- return handler; |
- } |
- |
- public AprSocketContext getContext() { |
- return context; |
- } |
- |
- AprSocket setHost(HostInfo hi) { |
- hostInfo = hi; |
- return this; |
- } |
- |
- /** |
- */ |
- public void connect() throws IOException { |
- if (isBlocking()) { |
- // will call handleConnected() at the end. |
- context.connectBlocking(this); |
- } else { |
- synchronized(this) { |
- if ((status & CONNECTING) != 0) { |
- return; |
- } |
- status |= CONNECTING; |
- } |
- context.connectExecutor.execute(this); |
- } |
- } |
- |
- |
- // after connection is done, called from a thread pool ( not IO thread ) |
- // may block for handshake. |
- void afterConnect() throws IOException { |
- if (hostInfo.secure) { |
- blockingStartTLS(); |
- } |
- |
- setNonBlocking(); // call again, to set the bits ( connect was blocking ) |
- |
- setStatus(CONNECTED); |
- clearStatus(CONNECTING); |
- |
- notifyConnected(false); |
- } |
- |
- public HostInfo getHost() { |
- return hostInfo; |
- } |
- |
- /** |
- * Write as much data as possible to the socket. |
- * |
- * @param data |
- * @param off |
- * @param len |
- * @return For both blocking and non-blocking, returns the number of bytes |
- * written. If no data can be written (e.g. if the buffers are |
- * full) 0 will be returned. |
- * @throws IOException |
- */ |
- public int write(byte[] data, int off, int len, long to) throws IOException { |
- long max = System.currentTimeMillis() + to; |
- |
- while (true) { |
- int rc = writeInternal(data, off, len); |
- if (rc < 0) { |
- throw new IOException("Write error " + rc); |
- } else if (rc == 0) { |
- // need poll out - do we need to update polling ? |
- context.findPollerAndAdd(this); |
- } else { |
- return rc; |
- } |
- |
- try { |
- long waitTime = max - System.currentTimeMillis(); |
- if (waitTime <= 0) { |
- return 0; |
- } |
- wait(waitTime); |
- } catch (InterruptedException e) { |
- return 0; |
- } |
- } |
- } |
- |
- public int write(byte[] data, int off, int len) throws IOException { |
- // In SSL mode, read/write can't be called at the same time. |
- int rc = writeInternal(data, off, len); |
- if (rc < 0) { |
- throw new IOException("Write error " + rc); |
- } else if (rc == 0) { |
- // need poll out - do we need to update polling ? |
- synchronized (this) { |
- context.findPollerAndAdd(this); |
- } |
- } |
- return rc; |
- } |
- |
- private int writeInternal(byte[] data, int off, int len) throws IOException { |
- int rt = 0; |
- int sent = 0; |
- synchronized(this) { |
- if ((status & CLOSED) != 0 |
- || socket == 0 |
- || !context.running) { |
- throw new IOException("Closed"); |
- } |
- if ((status & WRITING) != 0) { |
- throw new IOException("Write from 2 threads not allowed"); |
- } |
- status |= WRITING; |
- |
- while (len > 0) { |
- sent = Socket.send(socket, data, off, len); |
- if (sent <= 0) { |
- break; |
- } |
- off += sent; |
- len -= sent; |
- } |
- |
- status &= ~WRITING; |
- } |
- |
- if (context.rawDataHandler != null) { |
- context.rawData(this, false, data, off, sent, len, false); |
- } |
- |
- if (sent <= 0) { |
- if (sent == -Status.TIMEUP || sent == -Status.EAGAIN || sent == 0) { |
- setStatus(POLLOUT); |
- updatePolling(); |
- return rt; |
- } |
- log.warning("apr.send(): Failed to send, closing " + sent); |
- reset(); |
- throw new IOException("Error sending " + sent + " " + Error.strerror(-sent)); |
- } else { |
- off += sent; |
- len -= sent; |
- rt += sent; |
- return sent; |
- } |
- } |
- |
- public int read(byte[] data, int off, int len, long to) throws IOException { |
- int rd = readNB(data, off, len); |
- if (rd == 0) { |
- synchronized(this) { |
- try { |
- wait(to); |
- } catch (InterruptedException e) { |
- return 0; |
- } |
- } |
- rd = readNB(data, off, len); |
- } |
- return processReadResult(data, off, len, rd); |
- } |
- |
- public int read(byte[] data, int off, int len) throws IOException { |
- return readNB(data, off, len); |
- } |
- |
- private int processReadResult(byte[] data, int off, int len, int read) |
- throws IOException { |
- if (context.rawDataHandler != null) { |
- context.rawData(this, true, data, off, read, len, false); |
- } |
- |
- if (read > 0) { |
- return read; |
- } |
- |
- if (read == 0 || read == -Status.TIMEUP || read == -Status.ETIMEDOUT |
- || read == -Status.EAGAIN) { |
- read = 0; |
- setStatus(POLLIN); |
- updatePolling(); |
- return 0; |
- } |
- |
- if (read == -Status.APR_EOF || read == -1) { |
- close(); |
- return -1; |
- } |
- // abrupt close |
- reset(); |
- throw new IOException("apr.read(): " + read + " " + Error.strerror(-read)); |
- } |
- |
- public int readNB(byte[] data, int off, int len) throws IOException { |
- int read; |
- synchronized(this) { |
- if ((status & CLOSED) != 0 |
- || socket == 0 |
- || !context.running) { |
- return -1; |
- } |
- if ((status & READING) != 0) { |
- throw new IOException("Read from 2 threads not allowed"); |
- } |
- status |= READING; |
- |
- read = Socket.recv(socket, data, off, len); |
- status &= ~READING; |
- } |
- return processReadResult(data, off, len, read); |
- } |
- |
- /* |
- No support for shutdownOutput: SSL is quite tricky. |
- Use close() instead - no read/write will be allowed after. |
- |
- */ |
- |
- public void close() { |
- synchronized (this) { |
- if ((status & CLOSED) != 0 || socket == 0) { |
- return; |
- } |
- status |= CLOSED; |
- status &= ~POLLIN; |
- status &= ~POLLOUT; |
- } |
- if (context.rawDataHandler != null) { |
- context.rawDataHandler.rawData(this, false, null, 0, 0, 0, true); |
- } |
- Socket.close(socket); |
- if (poller == null) { |
- maybeDestroy(); |
- } else { |
- try { |
- poller.requestUpdate(this); |
- } catch (IOException e) { |
- e.printStackTrace(); |
- } |
- } |
- } |
- |
- void maybeDestroy() { |
- synchronized(this) { |
- if (socket == 0 || |
- (status & CONNECTING) != 0 || !context.running) { |
- // closed or operation in progress |
- // if context stopped, pool will be destroyed and close |
- // all sockets automatically. |
- return; |
- } |
- if ((status & CLOSED) == 0) { |
- return; // not closed |
- } |
- if ((status & (WRITING | READING)) != 0) { |
- return; // not closed |
- } |
- |
- if (context.rawDataHandler != null) { |
- context.rawDataHandler.rawData(this, false, null, -1, -1, -1, true); |
- } |
- if (log.isLoggable(Level.FINE)) { |
- log.info("closing: context.open=" + context.open.get() + " " + this); |
- } |
- |
- context.open.decrementAndGet(); |
- |
- if (socket != 0 && (status & CLOSED) == 0) { |
- Socket.close(socket); |
- status |= CLOSED; |
- } |
- |
- if (handler != null) { |
- if (isBlocking()) { |
- context.getExecutor().execute(this); |
- } else { |
- handler.closed(this); |
- } |
- } |
- |
- context.destroySocket(this); |
- } |
- } |
- |
- |
- |
- /** |
- * Close input and output, potentially sending RST, than close the socket. |
- * |
- * The proper way to close when gracefully done is by calling writeEnd() and |
- * reading all remaining input until -1 (EOF) is received. |
- * |
- * If EOF is received, the proper way to close is send whatever is remaining and |
- * call writeEnd(); |
- */ |
- public void reset() { |
- setStatus(ERROR); |
- close(); |
- } |
- |
- |
- /** |
- */ |
- public boolean isClosed() { |
- synchronized(this) { |
- if ((status & CLOSED) != 0 || socket == 0 || !context.running) { |
- return true; |
- } |
- return false; |
- } |
- } |
- |
- public long getIOTimeout() throws IOException { |
- if (socket != 0 && context.running) { |
- try { |
- return Socket.timeoutGet(socket) / 1000; |
- } catch (Exception e) { |
- throw new IOException(e); |
- } |
- } else { |
- throw new IOException("Socket is closed"); |
- } |
- } |
- |
- // Cert is in DER format |
- // Called after handshake |
- public byte[][] getPeerCert(boolean check) throws IOException { |
- getHost(); |
- if (hostInfo.certs != null && hostInfo.certs != NO_CERTS && !check) { |
- return hostInfo.certs; |
- } |
- if (!checkBitAndSocket(SSL_ATTACHED)) { |
- return NO_CERTS; |
- } |
- try { |
- int certLength = SSLSocket.getInfoI(socket, |
- SSL.SSL_INFO_CLIENT_CERT_CHAIN); |
- // TODO: if resumed, old certs are good. |
- // If not - warn if certs changed, remember first cert, etc. |
- if (certLength <= 0) { |
- // Can also happen on session resume - keep the old |
- if (hostInfo.certs == null) { |
- hostInfo.certs = NO_CERTS; |
- } |
- return hostInfo.certs; |
- } |
- hostInfo.certs = new byte[certLength + 1][]; |
- |
- hostInfo.certs[0] = SSLSocket.getInfoB(socket, |
- SSL.SSL_INFO_CLIENT_CERT); |
- for (int i = 0; i < certLength; i++) { |
- hostInfo.certs[i + 1] = SSLSocket.getInfoB(socket, |
- SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); |
- } |
- return hostInfo.certs; |
- } catch (Exception e) { |
- throw new IOException(e); |
- } |
- } |
- |
- public X509Certificate[] getPeerX509Cert() throws IOException { |
- byte[][] certs = getPeerCert(false); |
- X509Certificate[] xcerts = new X509Certificate[certs.length]; |
- if (certs.length == 0) { |
- return xcerts; |
- } |
- try { |
- CertificateFactory cf = CertificateFactory.getInstance("X.509"); |
- for (int i = 0; i < certs.length; i++) { |
- if (certs[i] != null) { |
- ByteArrayInputStream bis = new ByteArrayInputStream( |
- certs[i]); |
- xcerts[i] = (X509Certificate) cf.generateCertificate(bis); |
- bis.close(); |
- } |
- } |
- } catch (CertificateException ex) { |
- throw new IOException(ex); |
- } |
- return xcerts; |
- } |
- |
- public String getCipherSuite() throws IOException { |
- if (checkBitAndSocket(SSL_ATTACHED)) { |
- return null; |
- } |
- try { |
- return SSLSocket.getInfoS(socket, SSL.SSL_INFO_CIPHER); |
- } catch (Exception e) { |
- throw new IOException(e); |
- } |
- } |
- |
- public int getKeySize() throws IOException { |
- if (checkBitAndSocket(SSL_ATTACHED)) { |
- return -1; |
- } |
- try { |
- return SSLSocket.getInfoI(socket, SSL.SSL_INFO_CIPHER_USEKEYSIZE); |
- } catch (Exception e) { |
- throw new IOException(e); |
- } |
- } |
- |
- public int getRemotePort() throws IOException { |
- if (socket != 0 && context.running) { |
- try { |
- long sa = Address.get(Socket.APR_REMOTE, socket); |
- Sockaddr addr = Address.getInfo(sa); |
- return addr.port; |
- } catch (Exception ex) { |
- throw new IOException(ex); |
- } |
- } |
- throw new IOException("Socket closed"); |
- } |
- |
- public String getRemoteAddress() throws IOException { |
- if (socket != 0 && context.running) { |
- try { |
- long sa = Address.get(Socket.APR_REMOTE, socket); |
- return Address.getip(sa); |
- } catch (Exception ex) { |
- throw new IOException(ex); |
- } |
- } |
- throw new IOException("Socket closed"); |
- } |
- |
- public String getRemoteHostname() throws IOException { |
- if (socket != 0 && context.running) { |
- try { |
- long sa = Address.get(Socket.APR_REMOTE, socket); |
- String remoteHost = Address.getnameinfo(sa, 0); |
- if (remoteHost == null) { |
- remoteHost = Address.getip(sa); |
- } |
- return remoteHost; |
- } catch (Exception ex) { |
- throw new IOException(ex); |
- } |
- } |
- throw new IOException("Socket closed"); |
- } |
- |
- public int getLocalPort() throws IOException { |
- if (socket != 0 && context.running) { |
- try { |
- long sa = Address.get(Socket.APR_LOCAL, socket); |
- Sockaddr addr = Address.getInfo(sa); |
- return addr.port; |
- } catch (Exception ex) { |
- throw new IOException(ex); |
- } |
- } |
- throw new IOException("Socket closed"); |
- } |
- |
- public String getLocalAddress() throws IOException { |
- if (socket != 0 && context.running) { |
- try { |
- long sa = Address.get(Socket.APR_LOCAL, socket); |
- return Address.getip(sa); |
- } catch (Exception ex) { |
- throw new IOException(ex); |
- } |
- } |
- throw new IOException("Socket closed"); |
- } |
- |
- public String getLocalHostname() throws IOException { |
- if (socket != 0 && context.running) { |
- try { |
- long sa = Address.get(Socket.APR_LOCAL, socket); |
- return Address.getnameinfo(sa, 0); |
- } catch (Exception ex) { |
- throw new IOException(ex); |
- } |
- } |
- throw new IOException("Socket closed"); |
- } |
- |
- public boolean isBlocking() { |
- return ! (handler instanceof AprSocketContext.NonBlockingPollHandler); |
- } |
- |
- public boolean isError() { |
- return checkPreConnect(ERROR); |
- } |
- |
- void notifyError(Throwable err, boolean needsThread) { |
- if (handler instanceof AprSocketContext.NonBlockingPollHandler) { |
- if (err != null) { |
- ((AprSocketContext.NonBlockingPollHandler) handler).error(this, err); |
- } |
- } else { |
- // poller destroyed, etc |
- if (needsThread) { |
- context.getExecutor().execute(this); |
- } else { |
- try { |
- notifyIO(); |
- } catch (IOException e) { |
- log.log(Level.SEVERE, this + " error ", e); |
- } |
- } |
- } |
- } |
- |
- // Called after connect and from poller. |
- void notifyIO() throws IOException { |
- long t0 = System.currentTimeMillis(); |
- try { |
- if (handler != null) { |
- handler.process(this, true, false, false); |
- } |
- } catch (Throwable t) { |
- throw new IOException(t); |
- } finally { |
- long t1 = System.currentTimeMillis(); |
- t1 -= t0; |
- if (t1 > context.maxHandlerTime.get()) { |
- context.maxHandlerTime.set(t1); |
- } |
- context.totalHandlerTime.addAndGet(t1); |
- context.handlerCount.incrementAndGet(); |
- } |
- } |
- |
- private void notifyConnected(boolean server) throws IOException { |
- // Will set the handler on the channel for accepted |
- context.onSocket(this); |
- |
- if (handler instanceof AprSocketContext.NonBlockingPollHandler) { |
- ((AprSocketContext.NonBlockingPollHandler) handler).connected(this); |
- |
- ((AprSocketContext.NonBlockingPollHandler) handler).process(this, true, true, false); |
- // Now register for polling - unless process() set suspendRead and |
- // doesn't need out notifications |
- updatePolling(); |
- } else { |
- if (server) { |
- // client will block in connect(). |
- // Server: call process(); |
- notifyIO(); |
- } |
- } |
- } |
- |
- private void updatePolling() throws IOException { |
- synchronized (this) { |
- if ((status & CLOSED) != 0) { |
- maybeDestroy(); |
- return; |
- } |
- } |
- context.findPollerAndAdd(this); |
- } |
- |
- @Override |
- public void run() { |
- if (!context.running) { |
- return; |
- } |
- if (checkPreConnect(CLOSED)) { |
- if (handler != null) { |
- handler.closed(this); |
- } |
- return; |
- } |
- if (!checkPreConnect(CONNECTED)) { |
- if (checkBitAndSocket(ACCEPTED)) { |
- try { |
- context.open.incrementAndGet(); |
- |
- if (log.isLoggable(Level.FINE)) { |
- log.info("Accept: " + context.open.get() + " " + this + " " + |
- getRemotePort()); |
- } |
- if (context.tcpNoDelay) { |
- Socket.optSet(socket, Socket.APR_TCP_NODELAY, 1); |
- } |
- |
- setStatus(CONNECTED); |
- if (context.sslMode) { |
- Socket.timeoutSet(socket, |
- context.connectTimeout * 1000L); |
- blockingStartTLS(); |
- } |
- setNonBlocking(); // call again, to set the bits ( connect was blocking ) |
- |
- notifyConnected(true); |
- return; |
- } catch (Throwable t) { |
- t.printStackTrace(); // no error handler yet |
- reset(); |
- notifyError(t, false); |
- return; |
- } |
- } |
- if (checkPreConnect(CONNECTING)) { |
- // Non-blocking connect - will call 'afterConnection' at the end. |
- try { |
- context.connectBlocking(this); |
- } catch (IOException t) { |
- reset(); // also sets status ERROR |
- if (handler instanceof AprSocketContext.NonBlockingPollHandler) { |
- ((AprSocketContext.NonBlockingPollHandler) handler).process(this, false, false, true); |
- } |
- notifyError(t, false); |
- } |
- } |
- } else { |
- if (handler != null) { |
- try { |
- notifyIO(); |
- } catch (Throwable e) { |
- log.log(Level.SEVERE, this + " error ", e); |
- reset(); |
- // no notifyIO - just did it. |
- } |
- } |
- } |
- } |
- |
- /** |
- * This is a blocking call ! ( can be made non-blocking, but too complex ) |
- * |
- * Will be called automatically after connect() or accept if 'secure' is |
- * true. |
- * |
- * Can be called manually to upgrade the channel |
- * @throws IOException |
- */ |
- public void blockingStartTLS() throws IOException { |
- synchronized(this) { |
- if (socket == 0 || !context.running) { |
- return; |
- } |
- if ((status & SSL_ATTACHED) != 0) { |
- return; |
- } |
- status |= SSL_ATTACHED; |
- } |
- |
- try { |
- if (log.isLoggable(Level.FINE)) { |
- log.info(this + " StartSSL"); |
- } |
- |
- AprSocketContext aprCon = context; |
- SSLSocket.attach(aprCon.getSslCtx(), socket); |
- |
- if (context.debugSSL) { |
- SSLExt.debug(socket); |
- } |
- if (!getContext().isServer()) { |
- if (context.USE_TICKETS && hostInfo.ticketLen > 0) { |
- SSLExt.setTicket(socket, hostInfo.ticket, |
- hostInfo.ticketLen); |
- } else if (hostInfo.sessDer != null) { |
- SSLExt.setSessionData(socket, hostInfo.sessDer, |
- hostInfo.sessDer.length); |
- } |
- } |
- SSLExt.sslSetMode(socket, SSLExt.SSL_MODE_ENABLE_PARTIAL_WRITE | |
- SSLExt.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); |
- |
- int rc = SSLSocket.handshake(socket); |
- |
- // At this point we have the session ID, remote certs, etc |
- // we can lookup host info |
- if (hostInfo == null) { |
- hostInfo = new HostInfo(); |
- } |
- |
- if (rc != Status.APR_SUCCESS) { |
- throw new IOException(this + " Handshake failed " + rc + " " |
- + Error.strerror(rc) + " SSLL " |
- + SSL.getLastError()); |
- } else { // SUCCESS |
- handshakeDone(); |
- } |
- } catch (IOException e) { |
- throw e; |
- } catch (Exception e) { |
- throw new IOException(e); |
- } |
- } |
- |
- private void handshakeDone() throws IOException { |
- getHost(); |
- if (socket == 0 || !context.running) { |
- throw new IOException("Socket closed"); |
- } |
- if (context.USE_TICKETS && ! context.isServer()) { |
- if (hostInfo.ticket == null) { |
- hostInfo.ticket = new byte[2048]; |
- } |
- int ticketLen = SSLExt.getTicket(socket, hostInfo.ticket); |
- if (ticketLen > 0) { |
- hostInfo.ticketLen = ticketLen; |
- if (log.isLoggable(Level.FINE)) { |
- log.info("Received ticket: " + ticketLen); |
- } |
- } |
- } |
- |
- // TODO: if the ticket, session id or session changed - callback to |
- // save the session again |
- try { |
- hostInfo.sessDer = SSLExt.getSessionData(socket); |
- getPeerCert(true); |
- hostInfo.sessionId = SSLSocket.getInfoS(socket, |
- SSL.SSL_INFO_SESSION_ID); |
- } catch (Exception e) { |
- throw new IOException(e); |
- } |
- |
- hostInfo.npn = new byte[32]; |
- hostInfo.npnLen = SSLExt.getNPN(socket, hostInfo.npn); |
- |
- // If custom verification is used - should check the certificates |
- if (context.tlsCertVerifier != null) { |
- context.tlsCertVerifier.handshakeDone(this); |
- } |
- } |
- |
- int requestedPolling() { |
- synchronized(this) { |
- if (socket == 0 || ((status & CLOSED) != 0)) { |
- return 0; |
- } |
- // Implicit: |
- //Poll.APR_POLLNVAL | Poll.APR_POLLHUP | Poll.APR_POLLERR | |
- int res = 0; |
- if ((status & POLLIN) != 0) { |
- res = Poll.APR_POLLIN; |
- } |
- if ((status & POLLOUT) != 0) { |
- res |= Poll.APR_POLLOUT; |
- } |
- return res; |
- } |
- } |
- |
- boolean checkBitAndSocket(int bit) { |
- synchronized (this) { |
- return ((status & bit) != 0 && socket != 0 && |
- (status & CLOSED) == 0 && context.running); |
- } |
- } |
- |
- boolean checkPreConnect(int bit) { |
- synchronized (this) { |
- return ((status & bit) != 0); |
- } |
- } |
- |
- void clearStatus(int bit) { |
- synchronized (this) { |
- status &= ~bit; |
- } |
- } |
- |
- boolean setStatus(int bit) { |
- synchronized (this) { |
- int old = status & bit; |
- status |= bit; |
- return old != 0; |
- } |
- } |
- |
- |
-} |