Example usage for io.netty.buffer ByteBuf writeBytes

List of usage examples for io.netty.buffer ByteBuf writeBytes

Introduction

In this page you can find the example usage for io.netty.buffer ByteBuf writeBytes.

Prototype

public abstract ByteBuf writeBytes(ByteBuffer src);

Source Link

Document

Transfers the specified source buffer's data to this buffer starting at the current writerIndex until the source buffer's position reaches its limit, and increases the writerIndex by the number of the transferred bytes.

Usage

From source file:com.mobius.software.android.iotbroker.mqtt.parser.MQParser.java

License:Open Source License

public static ByteBuf encode(MQMessage header) throws UnsupportedEncodingException, MalformedMessageException {
    int length = header.getLength();
    ByteBuf buf = getBuffer(length);
    MessageType type = header.getType();

    switch (type) {
    case CONNECT:
        Connect connect = (Connect) header;
        if (connect.isWillFlag() && !connect.getWill().isValid())
            throw new MalformedMessageException("invalid will encoding");

        buf.setByte(0, (byte) (type.getNum() << 4));
        buf.writeShort(4);//from   ww w  . j ava2  s.c o  m
        buf.writeBytes(connect.getName().getBytes());
        buf.writeByte(connect.getProtocolLevel());
        byte contentFlags = 0;
        contentFlags |= 0;
        contentFlags |= connect.isClean() ? 0x02 : 0;
        contentFlags |= connect.isWillFlag() ? 0x04 : 0;
        contentFlags |= connect.isWillFlag() ? connect.getWill().getTopic().getQos().getValue() << 3 : 0;
        contentFlags |= connect.isWillFlag() ? connect.getWill().getRetain() ? 0x20 : 0 : 0;
        contentFlags |= connect.isUsernameFlag() ? 0x40 : 0;
        contentFlags |= connect.isPasswordFlag() ? 0x80 : 0;
        buf.writeByte(contentFlags);
        buf.writeShort(connect.getKeepAlive());
        buf.writeShort(connect.getClientID().length());
        buf.writeBytes(connect.getClientID().getBytes("UTF-8"));

        if (connect.isWillFlag()) {
            Text willTopic = connect.getWill().getTopic().getName();
            if (willTopic != null) {
                buf.writeShort(willTopic.length());
                buf.writeBytes(willTopic.toString().getBytes("UTF-8"));
            }

            byte[] willMessage = connect.getWill().getContent();
            if (willMessage != null) {
                buf.writeShort(willMessage.length);
                buf.writeBytes(willMessage);
            }
        }

        String username = connect.getUserName();
        if (username != null) {
            buf.writeShort(username.length());
            buf.writeBytes(username.getBytes("UTF-8"));
        }

        String password = connect.getPassword();
        if (password != null) {
            buf.writeShort(password.length());
            buf.writeBytes(password.getBytes("UTF-8"));
        }
        break;

    case CONNACK:
        Connack connack = (Connack) header;
        buf.setByte(0, (byte) (type.getNum() << 4));
        buf.writeBoolean(connack.isSessionPresent());
        buf.writeByte(connack.getReturnCode().getNum());
        break;

    case PUBLISH:
        Publish publish = (Publish) header;
        byte firstByte = (byte) (type.getNum() << 4);
        firstByte |= publish.isDup() ? 8 : 0;
        firstByte |= (publish.getTopic().getQos().getValue() << 1);
        firstByte |= publish.isRetain() ? 1 : 0;
        buf.setByte(0, firstByte);
        buf.writeShort(publish.getTopic().length());
        buf.writeBytes(publish.getTopic().getName().toString().getBytes("UTF-8"));
        if (publish.getPacketID() != null)
            buf.writeShort(publish.getPacketID());
        buf.writeBytes(publish.getContent());
        break;

    case PUBACK:
        Puback puback = (Puback) header;
        buf.setByte(0, (byte) (type.getNum() << 4));
        buf.writeShort(puback.getPacketID());
        break;

    case PUBREC:
        Pubrec pubrec = (Pubrec) header;
        buf.setByte(0, (byte) (type.getNum() << 4));
        buf.writeShort(pubrec.getPacketID());
        break;

    case PUBREL:
        Pubrel pubrel = (Pubrel) header;
        buf.setByte(0, (byte) ((type.getNum() << 4) | 0x2));
        buf.writeShort(pubrel.getPacketID());
        break;

    case PUBCOMP:
        Pubcomp pubcomp = (Pubcomp) header;
        buf.setByte(0, (byte) (type.getNum() << 4));
        buf.writeShort(pubcomp.getPacketID());
        break;

    case SUBSCRIBE:
        Subscribe sub = (Subscribe) header;
        buf.setByte(0, (byte) ((type.getNum() << 4) | 0x2));
        if (sub.getPacketID() != null)
            buf.writeShort(sub.getPacketID());
        for (Topic subscription : sub.getTopics()) {
            buf.writeShort(subscription.getName().length());
            buf.writeBytes(subscription.getName().toString().getBytes("UTF-8"));
            buf.writeByte(subscription.getQos().getValue());
        }
        break;

    case SUBACK:
        Suback suback = (Suback) header;
        buf.setByte(0, (byte) (type.getNum() << 4));
        buf.writeShort(suback.getPacketID());
        for (SubackCode code : suback.getReturnCodes())
            buf.writeByte(code.getNum());
        break;

    case UNSUBSCRIBE:
        Unsubscribe unsub = (Unsubscribe) header;
        buf.setByte(0, (byte) ((type.getNum() << 4) | 0x2));
        buf.writeShort(unsub.getPacketID());
        for (Topic topic : unsub.getTopics()) {
            buf.writeShort(topic.getName().length());
            buf.writeBytes(topic.getName().toString().getBytes("UTF-8"));
        }
        break;

    case UNSUBACK:
        Unsuback unsuback = (Unsuback) header;
        buf.setByte(0, (byte) (type.getNum() << 4));
        buf.writeShort(unsuback.getPacketID());
        break;

    case DISCONNECT:
    case PINGREQ:
    case PINGRESP:
        buf.setByte(0, (byte) (type.getNum() << 4));
        break;

    default:
        throw new MalformedMessageException("Invalid header type: " + type);
    }

    return buf;
}

