void closeAsync() { IoUtils.safeClose(pipeOutputStream); synchronized (this) { channel.free(this); closed = true; // wake up waiters notifyAll(); } }
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) { int res; SaslWrapper saslWrapper = connection.getSaslWrapper(); try { Pooled<ByteBuffer> pooled = connection.allocate(); ByteBuffer buffer = pooled.getResource(); try { for (; ; ) try { res = channel.receive(buffer); if (res == -1) { log.trace("Received connection end-of-stream"); try { channel.shutdownReads(); } finally { handler.handleConnectionClose(); } return; } else if (res == 0) { log.trace("No message ready; returning"); return; } buffer.flip(); if (saslWrapper != null) { final ByteBuffer source = buffer.duplicate(); buffer.clear(); saslWrapper.unwrap(buffer, source); buffer.flip(); } final byte protoId = buffer.get(); try { switch (protoId) { case Protocol.CONNECTION_ALIVE: { log.trace("Received connection alive"); connection.sendAliveResponse(); return; } case Protocol.CONNECTION_ALIVE_ACK: { log.trace("Received connection alive ack"); return; } case Protocol.CONNECTION_CLOSE: { log.trace("Received connection close request"); handler.receiveCloseRequest(); return; } case Protocol.CHANNEL_OPEN_REQUEST: { log.trace("Received channel open request"); int channelId = buffer.getInt() ^ 0x80000000; int inboundWindow = Integer.MAX_VALUE; int inboundMessages = 0xffff; int outboundWindow = Integer.MAX_VALUE; int outboundMessages = 0xffff; long inboundMessageSize = Long.MAX_VALUE; long outboundMessageSize = Long.MAX_VALUE; // parse out request int b; String serviceType = null; OUT: for (; ; ) { b = buffer.get() & 0xff; switch (b) { case Protocol.O_END: break OUT; case Protocol.O_SERVICE_NAME: { serviceType = ProtocolUtils.readString(buffer); break; } case Protocol.O_MAX_INBOUND_MSG_WINDOW_SIZE: { outboundWindow = Math.min(outboundWindow, ProtocolUtils.readInt(buffer)); break; } case Protocol.O_MAX_INBOUND_MSG_COUNT: { outboundMessages = Math.min(outboundMessages, ProtocolUtils.readUnsignedShort(buffer)); break; } case Protocol.O_MAX_OUTBOUND_MSG_WINDOW_SIZE: { inboundWindow = Math.min(inboundWindow, ProtocolUtils.readInt(buffer)); break; } case Protocol.O_MAX_OUTBOUND_MSG_COUNT: { inboundMessages = Math.min(inboundMessages, ProtocolUtils.readUnsignedShort(buffer)); break; } case Protocol.O_MAX_INBOUND_MSG_SIZE: { outboundMessageSize = Math.min(outboundMessageSize, ProtocolUtils.readLong(buffer)); break; } case Protocol.O_MAX_OUTBOUND_MSG_SIZE: { inboundMessageSize = Math.min(inboundMessageSize, ProtocolUtils.readLong(buffer)); break; } default: { Buffers.skip(buffer, buffer.get() & 0xff); break; } } } if ((channelId & 0x80000000) != 0) { // invalid channel ID, original should have had MSB=1 and thus the complement // should be MSB=0 refuseService(channelId, "Invalid channel ID"); break; } if (serviceType == null) { // invalid service reply refuseService(channelId, "Missing service name"); break; } final RegisteredService registeredService = handler.getConnectionContext().getRegisteredService(serviceType); if (registeredService == null) { refuseService(channelId, "Unknown service name"); break; } final OptionMap serviceOptionMap = registeredService.getOptionMap(); outboundWindow = Math.min( outboundWindow, serviceOptionMap.get( RemotingOptions.TRANSMIT_WINDOW_SIZE, Protocol.DEFAULT_WINDOW_SIZE)); outboundMessages = Math.min( outboundMessages, serviceOptionMap.get( RemotingOptions.MAX_OUTBOUND_MESSAGES, Protocol.DEFAULT_MESSAGE_COUNT)); inboundWindow = Math.min( inboundWindow, serviceOptionMap.get( RemotingOptions.RECEIVE_WINDOW_SIZE, Protocol.DEFAULT_WINDOW_SIZE)); inboundMessages = Math.min( inboundMessages, serviceOptionMap.get( RemotingOptions.MAX_INBOUND_MESSAGES, Protocol.DEFAULT_MESSAGE_COUNT)); outboundMessageSize = Math.min( outboundMessageSize, serviceOptionMap.get( RemotingOptions.MAX_OUTBOUND_MESSAGE_SIZE, Long.MAX_VALUE)); inboundMessageSize = Math.min( inboundMessageSize, serviceOptionMap.get( RemotingOptions.MAX_INBOUND_MESSAGE_SIZE, Long.MAX_VALUE)); final OpenListener openListener = registeredService.getOpenListener(); if (!handler.handleInboundChannelOpen()) { // refuse refuseService(channelId, "Channel refused"); break; } boolean ok1 = false; try { // construct the channel RemoteConnectionChannel connectionChannel = new RemoteConnectionChannel( handler, connection, channelId, outboundWindow, inboundWindow, outboundMessages, inboundMessages, outboundMessageSize, inboundMessageSize); RemoteConnectionChannel existing = handler.addChannel(connectionChannel); if (existing != null) { log.tracef("Encountered open request for duplicate %s", existing); // the channel already exists, which means the remote side "forgot" about it // or we somehow missed the close message. // the only safe thing to do is to terminate the existing channel. try { refuseService(channelId, "Duplicate ID"); } finally { existing.handleRemoteClose(); } break; } // construct reply Pooled<ByteBuffer> pooledReply = connection.allocate(); boolean ok2 = false; try { ByteBuffer replyBuffer = pooledReply.getResource(); replyBuffer.clear(); replyBuffer.put(Protocol.CHANNEL_OPEN_ACK); replyBuffer.putInt(channelId); ProtocolUtils.writeInt( replyBuffer, Protocol.O_MAX_INBOUND_MSG_WINDOW_SIZE, inboundWindow); ProtocolUtils.writeShort( replyBuffer, Protocol.O_MAX_INBOUND_MSG_COUNT, inboundMessages); if (inboundMessageSize != Long.MAX_VALUE) { ProtocolUtils.writeLong( replyBuffer, Protocol.O_MAX_INBOUND_MSG_SIZE, inboundMessageSize); } ProtocolUtils.writeInt( replyBuffer, Protocol.O_MAX_OUTBOUND_MSG_WINDOW_SIZE, outboundWindow); ProtocolUtils.writeShort( replyBuffer, Protocol.O_MAX_OUTBOUND_MSG_COUNT, outboundMessages); if (outboundMessageSize != Long.MAX_VALUE) { ProtocolUtils.writeLong( replyBuffer, Protocol.O_MAX_OUTBOUND_MSG_SIZE, outboundMessageSize); } replyBuffer.put((byte) 0); replyBuffer.flip(); ok2 = true; // send takes ownership of the buffer connection.send(pooledReply); } finally { if (!ok2) pooledReply.free(); } ok1 = true; // Call the service open listener connection .getExecutor() .execute(SpiUtils.getServiceOpenTask(connectionChannel, openListener)); break; } finally { // the inbound channel wasn't open so don't leak the ref count if (!ok1) handler.handleInboundChannelClosed(); } } case Protocol.MESSAGE_DATA: { log.trace("Received message data"); int channelId = buffer.getInt() ^ 0x80000000; RemoteConnectionChannel connectionChannel = handler.getChannel(channelId); if (connectionChannel == null) { // ignore the data log.tracef("Ignoring message data for expired channel"); break; } connectionChannel.handleMessageData(pooled); // need a new buffer now pooled = connection.allocate(); buffer = pooled.getResource(); break; } case Protocol.MESSAGE_WINDOW_OPEN: { log.trace("Received message window open"); int channelId = buffer.getInt() ^ 0x80000000; RemoteConnectionChannel connectionChannel = handler.getChannel(channelId); if (connectionChannel == null) { // ignore log.tracef("Ignoring window open for expired channel"); break; } connectionChannel.handleWindowOpen(pooled); break; } case Protocol.MESSAGE_CLOSE: { log.trace("Received message async close"); int channelId = buffer.getInt() ^ 0x80000000; RemoteConnectionChannel connectionChannel = handler.getChannel(channelId); if (connectionChannel == null) { break; } connectionChannel.handleAsyncClose(pooled); break; } case Protocol.CHANNEL_CLOSED: { log.trace("Received channel closed"); int channelId = buffer.getInt() ^ 0x80000000; RemoteConnectionChannel connectionChannel = handler.getChannel(channelId); if (connectionChannel == null) { break; } connectionChannel.handleRemoteClose(); break; } case Protocol.CHANNEL_SHUTDOWN_WRITE: { log.trace("Received channel shutdown write"); int channelId = buffer.getInt() ^ 0x80000000; RemoteConnectionChannel connectionChannel = handler.getChannel(channelId); if (connectionChannel == null) { break; } connectionChannel.handleIncomingWriteShutdown(); break; } case Protocol.CHANNEL_OPEN_ACK: { log.trace("Received channel open ack"); int channelId = buffer.getInt() ^ 0x80000000; if ((channelId & 0x80000000) == 0) { // invalid break; } PendingChannel pendingChannel = handler.removePendingChannel(channelId); if (pendingChannel == null) { // invalid break; } int outboundWindow = pendingChannel.getOutboundWindowSize(); int inboundWindow = pendingChannel.getInboundWindowSize(); int outboundMessageCount = pendingChannel.getOutboundMessageCount(); int inboundMessageCount = pendingChannel.getInboundMessageCount(); long outboundMessageSize = pendingChannel.getOutboundMessageSize(); long inboundMessageSize = pendingChannel.getInboundMessageSize(); OUT: for (; ; ) { switch (buffer.get() & 0xff) { case Protocol.O_MAX_INBOUND_MSG_WINDOW_SIZE: { outboundWindow = Math.min(outboundWindow, ProtocolUtils.readInt(buffer)); break; } case Protocol.O_MAX_INBOUND_MSG_COUNT: { outboundMessageCount = Math.min( outboundMessageCount, ProtocolUtils.readUnsignedShort(buffer)); break; } case Protocol.O_MAX_OUTBOUND_MSG_WINDOW_SIZE: { inboundWindow = Math.min(inboundWindow, ProtocolUtils.readInt(buffer)); break; } case Protocol.O_MAX_OUTBOUND_MSG_COUNT: { inboundMessageCount = Math.min( inboundMessageCount, ProtocolUtils.readUnsignedShort(buffer)); break; } case Protocol.O_MAX_INBOUND_MSG_SIZE: { outboundMessageSize = Math.min(outboundMessageSize, ProtocolUtils.readLong(buffer)); break; } case Protocol.O_MAX_OUTBOUND_MSG_SIZE: { inboundMessageSize = Math.min(inboundMessageSize, ProtocolUtils.readLong(buffer)); break; } case Protocol.O_END: { break OUT; } default: { // ignore unknown parameter Buffers.skip(buffer, buffer.get() & 0xff); break; } } } RemoteConnectionChannel newChannel = new RemoteConnectionChannel( handler, connection, channelId, outboundWindow, inboundWindow, outboundMessageCount, inboundMessageCount, outboundMessageSize, inboundMessageSize); handler.putChannel(newChannel); pendingChannel.getResult().setResult(newChannel); break; } case Protocol.SERVICE_ERROR: { log.trace("Received service error"); int channelId = buffer.getInt() ^ 0x80000000; PendingChannel pendingChannel = handler.removePendingChannel(channelId); if (pendingChannel == null) { // invalid break; } String reason = new String(Buffers.take(buffer), Protocol.UTF_8); pendingChannel.getResult().setException(new IOException(reason)); break; } default: { log.unknownProtocolId(protoId); break; } } } catch (BufferUnderflowException e) { log.bufferUnderflow(protoId); } } catch (BufferUnderflowException e) { log.bufferUnderflowRaw(); } finally { buffer.clear(); } } finally { pooled.free(); } } catch (IOException e) { connection.handleException(e); handler.handleConnectionClose(); } }
Pooled<ByteBuffer> allocate(byte protoId) { Pooled<ByteBuffer> pooled = channel.allocate(protoId); ByteBuffer buffer = pooled.getResource(); buffer.putShort(messageId); return pooled; }
public void flush() throws IOException { log.trace("Flushing message channel"); Channels.flushBlocking(channel.getRemoteConnection().getChannel()); }