void closeBlocking() throws IOException { state |= FLAG_CLOSED; try { if (buffer != null) { Channels.writeBlocking(channel, buffer); } channel.shutdownWrites(); Channels.flushBlocking(channel); } finally { channel.close(); } }
@Override public int read(final byte[] b, final int off, final int len) throws IOException { if (anyAreSet(state, FLAG_CLOSED)) { throw UndertowServletMessages.MESSAGES.streamIsClosed(); } if (anyAreSet(state, FLAG_FINISHED)) { return -1; } ByteBuffer buffer = ByteBuffer.wrap(b, off, len); if (listener == null) { int res = Channels.readBlocking(channel, buffer); if (res == -1) { state |= FLAG_FINISHED; } return res; } else { if (anyAreClear(state, FLAG_READY)) { throw UndertowServletMessages.MESSAGES.streamNotReady(); } int res = channel.read(buffer); if (res == -1) { state |= FLAG_FINISHED; } else if (res == 0) { state &= ~FLAG_READY; channel.resumeReads(); } return res; } }
@Override public void write(final byte[] b, final int off, final int len) throws IOException { if (anyAreSet(state, FLAG_CLOSED)) { throw UndertowServletMessages.MESSAGES.streamIsClosed(); } if (listener == null) { Channels.writeBlocking(channel, ByteBuffer.wrap(b, off, len)); } else { if (anyAreClear(state, FLAG_READY)) { throw UndertowServletMessages.MESSAGES.streamNotReady(); } int res; ByteBuffer buffer = ByteBuffer.wrap(b); do { res = channel.write(buffer); if (res == 0) { ByteBuffer copy = ByteBuffer.allocate(buffer.remaining()); copy.put(buffer); copy.flip(); this.buffer = copy; state = state & ~FLAG_READY; channel.resumeWrites(); return; } } while (buffer.hasRemaining()); } }
public void renegotiateBufferRequest(HttpServerExchange exchange, SslClientAuthMode newAuthMode) throws IOException { int maxSize = exchange .getConnection() .getUndertowOptions() .get(UndertowOptions.MAX_BUFFERED_REQUEST_SIZE, 16384); if (maxSize <= 0) { throw new SSLPeerUnverifiedException(""); } // first we need to read the request boolean requestResetRequired = false; StreamSourceChannel requestChannel = Connectors.getExistingRequestChannel(exchange); if (requestChannel == null) { requestChannel = exchange.getRequestChannel(); requestResetRequired = true; } Pooled<ByteBuffer> pooled = exchange.getConnection().getBufferPool().allocate(); boolean free = true; // if the pooled buffer should be freed int usedBuffers = 0; Pooled<ByteBuffer>[] poolArray = null; final int bufferSize = pooled.getResource().remaining(); int allowedBuffers = ((maxSize + bufferSize - 1) / bufferSize); poolArray = new Pooled[allowedBuffers]; poolArray[usedBuffers++] = pooled; try { int res; do { final ByteBuffer buf = pooled.getResource(); res = Channels.readBlocking(requestChannel, buf); if (!buf.hasRemaining()) { if (usedBuffers == allowedBuffers) { throw new SSLPeerUnverifiedException(""); } else { buf.flip(); pooled = exchange.getConnection().getBufferPool().allocate(); poolArray[usedBuffers++] = pooled; } } } while (res != -1); free = false; pooled.getResource().flip(); Connectors.ungetRequestBytes(exchange, poolArray); renegotiateNoRequest(exchange, newAuthMode); } finally { if (free) { for (Pooled<ByteBuffer> buf : poolArray) { if (buf != null) { buf.free(); } } } if (requestResetRequired) { exchange.requestChannel = null; } } }
@Override public void flush() throws IOException { if (anyAreSet(state, FLAG_CLOSED)) { throw UndertowServletMessages.MESSAGES.streamIsClosed(); } if (listener == null) { Channels.flushBlocking(channel); } }
private static <I extends StreamSourceChannel, O extends StreamSinkChannel> void done( I source, O sink, ChannelListener<? super I> sourceListener, ChannelListener<? super O> sinkListener) { Channels.setReadListener(source, sourceListener); if (sourceListener == null) { source.suspendReads(); } else { source.wakeupReads(); } Channels.setWriteListener(sink, sinkListener); if (sinkListener == null) { sink.suspendWrites(); } else { sink.wakeupWrites(); } }
@Override public void sendBinary(final ByteBuffer partialByte, final boolean isLast) throws IOException { if (textFrameSender != null) { throw JsrWebSocketMessages.MESSAGES.cannotSendInMiddleOfFragmentedMessage(); } if (binaryFrameSender == null) { binaryFrameSender = webSocketChannel.send(WebSocketFrameType.BINARY); } try { Channels.writeBlocking(binaryFrameSender, partialByte); if (isLast) { binaryFrameSender.shutdownWrites(); Channels.flushBlocking(binaryFrameSender); } } finally { if (isLast) { binaryFrameSender = null; } } }
@Override public void sendText(final String partialMessage, final boolean isLast) throws IOException { if (binaryFrameSender != null) { throw JsrWebSocketMessages.MESSAGES.cannotSendInMiddleOfFragmentedMessage(); } if (textFrameSender == null) { textFrameSender = webSocketChannel.send(WebSocketFrameType.TEXT); } try { Channels.writeBlocking(textFrameSender, WebSocketUtils.fromUtf8String(partialMessage)); if (isLast) { textFrameSender.shutdownWrites(); Channels.flushBlocking(textFrameSender); } } finally { if (isLast) { textFrameSender = null; } } }
@Override public void close() throws IOException { state |= FLAG_CLOSED; state &= ~FLAG_READY; if (listener == null) { channel.shutdownWrites(); state |= FLAG_DELEGATE_SHUTDOWN; Channels.flushBlocking(channel); } else { if (buffer == null) { channel.shutdownWrites(); state |= FLAG_DELEGATE_SHUTDOWN; if (!channel.flush()) { channel.resumeWrites(); } } } }
public void accept(final Pooled<ByteBuffer> pooledBuffer, final boolean eof) throws IOException { try { final ByteBuffer buffer = pooledBuffer.getResource(); final ConnectedMessageChannel messageChannel = channel.getRemoteConnection().getChannel(); if (eof) { // EOF flag (sync close) buffer.put(7, (byte) (buffer.get(7) | Protocol.MSG_FLAG_EOF)); log.tracef("Sending message (with EOF) (%s) to %s", buffer, messageChannel); } if (cancelled) { buffer.put(7, (byte) (buffer.get(7) | Protocol.MSG_FLAG_CANCELLED)); buffer.limit(8); // discard everything in the buffer log.trace("Message includes cancel flag"); } synchronized (OutboundMessage.this) { int msgSize = buffer.remaining(); window -= msgSize; while (window < msgSize) { try { log.trace("Message window is closed, waiting"); OutboundMessage.this.wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new InterruptedIOException("Interrupted on write"); } } log.trace("Message window is open, proceeding with send"); } Channels.sendBlocking(messageChannel, buffer); } finally { pooledBuffer.free(); if (eof) { channel.free(OutboundMessage.this); } } }
public void handleEvent(final ConnectedMessageChannel channel) { final Pooled<ByteBuffer> pooledReceiveBuffer = connection.allocate(); try { final ByteBuffer receiveBuffer = pooledReceiveBuffer.getResource(); int res = 0; try { res = channel.receive(receiveBuffer); } catch (IOException e) { connection.handleException(e); return; } if (res == -1) { connection.handleException(client.abruptClose(connection)); return; } if (res == 0) { return; } receiveBuffer.flip(); boolean starttls = false; final Set<String> saslMechs = new LinkedHashSet<String>(); final byte msgType = receiveBuffer.get(); switch (msgType) { case Protocol.CONNECTION_ALIVE: { client.trace("Client received connection alive"); return; } case Protocol.CONNECTION_CLOSE: { client.trace("Client received connection close request"); connection.handleIncomingCloseRequest(); return; } case Protocol.CAPABILITIES: { client.trace("Client received capabilities response"); while (receiveBuffer.hasRemaining()) { final byte type = receiveBuffer.get(); final int len = receiveBuffer.get() & 0xff; final ByteBuffer data = Buffers.slice(receiveBuffer, len); switch (type) { case Protocol.CAP_VERSION: { final byte version = data.get(); client.tracef( "Client received capability: version %d", Integer.valueOf(version & 0xff)); // We only support version zero, so knowing the other side's version is not // useful presently break; } case Protocol.CAP_SASL_MECH: { final String mechName = Buffers.getModifiedUtf8(data); client.tracef("Client received capability: SASL mechanism %s", mechName); if (!failedMechs.contains(mechName) && !disallowedMechs.contains(mechName) && (allowedMechs == null || allowedMechs.contains(mechName))) { client.tracef("SASL mechanism %s added to allowed set", mechName); saslMechs.add(mechName); } break; } case Protocol.CAP_STARTTLS: { client.trace("Client received capability: STARTTLS"); starttls = true; break; } default: { client.tracef( "Client received unknown capability %02x", Integer.valueOf(type & 0xff)); // unknown, skip it for forward compatibility. break; } } } if (starttls) { // only initiate starttls if not forbidden by config if (optionMap.get(Options.SSL_STARTTLS, true)) { // Prepare the request message body final Pooled<ByteBuffer> pooledSendBuffer = connection.allocate(); final ByteBuffer sendBuffer = pooledSendBuffer.getResource(); sendBuffer.put(Protocol.STARTTLS); sendBuffer.flip(); connection.setReadListener(new StartTls(serverName)); connection.send(pooledSendBuffer); // all set return; } } if (saslMechs.isEmpty()) { connection.handleException( new SaslException("No more authentication mechanisms to try")); return; } // OK now send our authentication request final OptionMap optionMap = connection.getOptionMap(); final String userName = optionMap.get(RemotingOptions.AUTHORIZE_ID); final Map<String, ?> propertyMap = SaslUtils.createPropertyMap( optionMap, Channels.getOption(channel, Options.SECURE, false)); final SaslClient saslClient; try { saslClient = AccessController.doPrivileged( new PrivilegedExceptionAction<SaslClient>() { public SaslClient run() throws SaslException { return Sasl.createSaslClient( saslMechs.toArray(new String[saslMechs.size()]), userName, "remote", serverName, propertyMap, callbackHandler); } }, accessControlContext); } catch (PrivilegedActionException e) { final SaslException se = (SaslException) e.getCause(); connection.handleException(se); return; } final String mechanismName = saslClient.getMechanismName(); client.tracef("Client initiating authentication using mechanism %s", mechanismName); // Prepare the request message body final Pooled<ByteBuffer> pooledSendBuffer = connection.allocate(); final ByteBuffer sendBuffer = pooledSendBuffer.getResource(); sendBuffer.put(Protocol.AUTH_REQUEST); Buffers.putModifiedUtf8(sendBuffer, mechanismName); sendBuffer.flip(); connection.send(pooledSendBuffer); connection.setReadListener(new Authentication(saslClient, serverName)); return; } default: { client.unknownProtocolId(msgType); connection.handleException(client.invalidMessage(connection)); return; } } } catch (BufferUnderflowException e) { connection.handleException(client.invalidMessage(connection)); return; } catch (BufferOverflowException e) { connection.handleException(client.invalidMessage(connection)); return; } finally { pooledReceiveBuffer.free(); } }
public void flush() throws IOException { log.trace("Flushing message channel"); Channels.flushBlocking(channel.getRemoteConnection().getChannel()); }