From source file:com.mobius.software.android.iotbroker.mqtt.parser.MQParser.java

License:Open Source License

private static ByteBuf getBuffer(final int length) throws MalformedMessageException {
    byte[] lengthBytes;

    if (length <= 127)
        lengthBytes = new byte[1];
    else if (length <= 16383)
        lengthBytes = new byte[2];
    else if (length <= 2097151)
        lengthBytes = new byte[3];
    else if (length <= 26843545)
        lengthBytes = new byte[4];
    else/* w  ww  .j av  a2s . c om*/
        throw new MalformedMessageException("header length exceeds maximum of 26843545 bytes");

    byte encByte;
    int pos = 0, l = length;
    do {
        encByte = (byte) (l % 128);
        l /= 128;
        if (l > 0)
            lengthBytes[pos++] = (byte) (encByte | 128);
        else
            lengthBytes[pos++] = encByte;
    } while (l > 0);

    int bufferSize = 1 + lengthBytes.length + length;
    ByteBuf buf = Unpooled.buffer(bufferSize);

    buf.writeByte(0);
    buf.writeBytes(lengthBytes);

    return buf;
}

From source file:com.mobius.software.mqtt.parser.MQParser.java

License:Open Source License

public MQMessage decodeUsingCache(ByteBuf buf) throws MalformedMessageException {
    byte fixedHeader = buf.readByte();

    LengthDetails length = LengthDetails.decode(buf);

    MessageType type = MessageType.valueOf((fixedHeader >> 4) & 0xf);
    MQMessage header = cache.borrowMessage(type);
    try {//from  w w  w.j a v  a  2s  .  c om
        switch (type) {
        case CONNECT:

            byte[] nameValue = new byte[buf.readUnsignedShort()];
            buf.readBytes(nameValue, 0, nameValue.length);
            String name = new String(nameValue, "UTF-8");
            if (!name.equals("MQTT"))
                throw new MalformedMessageException("CONNECT, protocol-name set to " + name);

            int protocolLevel = buf.readUnsignedByte();

            byte contentFlags = buf.readByte();

            boolean userNameFlag = ((contentFlags >> 7) & 1) == 1 ? true : false;
            boolean userPassFlag = ((contentFlags >> 6) & 1) == 1 ? true : false;
            boolean willRetain = ((contentFlags >> 5) & 1) == 1 ? true : false;
            QoS willQos = QoS.valueOf(((contentFlags & 0x1f) >> 3) & 3);
            if (willQos == null)
                throw new MalformedMessageException("CONNECT, will QoS set to " + willQos);
            boolean willFlag = (((contentFlags >> 2) & 1) == 1) ? true : false;

            if (willQos.getValue() > 0 && !willFlag)
                throw new MalformedMessageException(
                        "CONNECT, will QoS set to " + willQos + ", willFlag not set");

            if (willRetain && !willFlag)
                throw new MalformedMessageException("CONNECT, will retain set, willFlag not set");

            boolean cleanSession = ((contentFlags >> 1) & 1) == 1 ? true : false;

            boolean reservedFlag = (contentFlags & 1) == 1 ? true : false;
            if (reservedFlag)
                throw new MalformedMessageException("CONNECT, reserved flag set to true");

            int keepalive = buf.readUnsignedShort();

            byte[] clientIdValue = new byte[buf.readUnsignedShort()];
            buf.readBytes(clientIdValue, 0, clientIdValue.length);
            String clientID = new String(clientIdValue, "UTF-8");
            if (!StringVerifier.verify(clientID))
                throw new MalformedMessageException(
                        "ClientID contains restricted characters: U+0000, U+D000-U+DFFF");

            Text willTopic = null;
            byte[] willMessage = null;
            String username = null;
            String password = null;

            Will will = null;
            if (willFlag) {
                if (buf.readableBytes() < 2)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                byte[] willTopicValue = new byte[buf.readUnsignedShort()];
                if (buf.readableBytes() < willTopicValue.length)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                buf.readBytes(willTopicValue, 0, willTopicValue.length);

                String willTopicName = new String(willTopicValue, "UTF-8");
                if (!StringVerifier.verify(willTopicName))
                    throw new MalformedMessageException(
                            "WillTopic contains one or more restricted characters: U+0000, U+D000-U+DFFF");
                willTopic = new Text(willTopicName);

                if (buf.readableBytes() < 2)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                willMessage = new byte[buf.readUnsignedShort()];
                if (buf.readableBytes() < willMessage.length)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                buf.readBytes(willMessage, 0, willMessage.length);
                if (willTopic.length() == 0)
                    throw new MalformedMessageException("invalid will encoding");
                will = new Will(new Topic(willTopic, willQos), willMessage, willRetain);
                if (!will.isValid())
                    throw new MalformedMessageException("invalid will encoding");
            }

            if (userNameFlag) {
                if (buf.readableBytes() < 2)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                byte[] userNameValue = new byte[buf.readUnsignedShort()];
                if (buf.readableBytes() < userNameValue.length)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                buf.readBytes(userNameValue, 0, userNameValue.length);
                username = new String(userNameValue, "UTF-8");
                if (!StringVerifier.verify(username))
                    throw new MalformedMessageException(
                            "Username contains one or more restricted characters: U+0000, U+D000-U+DFFF");
            }

            if (userPassFlag) {
                if (buf.readableBytes() < 2)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                byte[] userPassValue = new byte[buf.readUnsignedShort()];
                if (buf.readableBytes() < userPassValue.length)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                buf.readBytes(userPassValue, 0, userPassValue.length);
                password = new String(userPassValue, "UTF-8");
                if (!StringVerifier.verify(password))
                    throw new MalformedMessageException(
                            "Password contains one or more restricted characters: U+0000, U+D000-U+DFFF");
            }

            if (buf.readableBytes() > 0)
                throw new MalformedMessageException("Invalid encoding will/username/password");

            Connect connect = (Connect) header;
            connect.reInit(username, password, clientID, cleanSession, keepalive, will);
            connect.setProtocolLevel(protocolLevel);
            break;

        case CONNACK:
            byte sessionPresentValue = buf.readByte();
            if (sessionPresentValue != 0 && sessionPresentValue != 1)
                throw new MalformedMessageException(
                        String.format("CONNACK, session-present set to %d", sessionPresentValue & 0xff));
            boolean isPresent = sessionPresentValue == 1 ? true : false;

            short connackByte = buf.readUnsignedByte();
            ConnackCode connackCode = ConnackCode.valueOf(connackByte);
            if (connackCode == null)
                throw new MalformedMessageException("Invalid connack code: " + connackByte);
            Connack connack = (Connack) header;
            connack.reInit(isPresent, connackCode);
            break;

        case PUBLISH:

            fixedHeader &= 0xf;

            boolean dup = ((fixedHeader >> 3) & 1) == 1 ? true : false;

            QoS qos = QoS.valueOf((fixedHeader & 0x07) >> 1);
            if (qos == null)
                throw new MalformedMessageException("invalid QoS value");
            if (dup && qos == QoS.AT_MOST_ONCE)
                throw new MalformedMessageException("PUBLISH, QoS-0 dup flag present");

            boolean retain = ((fixedHeader & 1) == 1) ? true : false;

            byte[] topicNameValue = new byte[buf.readUnsignedShort()];
            buf.readBytes(topicNameValue, 0, topicNameValue.length);
            String topicName = new String(topicNameValue, "UTF-8");
            if (!StringVerifier.verify(topicName))
                throw new MalformedMessageException(
                        "Publish-topic contains one or more restricted characters: U+0000, U+D000-U+DFFF");

            Integer packetID = null;
            if (qos != QoS.AT_MOST_ONCE) {
                packetID = buf.readUnsignedShort();
                if (packetID < 0 || packetID > 65535)
                    throw new MalformedMessageException("Invalid PUBLISH packetID encoding");
            }

            ByteBuf data = Unpooled.buffer(buf.readableBytes());
            data.writeBytes(buf);

            Publish publish = (Publish) header;
            publish.reInit(packetID, new Topic(new Text(topicName), qos), data, retain, dup);
            break;

        case PUBACK:
        case PUBREC:
        case PUBREL:
        case PUBCOMP:
        case UNSUBACK:
            CountableMessage countable = (CountableMessage) header;
            countable.reInit(buf.readUnsignedShort());
            break;

        case SUBSCRIBE:
            Integer subID = buf.readUnsignedShort();
            List<Topic> subscriptions = new ArrayList<>();
            while (buf.isReadable()) {
                byte[] value = new byte[buf.readUnsignedShort()];
                buf.readBytes(value, 0, value.length);
                QoS requestedQos = QoS.valueOf(buf.readByte());
                if (requestedQos == null)
                    throw new MalformedMessageException(
                            "Subscribe qos must be in range from 0 to 2: " + requestedQos);
                String topic = new String(value, "UTF-8");
                if (!StringVerifier.verify(topic))
                    throw new MalformedMessageException(
                            "Subscribe topic contains one or more restricted characters: U+0000, U+D000-U+DFFF");
                Topic subscription = new Topic(new Text(topic), requestedQos);
                subscriptions.add(subscription);
            }
            if (subscriptions.isEmpty())
                throw new MalformedMessageException("Subscribe with 0 topics");

            Subscribe subscribe = (Subscribe) header;
            subscribe.reInit(subID, subscriptions.toArray(new Topic[subscriptions.size()]));
            break;

        case SUBACK:
            Integer subackID = buf.readUnsignedShort();
            List<SubackCode> subackCodes = new ArrayList<>();
            while (buf.isReadable()) {
                short subackByte = buf.readUnsignedByte();
                SubackCode subackCode = SubackCode.valueOf(subackByte);
                if (subackCode == null)
                    throw new MalformedMessageException("Invalid suback code: " + subackByte);
                subackCodes.add(subackCode);
            }
            if (subackCodes.isEmpty())
                throw new MalformedMessageException("Suback with 0 return-codes");

            Suback suback = (Suback) header;
            suback.reInit(subackID, subackCodes);
            break;

        case UNSUBSCRIBE:
            Integer unsubID = buf.readUnsignedShort();
            List<Text> unsubscribeTopics = new ArrayList<>();
            while (buf.isReadable()) {
                byte[] value = new byte[buf.readUnsignedShort()];
                buf.readBytes(value, 0, value.length);
                String topic = new String(value, "UTF-8");
                if (!StringVerifier.verify(topic))
                    throw new MalformedMessageException(
                            "Unsubscribe topic contains one or more restricted characters: U+0000, U+D000-U+DFFF");
                unsubscribeTopics.add(new Text(topic));
            }
            if (unsubscribeTopics.isEmpty())
                throw new MalformedMessageException("Unsubscribe with 0 topics");
            Unsubscribe unsubscribe = (Unsubscribe) header;
            unsubscribe.reInit(unsubID, unsubscribeTopics.toArray(new Text[unsubscribeTopics.size()]));
            break;

        case PINGREQ:
        case PINGRESP:
        case DISCONNECT:
            break;

        default:
            throw new MalformedMessageException("Invalid header type: " + type);
        }

        if (buf.isReadable())
            throw new MalformedMessageException("unexpected bytes in content");

        if (length.getLength() != header.getLength())
            throw new MalformedMessageException(String.format("Invalid length. Encoded: %d, actual: %d",
                    length.getLength(), header.getLength()));

        return header;
    } catch (UnsupportedEncodingException e) {
        throw new MalformedMessageException("unsupported string encoding:" + e.getMessage());
    }
}

