/** * Constructor specifying the destination web socket location * * @param version * the protocol version * @param uri * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param subprotocols * CSV of supported protocols. Null if sub protocols not supported. * @param maxFramePayloadLength * Maximum length of a frame's payload */ protected WebSocketServerHandshaker( WebSocketVersion version, String uri, String subprotocols, int maxFramePayloadLength) { this.version = version; this.uri = uri; if (subprotocols != null) { String[] subprotocolArray = StringUtil.split(subprotocols, ','); for (int i = 0; i < subprotocolArray.length; i++) { subprotocolArray[i] = subprotocolArray[i].trim(); } this.subprotocols = subprotocolArray; } else { this.subprotocols = EmptyArrays.EMPTY_STRINGS; } this.maxFramePayloadLength = maxFramePayloadLength; }
/** * Create a new {@link ThreadPerChannelEventLoopGroup}. * * @param maxChannels the maximum number of channels to handle with this instance. Once you try to register * a new {@link Channel} and the maximum is exceed it will throw an * {@link ChannelException} on the {@link #register(Channel)} and * {@link #register(Channel, ChannelPromise)} method. * Use {@code 0} to use no limit * @param threadFactory the {@link ThreadFactory} used to create new {@link Thread} instances that handle the * registered {@link Channel}s * @param args arguments which will passed to each {@link #newChild(Object...)} call. */ protected ThreadPerChannelEventLoopGroup(int maxChannels, ThreadFactory threadFactory, Object... args) { if (maxChannels < 0) { throw new IllegalArgumentException(String.format( "maxChannels: %d (expected: >= 0)", maxChannels)); } if (threadFactory == null) { throw new NullPointerException("threadFactory"); } if (args == null) { childArgs = EmptyArrays.EMPTY_OBJECTS; } else { childArgs = args.clone(); } this.maxChannels = maxChannels; this.threadFactory = threadFactory; tooManyChannels = new ChannelException("too many channels (max: " + maxChannels + ')'); tooManyChannels.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE); }
/** * Create a new {@link ThreadPerChannelEventLoopGroup}. * * @param maxChannels the maximum number of channels to handle with this instance. Once you try to register * a new {@link Channel} and the maximum is exceed it will throw an * {@link ChannelException}. Use {@code 0} to use no limit * @param executor the {@link Executor} used to create new {@link Thread} instances that handle the * registered {@link Channel}s * @param args arguments which will passed to each {@link #newChild(Object...)} call. */ protected ThreadPerChannelEventLoopGroup(int maxChannels, Executor executor, Object... args) { if (maxChannels < 0) { throw new IllegalArgumentException(String.format( "maxChannels: %d (expected: >= 0)", maxChannels)); } if (executor == null) { throw new NullPointerException("executor"); } if (args == null) { childArgs = EmptyArrays.EMPTY_OBJECTS; } else { childArgs = args.clone(); } this.maxChannels = maxChannels; this.executor = executor; tooManyChannels = new ChannelException("too many channels (max: " + maxChannels + ')'); tooManyChannels.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE); }
@Override public byte[] get() throws IOException { if (file == null) { return EmptyArrays.EMPTY_BYTES; } return readFrom(file); }
private static ByteBuf newBinaryData(int statusCode, String reasonText) { byte[] reasonBytes = EmptyArrays.EMPTY_BYTES; if (reasonText != null) { reasonBytes = reasonText.getBytes(CharsetUtil.UTF_8); } ByteBuf binaryData = Unpooled.buffer(2 + reasonBytes.length); binaryData.writeShort(statusCode); if (reasonBytes.length > 0) { binaryData.writeBytes(reasonBytes); } binaryData.readerIndex(0); return binaryData; }
@Override public String[] getEnabledCipherSuites() { String[] enabled = SSL.getCiphers(ssl); if (enabled == null) { return EmptyArrays.EMPTY_STRINGS; } else { for (int i = 0; i < enabled.length; i++) { String mapped = toJavaCipherSuite(enabled[i]); if (mapped != null) { enabled[i] = mapped; } } return enabled; } }
@Override public String[] getEnabledProtocols() { List<String> enabled = new ArrayList<String>(); // Seems like there is no way to explict disable SSLv2Hello in openssl so it is always enabled enabled.add(PROTOCOL_SSL_V2_HELLO); int opts = SSL.getOptions(ssl); if ((opts & SSL.SSL_OP_NO_TLSv1) == 0) { enabled.add(PROTOCOL_TLS_V1); } if ((opts & SSL.SSL_OP_NO_TLSv1_1) == 0) { enabled.add(PROTOCOL_TLS_V1_1); } if ((opts & SSL.SSL_OP_NO_TLSv1_2) == 0) { enabled.add(PROTOCOL_TLS_V1_2); } if ((opts & SSL.SSL_OP_NO_SSLv2) == 0) { enabled.add(PROTOCOL_SSL_V2); } if ((opts & SSL.SSL_OP_NO_SSLv3) == 0) { enabled.add(PROTOCOL_SSL_V3); } int size = enabled.size(); if (size == 0) { return EmptyArrays.EMPTY_STRINGS; } else { return enabled.toArray(new String[size]); } }
@Override public String[] getValueNames() { Map<String, Object> values = this.values; if (values == null || values.isEmpty()) { return EmptyArrays.EMPTY_STRINGS; } return values.keySet().toArray(new String[values.size()]); }
@Override public byte[] array() { switch (components.size()) { case 0: return EmptyArrays.EMPTY_BYTES; case 1: return components.get(0).buf.array(); default: throw new UnsupportedOperationException(); } }
@Override public int setBytes(int index, InputStream in, int length) throws IOException { checkIndex(index, length); if (length == 0) { return in.read(EmptyArrays.EMPTY_BYTES); } int i = toComponentIndex(index); int readBytes = 0; do { Component c = components.get(i); ByteBuf s = c.buf; int adjustment = c.offset; int localLength = Math.min(length, s.capacity() - (index - adjustment)); int localReadBytes = s.setBytes(index - adjustment, in, localLength); if (localReadBytes < 0) { if (readBytes == 0) { return -1; } else { break; } } if (localReadBytes == localLength) { index += localLength; length -= localLength; readBytes += localLength; i ++; } else { index += localReadBytes; length -= localReadBytes; readBytes += localReadBytes; } } while (length > 0); return readBytes; }
@Test public void testGZIPCompressOnly() throws Exception { testGZIPCompressOnly0(null); // Do not write anything; just finish the stream. testGZIPCompressOnly0(EmptyArrays.EMPTY_BYTES); // Write an empty array. testGZIPCompressOnly0(BYTES_SMALL); testGZIPCompressOnly0(BYTES_LARGE); }
@Override public ByteBuffer[] nioBuffers(int index, int length) { checkIndex(index, length); if (length == 0) { return EmptyArrays.EMPTY_BYTE_BUFFERS; } List<ByteBuffer> buffers = new ArrayList<ByteBuffer>(components.size()); int i = toComponentIndex(index); while (length > 0) { Component c = components.get(i); ByteBuf s = c.buf; int adjustment = c.offset; int localLength = Math.min(length, s.capacity() - (index - adjustment)); switch (s.nioBufferCount()) { case 0: throw new UnsupportedOperationException(); case 1: buffers.add(s.nioBuffer(index - adjustment, localLength)); break; default: Collections.addAll(buffers, s.nioBuffers(index - adjustment, localLength)); } index += localLength; length -= localLength; i ++; } return buffers.toArray(new ByteBuffer[buffers.size()]); }
@Override public ByteBuffer[] nioBuffers(int index, int length) { checkIndex(index, length); if (length == 0) { return EmptyArrays.EMPTY_BYTE_BUFFERS; } RecyclableArrayList array = RecyclableArrayList.newInstance(buffers.length); try { Component c = findComponent(index); int i = c.index; int adjustment = c.offset; ByteBuf s = c.buf; for (;;) { int localLength = Math.min(length, s.capacity() - (index - adjustment)); switch (s.nioBufferCount()) { case 0: throw new UnsupportedOperationException(); case 1: array.add(s.nioBuffer(index - adjustment, localLength)); break; default: Collections.addAll(array, s.nioBuffers(index - adjustment, localLength)); } index += localLength; length -= localLength; adjustment += s.readableBytes(); if (length <= 0) { break; } s = buffer(++i); } return array.toArray(new ByteBuffer[array.size()]); } finally { array.recycle(); } }
private static ByteBuf encodeConnectMessage( ByteBufAllocator byteBufAllocator, MqttConnectMessage message) { int payloadBufferSize = 0; MqttFixedHeader mqttFixedHeader = message.fixedHeader(); MqttConnectVariableHeader variableHeader = message.variableHeader(); MqttConnectPayload payload = message.payload(); MqttVersion mqttVersion = MqttVersion.fromProtocolNameAndLevel(variableHeader.name(), (byte) variableHeader.version()); // Client id String clientIdentifier = payload.clientIdentifier(); if (!isValidClientId(mqttVersion, clientIdentifier)) { throw new MqttIdentifierRejectedException("invalid clientIdentifier: " + clientIdentifier); } byte[] clientIdentifierBytes = encodeStringUtf8(clientIdentifier); payloadBufferSize += 2 + clientIdentifierBytes.length; // Will topic and message String willTopic = payload.willTopic(); byte[] willTopicBytes = willTopic != null ? encodeStringUtf8(willTopic) : EmptyArrays.EMPTY_BYTES; byte[] willMessage = payload.willMessageInBytes(); byte[] willMessageBytes = willMessage != null ? willMessage : EmptyArrays.EMPTY_BYTES; if (variableHeader.isWillFlag()) { payloadBufferSize += 2 + willTopicBytes.length; payloadBufferSize += 2 + willMessageBytes.length; } String userName = payload.userName(); byte[] userNameBytes = userName != null ? encodeStringUtf8(userName) : EmptyArrays.EMPTY_BYTES; if (variableHeader.hasUserName()) { payloadBufferSize += 2 + userNameBytes.length; } byte[] password = payload.passwordInBytes(); byte[] passwordBytes = password != null ? password : EmptyArrays.EMPTY_BYTES; if (variableHeader.hasPassword()) { payloadBufferSize += 2 + passwordBytes.length; } // Fixed header byte[] protocolNameBytes = mqttVersion.protocolNameBytes(); int variableHeaderBufferSize = 2 + protocolNameBytes.length + 4; int variablePartSize = variableHeaderBufferSize + payloadBufferSize; int fixedHeaderBufferSize = 1 + getVariableLengthInt(variablePartSize); ByteBuf buf = byteBufAllocator.buffer(fixedHeaderBufferSize + variablePartSize); buf.writeByte(getFixedHeaderByte1(mqttFixedHeader)); writeVariableLengthInt(buf, variablePartSize); buf.writeShort(protocolNameBytes.length); buf.writeBytes(protocolNameBytes); buf.writeByte(variableHeader.version()); buf.writeByte(getConnVariableHeaderFlag(variableHeader)); buf.writeShort(variableHeader.keepAliveTimeSeconds()); // Payload buf.writeShort(clientIdentifierBytes.length); buf.writeBytes(clientIdentifierBytes, 0, clientIdentifierBytes.length); if (variableHeader.isWillFlag()) { buf.writeShort(willTopicBytes.length); buf.writeBytes(willTopicBytes, 0, willTopicBytes.length); buf.writeShort(willMessageBytes.length); buf.writeBytes(willMessageBytes, 0, willMessageBytes.length); } if (variableHeader.hasUserName()) { buf.writeShort(userNameBytes.length); buf.writeBytes(userNameBytes, 0, userNameBytes.length); } if (variableHeader.hasPassword()) { buf.writeShort(passwordBytes.length); buf.writeBytes(passwordBytes, 0, passwordBytes.length); } return buf; }
@Override public X509Certificate[] getAcceptedIssuers() { return EmptyArrays.EMPTY_X509_CERTIFICATES; }
@Override public byte[] array() { return EmptyArrays.EMPTY_BYTES; }
private ChannelFuture finishEncode(ChannelHandlerContext ctx, ChannelPromise promise) { if (finished) { promise.setSuccess(); return promise; } finished = true; ByteBuf footer; try { // Configure input. z.next_in = EmptyArrays.EMPTY_BYTES; z.next_in_index = 0; z.avail_in = 0; // Configure output. byte[] out = new byte[32]; // room for ADLER32 + ZLIB / CRC32 + GZIP header z.next_out = out; z.next_out_index = 0; z.avail_out = out.length; // Write the ADLER32 checksum (stream footer). int resultCode = z.deflate(JZlib.Z_FINISH); if (resultCode != JZlib.Z_OK && resultCode != JZlib.Z_STREAM_END) { promise.setFailure(ZlibUtil.deflaterException(z, "compression failure", resultCode)); return promise; } else if (z.next_out_index != 0) { footer = Unpooled.wrappedBuffer(out, 0, z.next_out_index); } else { footer = Unpooled.EMPTY_BUFFER; } } finally { z.deflateEnd(); // Deference the external references explicitly to tell the VM that // the allocated byte arrays are temporary so that the call stack // can be utilized. // I'm not sure if the modern VMs do this optimization though. z.next_in = null; z.next_out = null; } return ctx.writeAndFlush(footer, promise); }
@Test public void testDecodeEmpty() { ch.writeInbound(EMPTY_BUFFER); assertThat((byte[]) ch.readInbound(), is(EmptyArrays.EMPTY_BYTES)); }
@Test public void testEncodeEmpty() { ch.writeOutbound(EmptyArrays.EMPTY_BYTES); assertThat((ByteBuf) ch.readOutbound(), is(sameInstance(EMPTY_BUFFER))); }
private static IOException newConnectionResetException(String method, int errnoNegative) { IOException exception = newIOException(method, errnoNegative); exception.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE); return exception; }
private static ByteBuf encodeConnectMessage( ByteBufAllocator byteBufAllocator, MqttConnectMessage message) { int payloadBufferSize = 0; MqttFixedHeader mqttFixedHeader = message.fixedHeader(); MqttConnectVariableHeader variableHeader = message.variableHeader(); MqttConnectPayload payload = message.payload(); MqttVersion mqttVersion = MqttVersion.fromProtocolNameAndLevel(variableHeader.protocolName(), (byte) variableHeader.protocolLevel()); // Client id String clientId = payload.clientId(); byte[] clientIdBytes = encodeStringUtf8(clientId); payloadBufferSize += 2 + clientIdBytes.length; // Will topic and message String willTopic = payload.willTopic(); byte[] willTopicBytes = willTopic != null ? encodeStringUtf8(willTopic) : EmptyArrays.EMPTY_BYTES; String willMessage = payload.willMessage(); byte[] willMessageBytes = willMessage != null ? encodeStringUtf8(willMessage) : EmptyArrays.EMPTY_BYTES; if (variableHeader.willFlag()) { payloadBufferSize += 2 + willTopicBytes.length; payloadBufferSize += 2 + willMessageBytes.length; } String userName = payload.userName(); byte[] userNameBytes = userName != null ? encodeStringUtf8(userName) : EmptyArrays.EMPTY_BYTES; if (variableHeader.userNameFlag()) { payloadBufferSize += 2 + userNameBytes.length; } String password = payload.password(); byte[] passwordBytes = password != null ? encodeStringUtf8(password) : EmptyArrays.EMPTY_BYTES; if (variableHeader.passwordFlag()) { payloadBufferSize += 2 + passwordBytes.length; } // Fixed header byte[] protocolNameBytes = mqttVersion.protocolNameBytes(); int variableHeaderBufferSize = 2 + protocolNameBytes.length + 4; int variablePartSize = variableHeaderBufferSize + payloadBufferSize; int fixedHeaderBufferSize = 1 + getVariableLengthInt(variablePartSize); ByteBuf buf = byteBufAllocator.buffer(fixedHeaderBufferSize + variablePartSize); buf.writeByte(getFixedHeaderByte1(mqttFixedHeader)); writeVariableLengthInt(buf, variablePartSize); buf.writeShort(protocolNameBytes.length); buf.writeBytes(protocolNameBytes); buf.writeByte(variableHeader.protocolLevel()); buf.writeByte(getConnVariableHeaderFlag(variableHeader)); buf.writeShort(variableHeader.keepAlive()); // Payload buf.writeShort(clientIdBytes.length); buf.writeBytes(clientIdBytes, 0, clientIdBytes.length); if (variableHeader.willFlag()) { buf.writeShort(willTopicBytes.length); buf.writeBytes(willTopicBytes, 0, willTopicBytes.length); buf.writeShort(willMessageBytes.length); buf.writeBytes(willMessageBytes, 0, willMessageBytes.length); } if (variableHeader.userNameFlag()) { buf.writeShort(userNameBytes.length); buf.writeBytes(userNameBytes, 0, userNameBytes.length); } if (variableHeader.passwordFlag()) { buf.writeShort(passwordBytes.length); buf.writeBytes(passwordBytes, 0, passwordBytes.length); } return buf; }
@Test public void testEncodeEmpty() { ch.writeOutbound(EmptyArrays.EMPTY_BYTES); assertThat((ByteBuf) ch.readOutbound(), is(Unpooled.EMPTY_BUFFER)); }