From source file:com.mobius.software.mqtt.parser.MQParser.java

License:Open Source License

public static MQMessage decode(ByteBuf buf) throws MalformedMessageException {
    MQMessage header = null;//from www. j  a v  a2  s .  co m

    byte fixedHeader = buf.readByte();

    LengthDetails length = LengthDetails.decode(buf);

    MessageType type = MessageType.valueOf((fixedHeader >> 4) & 0xf);
    try {
        switch (type) {
        case CONNECT:

            byte[] nameValue = new byte[buf.readUnsignedShort()];
            buf.readBytes(nameValue, 0, nameValue.length);
            String name = new String(nameValue, "UTF-8");
            if (!name.equals("MQTT"))
                throw new MalformedMessageException("CONNECT, protocol-name set to " + name);

            int protocolLevel = buf.readUnsignedByte();

            byte contentFlags = buf.readByte();

            boolean userNameFlag = ((contentFlags >> 7) & 1) == 1 ? true : false;
            boolean userPassFlag = ((contentFlags >> 6) & 1) == 1 ? true : false;
            boolean willRetain = ((contentFlags >> 5) & 1) == 1 ? true : false;
            QoS willQos = QoS.valueOf(((contentFlags & 0x1f) >> 3) & 3);
            if (willQos == null)
                throw new MalformedMessageException("CONNECT, will QoS set to " + willQos);
            boolean willFlag = (((contentFlags >> 2) & 1) == 1) ? true : false;

            if (willQos.getValue() > 0 && !willFlag)
                throw new MalformedMessageException(
                        "CONNECT, will QoS set to " + willQos + ", willFlag not set");

            if (willRetain && !willFlag)
                throw new MalformedMessageException("CONNECT, will retain set, willFlag not set");

            boolean cleanSession = ((contentFlags >> 1) & 1) == 1 ? true : false;

            boolean reservedFlag = (contentFlags & 1) == 1 ? true : false;
            if (reservedFlag)
                throw new MalformedMessageException("CONNECT, reserved flag set to true");

            int keepalive = buf.readUnsignedShort();

            byte[] clientIdValue = new byte[buf.readUnsignedShort()];
            buf.readBytes(clientIdValue, 0, clientIdValue.length);
            String clientID = new String(clientIdValue, "UTF-8");
            if (!StringVerifier.verify(clientID))
                throw new MalformedMessageException(
                        "ClientID contains restricted characters: U+0000, U+D000-U+DFFF");

            Text willTopic = null;
            byte[] willMessage = null;
            String username = null;
            String password = null;

            Will will = null;
            if (willFlag) {
                if (buf.readableBytes() < 2)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                byte[] willTopicValue = new byte[buf.readUnsignedShort()];
                if (buf.readableBytes() < willTopicValue.length)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                buf.readBytes(willTopicValue, 0, willTopicValue.length);

                String willTopicName = new String(willTopicValue, "UTF-8");
                if (!StringVerifier.verify(willTopicName))
                    throw new MalformedMessageException(
                            "WillTopic contains one or more restricted characters: U+0000, U+D000-U+DFFF");
                willTopic = new Text(willTopicName);

                if (buf.readableBytes() < 2)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                willMessage = new byte[buf.readUnsignedShort()];
                if (buf.readableBytes() < willMessage.length)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                buf.readBytes(willMessage, 0, willMessage.length);
                if (willTopic.length() == 0)
                    throw new MalformedMessageException("invalid will encoding");
                will = new Will(new Topic(willTopic, willQos), willMessage, willRetain);
                if (!will.isValid())
                    throw new MalformedMessageException("invalid will encoding");
            }

            if (userNameFlag) {
                if (buf.readableBytes() < 2)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                byte[] userNameValue = new byte[buf.readUnsignedShort()];
                if (buf.readableBytes() < userNameValue.length)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                buf.readBytes(userNameValue, 0, userNameValue.length);
                username = new String(userNameValue, "UTF-8");
                if (!StringVerifier.verify(username))
                    throw new MalformedMessageException(
                            "Username contains one or more restricted characters: U+0000, U+D000-U+DFFF");
            }

            if (userPassFlag) {
                if (buf.readableBytes() < 2)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                byte[] userPassValue = new byte[buf.readUnsignedShort()];
                if (buf.readableBytes() < userPassValue.length)
                    throw new MalformedMessageException("Invalid encoding will/username/password");

                buf.readBytes(userPassValue, 0, userPassValue.length);
                password = new String(userPassValue, "UTF-8");
                if (!StringVerifier.verify(password))
                    throw new MalformedMessageException(
                            "Password contains one or more restricted characters: U+0000, U+D000-U+DFFF");
            }

            if (buf.readableBytes() > 0)
                throw new MalformedMessageException("Invalid encoding will/username/password");

            Connect connect = new Connect(username, password, clientID, cleanSession, keepalive, will);
            if (protocolLevel != 4)
                connect.setProtocolLevel(protocolLevel);
            header = connect;
            break;

        case CONNACK:
            byte sessionPresentValue = buf.readByte();
            if (sessionPresentValue != 0 && sessionPresentValue != 1)
                throw new MalformedMessageException(
                        String.format("CONNACK, session-present set to %d", sessionPresentValue & 0xff));
            boolean isPresent = sessionPresentValue == 1 ? true : false;

            short connackByte = buf.readUnsignedByte();
            ConnackCode connackCode = ConnackCode.valueOf(connackByte);
            if (connackCode == null)
                throw new MalformedMessageException("Invalid connack code: " + connackByte);
            header = new Connack(isPresent, connackCode);
            break;

        case PUBLISH:

            fixedHeader &= 0xf;

            boolean dup = ((fixedHeader >> 3) & 1) == 1 ? true : false;

            QoS qos = QoS.valueOf((fixedHeader & 0x07) >> 1);
            if (qos == null)
                throw new MalformedMessageException("invalid QoS value");
            if (dup && qos == QoS.AT_MOST_ONCE)
                throw new MalformedMessageException("PUBLISH, QoS-0 dup flag present");

            boolean retain = ((fixedHeader & 1) == 1) ? true : false;

            byte[] topicNameValue = new byte[buf.readUnsignedShort()];
            buf.readBytes(topicNameValue, 0, topicNameValue.length);
            String topicName = new String(topicNameValue, "UTF-8");
            if (!StringVerifier.verify(topicName))
                throw new MalformedMessageException(
                        "Publish-topic contains one or more restricted characters: U+0000, U+D000-U+DFFF");

            Integer packetID = null;
            if (qos != QoS.AT_MOST_ONCE) {
                packetID = buf.readUnsignedShort();
                if (packetID < 0 || packetID > 65535)
                    throw new MalformedMessageException("Invalid PUBLISH packetID encoding");
            }

            ByteBuf data = Unpooled.buffer(buf.readableBytes());
            data.writeBytes(buf);
            header = new Publish(packetID, new Topic(new Text(topicName), qos), data, retain, dup);
            break;

        case PUBACK:
            header = new Puback(buf.readUnsignedShort());
            break;

        case PUBREC:
            header = new Pubrec(buf.readUnsignedShort());
            break;

        case PUBREL:
            header = new Pubrel(buf.readUnsignedShort());
            break;

        case PUBCOMP:
            header = new Pubcomp(buf.readUnsignedShort());
            break;

        case SUBSCRIBE:
            Integer subID = buf.readUnsignedShort();
            List<Topic> subscriptions = new ArrayList<>();
            while (buf.isReadable()) {
                byte[] value = new byte[buf.readUnsignedShort()];
                buf.readBytes(value, 0, value.length);
                QoS requestedQos = QoS.valueOf(buf.readByte());
                if (requestedQos == null)
                    throw new MalformedMessageException(
                            "Subscribe qos must be in range from 0 to 2: " + requestedQos);
                String topic = new String(value, "UTF-8");
                if (!StringVerifier.verify(topic))
                    throw new MalformedMessageException(
                            "Subscribe topic contains one or more restricted characters: U+0000, U+D000-U+DFFF");
                Topic subscription = new Topic(new Text(topic), requestedQos);
                subscriptions.add(subscription);
            }
            if (subscriptions.isEmpty())
                throw new MalformedMessageException("Subscribe with 0 topics");

            header = new Subscribe(subID, subscriptions.toArray(new Topic[subscriptions.size()]));
            break;

        case SUBACK:
            Integer subackID = buf.readUnsignedShort();
            List<SubackCode> subackCodes = new ArrayList<>();
            while (buf.isReadable()) {
                short subackByte = buf.readUnsignedByte();
                SubackCode subackCode = SubackCode.valueOf(subackByte);
                if (subackCode == null)
                    throw new MalformedMessageException("Invalid suback code: " + subackByte);
                subackCodes.add(subackCode);
            }
            if (subackCodes.isEmpty())
                throw new MalformedMessageException("Suback with 0 return-codes");

            header = new Suback(subackID, subackCodes);
            break;

        case UNSUBSCRIBE:
            Integer unsubID = buf.readUnsignedShort();
            List<Text> unsubscribeTopics = new ArrayList<>();
            while (buf.isReadable()) {
                byte[] value = new byte[buf.readUnsignedShort()];
                buf.readBytes(value, 0, value.length);
                String topic = new String(value, "UTF-8");
                if (!StringVerifier.verify(topic))
                    throw new MalformedMessageException(
                            "Unsubscribe topic contains one or more restricted characters: U+0000, U+D000-U+DFFF");
                unsubscribeTopics.add(new Text(topic));
            }
            if (unsubscribeTopics.isEmpty())
                throw new MalformedMessageException("Unsubscribe with 0 topics");
            header = new Unsubscribe(unsubID, unsubscribeTopics.toArray(new Text[unsubscribeTopics.size()]));
            break;

        case UNSUBACK:
            header = new Unsuback(buf.readUnsignedShort());
            break;

        case PINGREQ:
            header = PINGREQ;
            break;
        case PINGRESP:
            header = PINGRESP;
            break;
        case DISCONNECT:
            header = DISCONNECT;
            break;

        default:
            throw new MalformedMessageException("Invalid header type: " + type);
        }

        if (buf.isReadable())
            throw new MalformedMessageException("unexpected bytes in content");

        if (length.getLength() != header.getLength())
            throw new MalformedMessageException(String.format("Invalid length. Encoded: %d, actual: %d",
                    length.getLength(), header.getLength()));

        return header;
    } catch (UnsupportedEncodingException e) {
        throw new MalformedMessageException("unsupported string encoding:" + e.getMessage());
    }
}

From source file:com.mobius.software.mqtt.parser.MQParser.java

License:Open Source License

public static ByteBuf encode(MQMessage header) throws MalformedMessageException {
    int length = header.getLength();
    ByteBuf buf = getBuffer(length);
    MessageType type = header.getType();
    try {/*from   w  ww .j av a 2s  .c  o  m*/
        switch (type) {
        case CONNECT:
            Connect connect = (Connect) header;
            if (connect.isWillFlag() && !connect.getWill().isValid())
                throw new MalformedMessageException("invalid will encoding");

            buf.setByte(0, (byte) (type.getNum() << 4));
            buf.writeShort(4);
            buf.writeBytes(connect.getName().getBytes());
            buf.writeByte(connect.getProtocolLevel());

            byte contentFlags = 0;
            if (connect.isCleanSession())
                contentFlags += 2;
            if (connect.isWillFlag()) {
                contentFlags += 4;
                contentFlags += connect.getWill().getTopic().getQos().getValue() << 3;
                if (connect.getWill().isRetain())
                    contentFlags += 0x20;
            }
            if (connect.isPasswordFlag())
                contentFlags += 0x40;
            if (connect.isUsernameFlag())
                contentFlags += 0x80;
            buf.writeByte(contentFlags);

            buf.writeShort(connect.getKeepalive());
            buf.writeShort(connect.getClientID().length());
            buf.writeBytes(connect.getClientID().getBytes("UTF-8"));

            if (connect.isWillFlag()) {
                Text willTopic = connect.getWill().getTopic().getName();
                if (willTopic != null) {
                    buf.writeShort(willTopic.length());
                    buf.writeBytes(willTopic.toString().getBytes("UTF-8"));
                }

                byte[] willMessage = connect.getWill().getContent();
                if (willMessage != null) {
                    buf.writeShort(willMessage.length);
                    buf.writeBytes(willMessage);
                }
            }

            String username = connect.getUsername();
            if (username != null) {
                buf.writeShort(username.length());
                buf.writeBytes(username.getBytes("UTF-8"));
            }

            String password = connect.getPassword();
            if (password != null) {
                buf.writeShort(password.length());
                buf.writeBytes(password.getBytes("UTF-8"));
            }
            break;

        case CONNACK:
            Connack connack = (Connack) header;
            buf.setByte(0, (byte) (type.getNum() << 4));
            buf.writeBoolean(connack.isSessionPresent());
            buf.writeByte(connack.getReturnCode().getNum());
            break;

        case PUBLISH:
            Publish publish = (Publish) header;
            byte firstByte = (byte) (type.getNum() << 4);
            firstByte |= publish.isDup() ? 8 : 0;
            firstByte |= (publish.getTopic().getQos().getValue() << 1);
            firstByte |= publish.isRetain() ? 1 : 0;
            buf.setByte(0, firstByte);
            buf.writeShort(publish.getTopic().length());
            buf.writeBytes(publish.getTopic().getName().toString().getBytes("UTF-8"));
            switch (publish.getTopic().getQos()) {
            case AT_MOST_ONCE:
                if (publish.getPacketID() != null)
                    throw new MalformedMessageException("publish qos-0 must not contain packetID");
                break;
            case AT_LEAST_ONCE:
            case EXACTLY_ONCE:
                if (publish.getPacketID() == null)
                    throw new MalformedMessageException("publish qos-1,2 must contain packetID");
                buf.writeShort(publish.getPacketID());
                break;
            }
            buf.writeBytes(publish.getContent());
            break;

        case PUBACK:
            Puback puback = (Puback) header;
            buf.setByte(0, (byte) (type.getNum() << 4));
            if (puback.getPacketID() == null)
                throw new MalformedMessageException("puback must contain packetID");
            buf.writeShort(puback.getPacketID());
            break;

        case PUBREC:
            Pubrec pubrec = (Pubrec) header;
            buf.setByte(0, (byte) (type.getNum() << 4));
            if (pubrec.getPacketID() == null)
                throw new MalformedMessageException("pubrec must contain packetID");
            buf.writeShort(pubrec.getPacketID());
            break;

        case PUBREL:
            Pubrel pubrel = (Pubrel) header;
            buf.setByte(0, (byte) ((type.getNum() << 4) | 0x2));
            if (pubrel.getPacketID() == null)
                throw new MalformedMessageException("pubrel must contain packetID");
            buf.writeShort(pubrel.getPacketID());
            break;

        case PUBCOMP:
            Pubcomp pubcomp = (Pubcomp) header;
            buf.setByte(0, (byte) (type.getNum() << 4));
            if (pubcomp.getPacketID() == null)
                throw new MalformedMessageException("pubcomp must contain packetID");
            buf.writeShort(pubcomp.getPacketID());
            break;

        case SUBSCRIBE:
            Subscribe sub = (Subscribe) header;
            buf.setByte(0, (byte) ((type.getNum() << 4) | 0x2));
            if (sub.getPacketID() == null)
                throw new MalformedMessageException("subscribe must contain packetID");
            buf.writeShort(sub.getPacketID());
            for (Topic subscription : sub.getTopics()) {
                buf.writeShort(subscription.getName().length());
                buf.writeBytes(subscription.getName().toString().getBytes("UTF-8"));
                buf.writeByte(subscription.getQos().getValue());
            }
            break;

        case SUBACK:
            Suback suback = (Suback) header;
            buf.setByte(0, (byte) (type.getNum() << 4));
            if (suback.getPacketID() == null)
                throw new MalformedMessageException("suback must contain packetID");
            buf.writeShort(suback.getPacketID());
            for (SubackCode code : suback.getReturnCodes())
                buf.writeByte(code.getNum());
            break;

        case UNSUBSCRIBE:
            Unsubscribe unsub = (Unsubscribe) header;
            buf.setByte(0, (byte) ((type.getNum() << 4) | 0x2));
            if (unsub.getPacketID() == null)
                throw new MalformedMessageException("subscribe must contain packetID");
            buf.writeShort(unsub.getPacketID());
            for (Text topic : unsub.getTopics()) {
                buf.writeShort(topic.length());
                buf.writeBytes(topic.toString().getBytes("UTF-8"));
            }
            break;

        case UNSUBACK:
            Unsuback unsuback = (Unsuback) header;
            buf.setByte(0, (byte) (type.getNum() << 4));
            if (unsuback.getPacketID() == null)
                throw new MalformedMessageException("unsuback must contain packetID");
            buf.writeShort(unsuback.getPacketID());
            break;

        case DISCONNECT:
        case PINGREQ:
        case PINGRESP:
            buf.setByte(0, (byte) (type.getNum() << 4));
            break;

        default:
            throw new MalformedMessageException("Invalid header type: " + type);
        }

        return buf;
    } catch (UnsupportedEncodingException e) {
        throw new MalformedMessageException("unsupported string encoding:" + e.getMessage());
    }
}

From source file:com.mobius.software.mqtt.parser.MQParser.java

License:Open Source License

public static ByteBuf getBuffer(final int length) throws MalformedMessageException {
    byte[] lengthBytes;

    if (length <= 127)
        lengthBytes = new byte[1];
    else if (length <= 16383)
        lengthBytes = new byte[2];
    else if (length <= 2097151)
        lengthBytes = new byte[3];
    else if (length <= 26843545)
        lengthBytes = new byte[4];
    else/*from w w w .ja va 2 s . com*/
        throw new MalformedMessageException("header length exceeds maximum of 26843545 bytes");

    byte encByte;
    int pos = 0, l = length;
    do {
        encByte = (byte) (l % 128);
        l /= 128;
        if (l > 0)
            lengthBytes[pos++] = (byte) (encByte | 128);
        else
            lengthBytes[pos++] = encByte;
    } while (l > 0);

    int bufferSize = 1 + lengthBytes.length + length;
    ByteBuf buf = Unpooled.buffer(bufferSize);

    buf.writeByte(0);
    buf.writeBytes(lengthBytes);

    return buf;
}

From source file:com.mobius.software.mqtt.parser.test.TestParser.java

License:Open Source License

@Test
public void testPositivenext() throws MalformedMessageException {
    ByteBuf buf = Unpooled.buffer(114);
    buf.writeByte(0x82);//from  ww w.ja v  a  2  s .  c  o m
    buf.writeByte(0x66);
    buf.writeShort(10);
    buf.writeShort(97);
    buf.writeBytes(new byte[96]);
    buf.writeByte(1);
    buf.writeByte(0);
    assertEquals("Invalid next header length", 104, MQParser.next(buf).capacity());
    assertEquals("buffer index was not reset", 0, buf.readerIndex());
}

From source file:com.mobius.software.mqtt.parser.test.TestParser.java

License:Open Source License

@Test(expected = MalformedMessageException.class)
public void testNegativeNext() throws MalformedMessageException {
    ByteBuf buf = Unpooled.buffer(103);
    buf.writeByte(0x82);//from w w w  . jav  a2  s.co  m
    buf.writeByte(0x66); //encoded l=104, actual l=103
    buf.writeShort(10);
    buf.writeShort(97);
    buf.writeBytes(new byte[96]);
    buf.writeByte(1);
    MQParser.next(buf);
}

From source file:com.mobius.software.mqtt.parser.test.TestParser.java

License:Open Source License

@Test
public void testNegativeNextIndexNotReset() throws MalformedMessageException {
    ByteBuf buf = Unpooled.buffer(103);
    buf.writeByte(0x82);/* w ww . ja v  a  2s  .c  o  m*/
    buf.writeByte(0x66); //encoded l=104, actual l=103
    buf.writeShort(10);
    buf.writeShort(97);
    buf.writeBytes(new byte[96]);
    buf.writeByte(1);
    try {
        MQParser.next(buf);
    } catch (MalformedMessageException e) {

    }
    assertEquals("buffer index was not reset", 0, buf.readerIndex());
}

From source file:com.mobius.software.mqtt.parser.test.TestParser.java

License:Open Source License

@Test(expected = MalformedMessageException.class)
public void testNextContentIncomplete() throws MalformedMessageException {
    ByteBuf buf = Unpooled.buffer(2120207);
    buf.writeByte(0x82);//w ww .  ja v a2 s.c o  m
    buf.writeByte(0x8a);
    buf.writeByte(0xB4);
    buf.writeByte(0x81);
    buf.writeByte(0x01);
    buf.writeBytes(new byte[2120201]); // one byte missing in content
    MQParser.next(buf);
    assertEquals("buffer index was not reset", 0, buf.readerIndex());
}